<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en">
	<id>https://wiki.multitheftauto.com/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=R3mp</id>
	<title>Multi Theft Auto: Wiki - User contributions [en]</title>
	<link rel="self" type="application/atom+xml" href="https://wiki.multitheftauto.com/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=R3mp"/>
	<link rel="alternate" type="text/html" href="https://wiki.multitheftauto.com/wiki/Special:Contributions/R3mp"/>
	<updated>2026-04-20T02:06:47Z</updated>
	<subtitle>User contributions</subtitle>
	<generator>MediaWiki 1.39.3</generator>
	<entry>
		<id>https://wiki.multitheftauto.com/index.php?title=Resource:Missiontimer&amp;diff=24371</id>
		<title>Resource:Missiontimer</title>
		<link rel="alternate" type="text/html" href="https://wiki.multitheftauto.com/index.php?title=Resource:Missiontimer&amp;diff=24371"/>
		<updated>2010-08-16T22:10:20Z</updated>

		<summary type="html">&lt;p&gt;R3mp: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Resource page}}&lt;br /&gt;
Missiontimer is a resource used to easily create timers that count down or up in your resources.&lt;br /&gt;
&lt;br /&gt;
== Overview ==&lt;br /&gt;
&lt;br /&gt;
The &amp;quot;deathmatch&amp;quot; gamemode is an example use of missiontimer.  It uses the &amp;quot;createMissionTimer&amp;quot; function to create a timer, and then the onMissionTimerElapsed event to trigger at the end:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;    g_MissionTimer = exports.missiontimer:createMissionTimer (g_TimeLimit,true,&amp;quot;%m:%s&amp;quot;,0.5,20,true,&amp;quot;default-bold&amp;quot;,1,255,255,255)&lt;br /&gt;
    addEventHandler ( &amp;quot;onMissionTimerElapsed&amp;quot;, g_MissionTimer, onTimeElapsed )&lt;br /&gt;
 &amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Then you use the onTimeElapsed function that you attached to the handler at the end of the timer.&lt;br /&gt;
&lt;br /&gt;
The arguments for createMissionTimer as follows:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;createMissionTimer ( duration, countdown, format, x, y, bg, font, scale, r, g, b )&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
* duration - The time in milliseconds&lt;br /&gt;
* countdown - A bool of whether to countdown or count up.  Setting it to true will count down from the duration, setting it to false will count up to the duration (latter isnt tested yet)&lt;br /&gt;
* format - A string detailing the format of the timer text to be shown. You can chose whether to show minutes, seconds or centiseconds using these 3 strings:&lt;br /&gt;
** %m - minutes&lt;br /&gt;
** %s - seconds&lt;br /&gt;
** %cs - centiseconds&lt;br /&gt;
This allows you to add normal text onto the timer as well as showing the time left (eg: &amp;quot;Time left: %m:%s&amp;quot;)&lt;br /&gt;
* x,y - Position on the screen, this uses &amp;quot;smart positioning&amp;quot;.  It can be relative or absolute - the deathmatch gamemode creates it at 0.5,20.  This means the x value is in the centre, the y is 20pixels from the top.  If you specify a negative value it draws the other way, i.e. -20 would be 20pixels from the bottom rather than the top.  The same can be done for x.&lt;br /&gt;
* bg - Whether to draw the default rounded-rectangle behind the timer.  Setting this to false will hide it&lt;br /&gt;
* font - The font of the timer.  Looks best in default-bold&lt;br /&gt;
* scale - The size of the text/bg.&lt;br /&gt;
* r,g,b - The red/green/blue components to make up the colour of the timer text (defaults to white)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
There are also some other exported functions that you may or may not need:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;setMissionTimerTime ( missionTimer, time )&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Sets the countdown/countup target time (in milliseconds) &lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;getMissionTimerTime ( missionTimer )&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Gets the number currently showing on the clock (in milliseconds)&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;setMissionTimerFrozen ( missionTimer, frozen )&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Sets the timer to frozen (true) or normal (false)&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;isMissionTimerFrozen ( missionTimer )&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
See if the timer is frozen&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;setMissionTimerHurryTime ( missionTimer, time )&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Set the time that the clock will turn red (in milliseconds) (ie: to indicate there is not much time left) &lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;setMissionTimerFormat ( missionTimer, format )&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Set the text format for the timer&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
To remove a missiontimer from the screen, use [[destroyElement]].&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Missiontimer is only compatible with MTASA 1.0 onwards.&lt;/div&gt;</summary>
		<author><name>R3mp</name></author>
	</entry>
	<entry>
		<id>https://wiki.multitheftauto.com/index.php?title=Resource:Missiontimer&amp;diff=24369</id>
		<title>Resource:Missiontimer</title>
		<link rel="alternate" type="text/html" href="https://wiki.multitheftauto.com/index.php?title=Resource:Missiontimer&amp;diff=24369"/>
		<updated>2010-08-16T20:31:24Z</updated>

		<summary type="html">&lt;p&gt;R3mp: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Resource page}}&lt;br /&gt;
Missiontimer is a resource used to easily create timers that count down or up in your resources.&lt;br /&gt;
&lt;br /&gt;
== Overview ==&lt;br /&gt;
&lt;br /&gt;
The &amp;quot;deathmatch&amp;quot; gamemode is an example use of missiontimer.  It uses the &amp;quot;createMissionTimer&amp;quot; function to create a timer, and then the onMissionTimerElapsed event to trigger at the end:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;    g_MissionTimer = exports.missiontimer:createMissionTimer (g_TimeLimit,true,&amp;quot;%m:%s&amp;quot;,0.5,20,true,&amp;quot;default-bold&amp;quot;,1,255,255,255)&lt;br /&gt;
    addEventHandler ( &amp;quot;onMissionTimerElapsed&amp;quot;, g_MissionTimer, onTimeElapsed )&lt;br /&gt;
 &amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Then you use the onTimeElapsed function that you attached to the handler at the end of the timer.&lt;br /&gt;
&lt;br /&gt;
The arguments for createMissionTimer as follows:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;createMissionTimer ( duration, countdown, showCS, x, y, bg, font, scale )&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
* duration - The time in milliseconds&lt;br /&gt;
* countdown - A bool of whether to countdown or count up.  Setting it to true will count down from the duration, setting it to false will count up to the duration (latter isnt tested yet)&lt;br /&gt;
* format - A string detailing the format of the timer text to be shown. You can chose whether to show minutes, seconds or centiseconds using these 3 strings:&lt;br /&gt;
** %m - minutes&lt;br /&gt;
** %s - seconds&lt;br /&gt;
** %cs - centiseconds&lt;br /&gt;
This allows you to add normal text onto the timer as well as showing the time left (eg: &amp;quot;Time left: %m:%s&amp;quot;)&lt;br /&gt;
* x,y - Position on the screen, this uses &amp;quot;smart positioning&amp;quot;.  It can be relative or absolute - the deathmatch gamemode creates it at 0.5,20.  This means the x value is in the centre, the y is 20pixels from the top.  If you specify a negative value it draws the other way, i.e. -20 would be 20pixels from the bottom rather than the top.  The same can be done for x.&lt;br /&gt;
* bg - Whether to draw the default rounded-rectangle behind the timer.  Setting this to false will hide it&lt;br /&gt;
* font - The font of the timer.  Looks best in default-bold&lt;br /&gt;
* scale - The size of the text/bg.&lt;br /&gt;
* r,g,b - The red/green/blue components to make up the colour of the timer text (defaults to white)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
There are also some other exported functions that you may or may not need:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;setMissionTimerTime ( missionTimer, time )&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Sets the countdown/countup target time (in milliseconds) &lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;getMissionTimerTime ( missionTimer )&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Gets the number currently showing on the clock (in milliseconds)&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;setMissionTimerFrozen ( missionTimer, frozen )&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Sets the timer to frozen (true) or normal (false)&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;isMissionTimerFrozen ( missionTimer )&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
See if the timer is frozen&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;setMissionTimerHurryTime ( missionTimer, time )&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Set the time that the clock will turn red (in milliseconds) (ie: to indicate there is not much time left) &lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;setMissionTimerFormat ( missionTimer, format )&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Set the text format for the timer&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
To remove a missiontimer from the screen, use [[destroyElement]].&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Missiontimer is only compatible with MTASA 1.0 onwards.&lt;/div&gt;</summary>
		<author><name>R3mp</name></author>
	</entry>
	<entry>
		<id>https://wiki.multitheftauto.com/index.php?title=Resource:Missiontimer&amp;diff=24368</id>
		<title>Resource:Missiontimer</title>
		<link rel="alternate" type="text/html" href="https://wiki.multitheftauto.com/index.php?title=Resource:Missiontimer&amp;diff=24368"/>
		<updated>2010-08-16T16:32:09Z</updated>

		<summary type="html">&lt;p&gt;R3mp: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Resource page}}&lt;br /&gt;
Missiontimer is a resource used to easily create timers that count down or up in your resources.&lt;br /&gt;
&lt;br /&gt;
== Overview ==&lt;br /&gt;
&lt;br /&gt;
The &amp;quot;deathmatch&amp;quot; gamemode is an example use of missiontimer.  It uses the &amp;quot;createMissionTimer&amp;quot; function to create a timer, and then the onMissionTimerElapsed event to trigger at the end:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;    g_MissionTimer = exports.missiontimer:createMissionTimer (g_TimeLimit,true,true,0.5,20,true,&amp;quot;default-bold&amp;quot;,1,&amp;quot;Time left: &amp;quot;)&lt;br /&gt;
    addEventHandler ( &amp;quot;onMissionTimerElapsed&amp;quot;, g_MissionTimer, onTimeElapsed )&lt;br /&gt;
 &amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Then you use the onTimeElapsed function that you attached to the handler at the end of the timer.&lt;br /&gt;
&lt;br /&gt;
The arguments for createMissionTimer as follows:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;createMissionTimer ( duration, countdown, showCS, x, y, bg, font, scale )&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
* duration - The time in milliseconds&lt;br /&gt;
* countdown - A bool of whether to countdown or count up.  Setting it to true will count down from the duration, setting it to false will count up to the duration (latter isnt tested yet)&lt;br /&gt;
* showCS - A bool of whether to show Centiseconds.  true shows them, false hides them.  Showing centi seconds means its in the format of MM:SS:CS (e.g. 12:31:10), hiding them means its in the format of MM:SS (12:31)&lt;br /&gt;
* x,y - Position on the screen, this uses &amp;quot;smart positioning&amp;quot;.  It can be relative or absolute - the deathmatch gamemode creates it at 0.5,20.  This means the x value is in the centre, the y is 20pixels from the top.  If you specify a negative value it draws the other way, i.e. -20 would be 20pixels from the bottom rather than the top.  The same can be done for x.&lt;br /&gt;
* bg - Whether to draw the default rounded-rectangle behind the timer.  Setting this to false will hide it&lt;br /&gt;
* font - The font of the timer.  Looks best in default-bold&lt;br /&gt;
* scale - The size of the text/bg.&lt;br /&gt;
* prefix - Any text that you want to show in front of the time (eg: Time left: 00:00). Leave this blank for no text&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
There are also some other exported functions that you may or may not need:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;setMissionTimerTime ( missionTimer, time )&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Sets the countdown/countup target time (in milliseconds) &lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;getMissionTimerTime ( missionTimer )&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Gets the number currently showing on the clock (in milliseconds)&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;setMissionTimerFrozen ( missionTimer, frozen )&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Sets the timer to frozen (true) or normal (false)&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;isMissionTimerFrozen ( missionTimer )&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
See if the timer is frozen&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;setMissionTimerHurryTime ( missionTimer, time )&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Set the time that the clock will turn red (in milliseconds) (ie: to indicate there is not much time left) &lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;setMissionTimerPrefix ( missionTimer, prefix )&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Set the prefix text on the timer&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
To remove a missiontimer from the screen, use [[destroyElement]].&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Missiontimer is only compatible with MTASA 1.0 onwards.&lt;/div&gt;</summary>
		<author><name>R3mp</name></author>
	</entry>
	<entry>
		<id>https://wiki.multitheftauto.com/index.php?title=Resource:Missiontimer&amp;diff=24341</id>
		<title>Resource:Missiontimer</title>
		<link rel="alternate" type="text/html" href="https://wiki.multitheftauto.com/index.php?title=Resource:Missiontimer&amp;diff=24341"/>
		<updated>2010-08-11T18:52:07Z</updated>

		<summary type="html">&lt;p&gt;R3mp: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Resource page}}&lt;br /&gt;
Missiontimer is a resource used to easily create timers that count down or up in your resources.&lt;br /&gt;
&lt;br /&gt;
== Overview ==&lt;br /&gt;
&lt;br /&gt;
The &amp;quot;deathmatch&amp;quot; gamemode is an example use of missiontimer.  It uses the &amp;quot;createMissionTimer&amp;quot; function to create a timer, and then the onMissionTimerElapsed event to trigger at the end:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;    g_MissionTimer = exports.missiontimer:createMissionTimer (g_TimeLimit,true,true,0.5,20,true,&amp;quot;default-bold&amp;quot;,1)&lt;br /&gt;
    addEventHandler ( &amp;quot;onMissionTimerElapsed&amp;quot;, g_MissionTimer, onTimeElapsed )&lt;br /&gt;
 &amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Then you use the onTimeElapsed function that you attached to the handler at the end of the timer.&lt;br /&gt;
&lt;br /&gt;
The arguments for createMissionTimer as follows:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;createMissionTimer ( duration, countdown, showCS, x, y, bg, font, scale )&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
* duration - The time in milliseconds&lt;br /&gt;
* countdown - A bool of whether to countdown or count up.  Setting it to true will count down from the duration, setting it to false will count up to the duration (latter isnt tested yet)&lt;br /&gt;
* showCS - A bool of whether to show Centiseconds.  true shows them, false hides them.  Showing centi seconds means its in the format of MM:SS:CS (e.g. 12:31:10), hiding them means its in the format of MM:SS (12:31)&lt;br /&gt;
* x,y - Position on the screen, this uses &amp;quot;smart positioning&amp;quot;.  It can be relative or absolute - the deathmatch gamemode creates it at 0.5,20.  This means the x value is in the centre, the y is 20pixels from the top.  If you specify a negative value it draws the other way, i.e. -20 would be 20pixels from the bottom rather than the top.  The same can be done for x.&lt;br /&gt;
* bg - Whether to draw the default rounded-rectangle behind the timer.  Setting this to false will hide it&lt;br /&gt;
* font - The font of the timer.  Looks best in default-bold&lt;br /&gt;
* scale - The size of the text/bg.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
There are also some other exported functions that you may or may not need:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;setMissionTimerTime ( missionTimer, time )&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Sets the countdown/countup target time (in milliseconds) &lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;getMissionTimerTime ( missionTimer )&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Gets the number currently showing on the clock (in milliseconds)&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;setMissionTimerFrozen ( missionTimer, frozen )&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Sets the timer to frozen (true) or normal (false)&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;isMissionTimerFrozen ( missionTimer )&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
See if the timer is frozen&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;setMissionTimerHurryTime ( missionTimer, time )&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Set the time that the clock will turn red (in milliseconds) (ie: to indicate there is not much time left) &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
To remove a missiontimer from the screen, use [[destroyElement]].&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Missiontimer is only compatible with MTASA 1.0 onwards.&lt;/div&gt;</summary>
		<author><name>R3mp</name></author>
	</entry>
	<entry>
		<id>https://wiki.multitheftauto.com/index.php?title=Call&amp;diff=24104</id>
		<title>Call</title>
		<link rel="alternate" type="text/html" href="https://wiki.multitheftauto.com/index.php?title=Call&amp;diff=24104"/>
		<updated>2010-07-26T13:27:20Z</updated>

		<summary type="html">&lt;p&gt;R3mp: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;__NOTOC__ &lt;br /&gt;
{{Server client function}}&lt;br /&gt;
This function is used to call a function from another resource (which must be running). &lt;br /&gt;
&lt;br /&gt;
The function which you wish to call '''must''' first be exported within the resource's meta.  For example:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;xml&amp;quot;&amp;gt;&amp;lt;meta&amp;gt;&lt;br /&gt;
	&amp;lt;info author=&amp;quot;jbeta&amp;quot; type=&amp;quot;script&amp;quot; description=&amp;quot;Scoreboard resource&amp;quot; /&amp;gt;&lt;br /&gt;
	&amp;lt;script src=&amp;quot;scoreboard_client.lua&amp;quot; type=&amp;quot;client&amp;quot;/&amp;gt;&lt;br /&gt;
	&amp;lt;script src=&amp;quot;scoreboard_exports.lua&amp;quot; type=&amp;quot;server&amp;quot;/&amp;gt;&lt;br /&gt;
	&lt;br /&gt;
	&amp;lt;script src=&amp;quot;scoreboard_http.lua&amp;quot; type=&amp;quot;server&amp;quot;/&amp;gt;&lt;br /&gt;
	&lt;br /&gt;
	&amp;lt;export function=&amp;quot;getScoreboardColumns&amp;quot; http=&amp;quot;true&amp;quot; /&amp;gt;&lt;br /&gt;
	&amp;lt;export function=&amp;quot;getScoreboardRows&amp;quot; http=&amp;quot;true&amp;quot; /&amp;gt;&lt;br /&gt;
	&lt;br /&gt;
	&amp;lt;export function=&amp;quot;addScoreboardColumn&amp;quot; type=&amp;quot;server&amp;quot;/&amp;gt;&lt;br /&gt;
	&amp;lt;export function=&amp;quot;removeScoreboardColumn&amp;quot; type=&amp;quot;server&amp;quot;/&amp;gt;&lt;br /&gt;
	&lt;br /&gt;
	&amp;lt;export function=&amp;quot;setPlayerScoreboardForced&amp;quot; type=&amp;quot;server&amp;quot;/&amp;gt;&lt;br /&gt;
	&amp;lt;export function=&amp;quot;setScoreboardForced&amp;quot; type=&amp;quot;client&amp;quot;/&amp;gt;&lt;br /&gt;
&amp;lt;/meta&amp;gt;&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
This enables other resources to call a function from this resource.&lt;br /&gt;
&lt;br /&gt;
You cannot call a server function from the client or vice versa. See [[triggerServerEvent]] and [[triggerClientEvent]] for possibilities to do that.&lt;br /&gt;
&lt;br /&gt;
{{New feature|3|1.0|&lt;br /&gt;
There is an easier syntax replacing this function. For example, you can instead of:&amp;lt;br&amp;gt;&lt;br /&gt;
  call ( getResourceFromName ( &amp;quot;resource&amp;quot; ), &amp;quot;exportedFunction&amp;quot;, 1, &amp;quot;2&amp;quot;, &amp;quot;three&amp;quot; )&lt;br /&gt;
do much like a normal call:&amp;lt;br&amp;gt;&lt;br /&gt;
  exports.resource:exportedFunction ( 1, &amp;quot;2&amp;quot;, &amp;quot;three&amp;quot; )&lt;br /&gt;
If the resource name contains illegal characters (such as hyphens), you can also do:&amp;lt;br&amp;gt;&lt;br /&gt;
  exports[&amp;quot;resource&amp;quot;]:exportedFunction ( 1, &amp;quot;2&amp;quot;, &amp;quot;three&amp;quot; )&lt;br /&gt;
&lt;br /&gt;
When using the [[call]] function, two extra &amp;quot;hidden&amp;quot; variables are passed to the exported function:&lt;br /&gt;
* '''sourceResource''' - The resource that called the exported function&lt;br /&gt;
* '''sourceResourceRoot''' - The resource root element of the resource which called the exported function.&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
==Syntax== &lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
var... call ( resource theResource, string theFunction, [ arguments... ] )&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt; &lt;br /&gt;
&lt;br /&gt;
===Required Arguments=== &lt;br /&gt;
*'''theResource:''' This is a resource pointer which refers to the resource you are calling a function from.&lt;br /&gt;
*'''theFunction:''' This is a string with the name of the function which you want to call.&lt;br /&gt;
&lt;br /&gt;
===Optional Arguments=== &lt;br /&gt;
{{OptionalArg}} &lt;br /&gt;
*'''arguments:''' Any arguments you may want to pass to the function when it is called. Any number of arguments of can be specified, each being passed to the designated function.&lt;br /&gt;
&lt;br /&gt;
===Returns===&lt;br /&gt;
Returns anything that the designated function has returned appropriately.  If the function does not exist, is not exported, or the call was not successful it will return ''nil''.&lt;br /&gt;
&lt;br /&gt;
==Example==&lt;br /&gt;
&amp;lt;section name=&amp;quot;Server&amp;quot; class=&amp;quot;server&amp;quot; show=&amp;quot;true&amp;quot;&amp;gt; &lt;br /&gt;
This extract shows adding of a &amp;quot;kills&amp;quot; column to the scoreboard resource. This then sets the ''gameShowKills'' variable to true, telling the rest of the script to start outputting kills.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
function showKills ( option )&lt;br /&gt;
	if option == false then&lt;br /&gt;
		-- Remove the &amp;quot;kills&amp;quot; column&lt;br /&gt;
		gameShowKills = false&lt;br /&gt;
		call(getResourceFromName(&amp;quot;scoreboard&amp;quot;), &amp;quot;removeScoreboardColumn&amp;quot;, &amp;quot;kills&amp;quot;)&lt;br /&gt;
	else&lt;br /&gt;
		-- Add the &amp;quot;kills&amp;quot; column&lt;br /&gt;
		gameShowKills = true&lt;br /&gt;
		call(getResourceFromName(&amp;quot;scoreboard&amp;quot;), &amp;quot;addScoreboardColumn&amp;quot;, &amp;quot;kills&amp;quot;)&lt;br /&gt;
		outputDebugString ( &amp;quot;Showing kills now...&amp;quot; )&lt;br /&gt;
	end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&amp;lt;/section&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==See Also==&lt;br /&gt;
{{Resource_functions}}&lt;/div&gt;</summary>
		<author><name>R3mp</name></author>
	</entry>
	<entry>
		<id>https://wiki.multitheftauto.com/index.php?title=GuiCreateScrollPane&amp;diff=23622</id>
		<title>GuiCreateScrollPane</title>
		<link rel="alternate" type="text/html" href="https://wiki.multitheftauto.com/index.php?title=GuiCreateScrollPane&amp;diff=23622"/>
		<updated>2010-06-06T02:12:45Z</updated>

		<summary type="html">&lt;p&gt;R3mp: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Client function}}&lt;br /&gt;
__NOTOC__&lt;br /&gt;
This creates a GUI scroll pane.&lt;br /&gt;
&lt;br /&gt;
==Syntax== &lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
element guiCreateScrollPane( float x, float y, float width, float height, bool relative, [gui-element parent = nil])&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt; &lt;br /&gt;
&lt;br /&gt;
===Required Arguments=== &lt;br /&gt;
*'''x:''' the 2D x offset of the GUI scrollpane from its parent. This is affected by the relative argument.&lt;br /&gt;
*'''y:''' the 2D y offset of the GUI scrollbar from its parent. This is affected by the relative argument.&lt;br /&gt;
*'''width:''' the width of the GUI scrollpane. This is affected by the relative argument.&lt;br /&gt;
*'''height:''' the height of the GUI scrollpane. This is affected by the relative argument.&lt;br /&gt;
*'''relative:''' whether sizes and positions are relative to their parent's. If this is true, then all measures must be between 0 and 1, representing sizes/positions as a fraction of the parent widget's size.&lt;br /&gt;
&lt;br /&gt;
===Optional Arguments===&lt;br /&gt;
*'''parent:''' the gui-element this scrollpane is attached to. By default, it is nil, meaning the widget is attached to the background.&lt;br /&gt;
&lt;br /&gt;
===Returns===&lt;br /&gt;
The gui-element if created, otherwise false.&lt;br /&gt;
&lt;br /&gt;
==Example== &lt;br /&gt;
&amp;lt;section name=&amp;quot;Client&amp;quot; class=&amp;quot;client&amp;quot; show=&amp;quot;true&amp;quot;&amp;gt;&lt;br /&gt;
This example creates a small window with a scrollpane on. Using the /fill command you can populate the scrollpane with the names of every player in the server.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
addEventHandler(&amp;quot;onClientResourceStart&amp;quot;,resourceRoot,&lt;br /&gt;
	function()&lt;br /&gt;
		-- create a window and create a scrollpane on it&lt;br /&gt;
		local window = guiCreateWindow(5,5,130,150,&amp;quot;&amp;quot;,false)&lt;br /&gt;
		-- the width and height values here are largely irrelevant as the scrollpane will automatically resize when needed&lt;br /&gt;
		scrollpane = guiCreateScrollPane(0,0,130,150,false,window)&lt;br /&gt;
	end&lt;br /&gt;
)&lt;br /&gt;
&lt;br /&gt;
addCommandHandler(&amp;quot;fill&amp;quot;,&lt;br /&gt;
	function()&lt;br /&gt;
		-- if the scrollpane exists&lt;br /&gt;
		if scrollpane then&lt;br /&gt;
			-- delete all the existing labels&lt;br /&gt;
			for i,v in ipairs(getElementChildren(scrollpane)) do&lt;br /&gt;
				destroyElement(v)&lt;br /&gt;
			end&lt;br /&gt;
		&lt;br /&gt;
			-- for every player in the server&lt;br /&gt;
			for i,v in ipairs(getElementsByType(&amp;quot;player&amp;quot;)) do&lt;br /&gt;
				-- create a label with their name on the scrollpane&lt;br /&gt;
				guiCreateLabel(5,i*20,90,20,tostring(getPlayerName(v)),false,scrollpane)&lt;br /&gt;
			end&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&amp;lt;/section&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==See Also==&lt;br /&gt;
{{GUI functions}}&lt;/div&gt;</summary>
		<author><name>R3mp</name></author>
	</entry>
	<entry>
		<id>https://wiki.multitheftauto.com/index.php?title=ExecuteCommandHandler&amp;diff=23587</id>
		<title>ExecuteCommandHandler</title>
		<link rel="alternate" type="text/html" href="https://wiki.multitheftauto.com/index.php?title=ExecuteCommandHandler&amp;diff=23587"/>
		<updated>2010-05-31T16:16:20Z</updated>

		<summary type="html">&lt;p&gt;R3mp: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Server client function}}&lt;br /&gt;
__NOTOC__&lt;br /&gt;
This function will call all the attached functions of an existing console command, for a specified player.&lt;br /&gt;
&lt;br /&gt;
==Syntax== &lt;br /&gt;
&amp;lt;section name=&amp;quot;Server&amp;quot; class=&amp;quot;server&amp;quot; show=&amp;quot;true&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;bool executeCommandHandler ( string commandName, player thePlayer, [ string args ] )&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Required Arguments==&lt;br /&gt;
*'''commandName:''' The name of the command you wish to execute. This is what must be typed into the console to trigger the function.&lt;br /&gt;
*'''thePlayer:''' The player that will be presented as executer of the command to the handler function(s) of the command.&lt;br /&gt;
&lt;br /&gt;
==Optional Arguments==&lt;br /&gt;
{{OptionalArg}}&lt;br /&gt;
* '''args:''' Additional parameters that will be passed to the handler function(s) of the command that is called, separated by a space.&lt;br /&gt;
&amp;lt;/section&amp;gt;&lt;br /&gt;
&amp;lt;section name=&amp;quot;Client&amp;quot; class=&amp;quot;client&amp;quot; show=&amp;quot;true&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;bool executeCommandHandler ( string commandName, [ string args ] )&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Required Arguments==&lt;br /&gt;
*'''commandName:''' The name of the command you wish to execute. This is what must be typed into the console to trigger the function.&lt;br /&gt;
&lt;br /&gt;
==Optional Arguments==&lt;br /&gt;
{{OptionalArg}}&lt;br /&gt;
* '''args:''' Additional parameters that will be passed to the handler function(s) of the command that is called, separated by a space.&lt;br /&gt;
&amp;lt;/section&amp;gt;&lt;br /&gt;
===Returns===&lt;br /&gt;
Returns ''true'' if the command handler was called successfully, ''false'' otherwise.&lt;br /&gt;
&lt;br /&gt;
==Example== &lt;br /&gt;
&amp;lt;section name=&amp;quot;Server&amp;quot; class=&amp;quot;server&amp;quot; show=&amp;quot;true&amp;quot;&amp;gt;&lt;br /&gt;
This example defines a command handler for the command ''createmarker'' (which creates a red marker at the caller's position). It then creates a second command handler ''createmarker2'' which will call the first one.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
-- Define the function that will handle the 'createmarker' command&lt;br /&gt;
function consoleCreateMarker ( playerSource, commandName )&lt;br /&gt;
	-- If a player triggered it (rather than the admin) then&lt;br /&gt;
	if ( playerSource )&lt;br /&gt;
		-- Get that player's position&lt;br /&gt;
		x, y, z = getElementPosition ( playerSource )&lt;br /&gt;
		-- Create a marker at their position&lt;br /&gt;
		createMarker ( x, y, z, 0, &amp;quot;checkpoint&amp;quot;, 255, 0, 0, 255 )&lt;br /&gt;
		-- Output it in the chat box&lt;br /&gt;
		outputChatBox ( &amp;quot;You got a red marker&amp;quot;, playerSource )&lt;br /&gt;
	end&lt;br /&gt;
end&lt;br /&gt;
-- Add the function as a handler for the command&lt;br /&gt;
addCommandHandler ( &amp;quot;createmarker&amp;quot;, consoleCreateMarker )&lt;br /&gt;
&lt;br /&gt;
-- Define a second console command that will just call the first.&lt;br /&gt;
-- First define the function&lt;br /&gt;
function consoleCreateMarker2 ( playerSource, commandName )&lt;br /&gt;
	-- re-route back to the original&lt;br /&gt;
	executeCommandHandler ( &amp;quot;createmarker&amp;quot;, playerSource )&lt;br /&gt;
end&lt;br /&gt;
-- Then add it as a handler for the new console command&lt;br /&gt;
addCommandHandler ( &amp;quot;createmarker2&amp;quot;, consoleCreateMarker2 )&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&amp;lt;/section&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==See Also==&lt;br /&gt;
{{Server functions}}&lt;/div&gt;</summary>
		<author><name>R3mp</name></author>
	</entry>
	<entry>
		<id>https://wiki.multitheftauto.com/index.php?title=GuiDeleteTab&amp;diff=22556</id>
		<title>GuiDeleteTab</title>
		<link rel="alternate" type="text/html" href="https://wiki.multitheftauto.com/index.php?title=GuiDeleteTab&amp;diff=22556"/>
		<updated>2010-03-07T00:57:59Z</updated>

		<summary type="html">&lt;p&gt;R3mp: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;__NOTOC__ &lt;br /&gt;
{{Client function}}&lt;br /&gt;
This function deletes a tab from a tab panel.&lt;br /&gt;
&lt;br /&gt;
==Syntax== &lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
bool guiDeleteTab ( element tabToDelete, element tabPanel )&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt; &lt;br /&gt;
&lt;br /&gt;
===Required Arguments=== &lt;br /&gt;
*'''tabToDelete:''' This is an element representing the tab that you want to delete.&lt;br /&gt;
*'''tabPanel:''' This is the [[guiCreateTabPanel|tab panel]] parent that the tab is attached to.&lt;br /&gt;
&lt;br /&gt;
===Returns===&lt;br /&gt;
Returns ''true'' the tab was successfully deleted, ''false'' otherwise.&lt;br /&gt;
&lt;br /&gt;
==Example== &lt;br /&gt;
This example removes a tab panel if a user LeftCtrl+Clicks a tab panel.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
function deleteTabOnClick ()&lt;br /&gt;
	if ( getKeyState ( &amp;quot;lctrl&amp;quot; ) == true ) and ( getElementType( source ) == &amp;quot;gui-tab&amp;quot; ) then    -- if the user is holding down left control&lt;br /&gt;
		guiDeleteTab ( source, getElementParent(source) )                -- delete the tab. No need to check if it was actually a tab that was clicked, as this function doesn't work on other controls anyway&lt;br /&gt;
	end&lt;br /&gt;
end&lt;br /&gt;
addEventHandler ( &amp;quot;onClientGUIClick&amp;quot;, getRootElement(), deleteTabOnClick  )    -- add an event handler for clicks&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==See Also==&lt;br /&gt;
{{GUI functions}}&lt;/div&gt;</summary>
		<author><name>R3mp</name></author>
	</entry>
	<entry>
		<id>https://wiki.multitheftauto.com/index.php?title=GetResourceFromName&amp;diff=22285</id>
		<title>GetResourceFromName</title>
		<link rel="alternate" type="text/html" href="https://wiki.multitheftauto.com/index.php?title=GetResourceFromName&amp;diff=22285"/>
		<updated>2010-01-15T14:33:03Z</updated>

		<summary type="html">&lt;p&gt;R3mp: Undo revision 22282 by Bober370 (Talk) this would only work if the code was put in the playerblips resource, making it mostly redundant anyway&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;__NOTOC__&lt;br /&gt;
{{Server client function}}&lt;br /&gt;
This function is used to retrieve a resource from its name. A resource's name is the same as its folder or file archive name on the server (without the extension).&lt;br /&gt;
&lt;br /&gt;
==Syntax== &lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
resource getResourceFromName ( string resourceName )&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt; &lt;br /&gt;
&lt;br /&gt;
===Required Arguments=== &lt;br /&gt;
*'''resourceName:''' the name of the resource you wish to get.&lt;br /&gt;
&lt;br /&gt;
===Returns===&lt;br /&gt;
Returns the ''resource'' with the specified name, or ''false'' if no resource of that name exists.&lt;br /&gt;
&lt;br /&gt;
==Example==&lt;br /&gt;
&amp;lt;section name=&amp;quot;Server&amp;quot; class=&amp;quot;server&amp;quot; show=&amp;quot;true&amp;quot;&amp;gt;&lt;br /&gt;
This example prints out a message to the chatbox when a resource named ''playerblips'' is started.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
function onStart( theResource )&lt;br /&gt;
     local blipsResource = getResourceFromName ( &amp;quot;playerblips&amp;quot; ) -- get the resource of name &amp;quot;playerblips&amp;quot;&lt;br /&gt;
     if ( blipsResource and theResource == blipsResource ) then -- check if the resource started was it&lt;br /&gt;
          outputChatBox ( &amp;quot;Blips resource started!&amp;quot; )&lt;br /&gt;
     end&lt;br /&gt;
end&lt;br /&gt;
addEventHandler ( &amp;quot;onResourceStart&amp;quot;, getRootElement(), onStart )&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&amp;lt;/section&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==See Also==&lt;br /&gt;
{{Resource_functions}}&lt;/div&gt;</summary>
		<author><name>R3mp</name></author>
	</entry>
	<entry>
		<id>https://wiki.multitheftauto.com/index.php?title=Scripting_the_GUI_-_Tutorial_2&amp;diff=22284</id>
		<title>Scripting the GUI - Tutorial 2</title>
		<link rel="alternate" type="text/html" href="https://wiki.multitheftauto.com/index.php?title=Scripting_the_GUI_-_Tutorial_2&amp;diff=22284"/>
		<updated>2010-01-15T01:29:07Z</updated>

		<summary type="html">&lt;p&gt;R3mp: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;'''Scripting the GUI - Tutorial 2 (Gates + Keypads)'''&lt;br /&gt;
&lt;br /&gt;
In this tutorial we will look at creating GUI keypads with combination codes for map-defined object gates.&lt;br /&gt;
We will be using serverside keycodes, with some client - server interaction to verify the codes and report the outcome.&lt;br /&gt;
&lt;br /&gt;
'''Note that this tutorial assumes you are familiar with all the content covered in the [[Introduction to Scripting GUI|GUI Scripting Introduction]].'''&lt;br /&gt;
&lt;br /&gt;
[[Image:Gui_keypad_tutorial.png|thumb|GUI Keypad]]&lt;br /&gt;
&lt;br /&gt;
==Setting up the Keypad==&lt;br /&gt;
To begin, open up a clientside lua file (if you have been following the [[Introduction to Scripting GUI|GUI Scripting Introduction]], this is gui.lua) to work with.&lt;br /&gt;
&lt;br /&gt;
===Creating the GUI===&lt;br /&gt;
By now, GUI creation should seem relatively straight forward, so we will not go over this in too much detail.&lt;br /&gt;
As in [[Scripting the GUI - Tutorial 1|Tutorial 1]] we will be using '''absolute''' values in this tutorial.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
function createKeypad()&lt;br /&gt;
	-- get the screen width and height&lt;br /&gt;
	local sWidth, sHeight = guiGetScreenSize()&lt;br /&gt;
&lt;br /&gt;
	-- create the window, using some maths to find the centre of the screen&lt;br /&gt;
	local Width,Height = 142,276&lt;br /&gt;
	local X = (sWidth/2) - (Width/2)&lt;br /&gt;
	local Y = (sHeight/2) - (Height/2)&lt;br /&gt;
	keypadWindow = guiCreateWindow(X,Y,Width,Height,&amp;quot;Keypad&amp;quot;,false)&lt;br /&gt;
	&lt;br /&gt;
	-- don't allow people to resize the keypad&lt;br /&gt;
	guiWindowSetSizable(keypadWindow,false)&lt;br /&gt;
&lt;br /&gt;
	-- create buttons labeled 0-9, &amp;quot;*&amp;quot;, &amp;quot;#&amp;quot;, &amp;quot;Enter&amp;quot; and &amp;quot;C&amp;quot; (clear)&lt;br /&gt;
	keypadButton1 = guiCreateButton(13,68,37,36,&amp;quot;1&amp;quot;,false,keypadWindow)&lt;br /&gt;
	keypadButton2 = guiCreateButton(53,68,37,36,&amp;quot;2&amp;quot;,false,keypadWindow)&lt;br /&gt;
	keypadButton3 = guiCreateButton(93,68,37,36,&amp;quot;3&amp;quot;,false,keypadWindow)&lt;br /&gt;
	keypadButton4 = guiCreateButton(13,108,37,36,&amp;quot;4&amp;quot;,false,keypadWindow)&lt;br /&gt;
	keypadButton5 = guiCreateButton(53,108,37,36,&amp;quot;5&amp;quot;,false,keypadWindow)&lt;br /&gt;
	keypadButton6 = guiCreateButton(93,108,37,36,&amp;quot;6&amp;quot;,false,keypadWindow)&lt;br /&gt;
	keypadButton7 = guiCreateButton(13,148,37,36,&amp;quot;7&amp;quot;,false,keypadWindow)&lt;br /&gt;
	keypadButton8 = guiCreateButton(53,148,37,36,&amp;quot;8&amp;quot;,false,keypadWindow)&lt;br /&gt;
	keypadButton9 = guiCreateButton(93,148,37,36,&amp;quot;9&amp;quot;,false,keypadWindow)&lt;br /&gt;
	keypadButtonAsterix = guiCreateButton(13,188,37,36,&amp;quot;*&amp;quot;,false,keypadWindow)&lt;br /&gt;
	keypadButton0 = guiCreateButton(53,188,37,36,&amp;quot;0&amp;quot;,false,keypadWindow)&lt;br /&gt;
	keypadButtonHash = guiCreateButton(93,188,37,36,&amp;quot;#&amp;quot;,false,keypadWindow)&lt;br /&gt;
	keypadButtonExit = guiCreateButton(13,228,37,36,&amp;quot;Exit&amp;quot;,false,keypadWindow)&lt;br /&gt;
	keypadButtonEnter = guiCreateButton(53,228,37,36,&amp;quot;Enter&amp;quot;,false,keypadWindow)&lt;br /&gt;
	keypadButtonClear = guiCreateButton(93,228,37,36,&amp;quot;Clear&amp;quot;,false,keypadWindow)&lt;br /&gt;
&lt;br /&gt;
	-- create a gridlist to act as a backdrop on the kaypad display&lt;br /&gt;
	keypadGridlistDisplay = guiCreateGridList(13,25,117,33,false,keypadWindow)&lt;br /&gt;
	guiGridListSetSelectionMode(keypadGridlistDisplay,2)&lt;br /&gt;
	guiSetAlpha(keypadGridlistDisplay,0.6)&lt;br /&gt;
	-- create a label so we can write text on the keypad display&lt;br /&gt;
	keypadLabelDisplay = guiCreateLabel(14,26,115,30,&amp;quot;Enter Keycode.&amp;quot;,false,keypadWindow)&lt;br /&gt;
	guiLabelSetColor(keypadLabelDisplay,255,000,000)&lt;br /&gt;
	guiLabelSetVerticalAlign(keypadLabelDisplay,&amp;quot;center&amp;quot;)&lt;br /&gt;
	guiLabelSetHorizontalAlign(keypadLabelDisplay,&amp;quot;center&amp;quot;,false)&lt;br /&gt;
	&lt;br /&gt;
	guiSetVisible(keypadWindow,false)&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
-- create the GUI when the resource starts&lt;br /&gt;
addEventHandler(&amp;quot;onClientResourceStart&amp;quot;,getResourceRootElement(getThisResource()),createKeypad)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
As you can see, the keypad consists of 10 numerical keys (0-9), two character keys (* and #), a clear key, an exit key and an enter key.&lt;br /&gt;
This means the codes used on the keypad can contain any of these characters (0123456789*#).&lt;br /&gt;
&lt;br /&gt;
===Managing the display===&lt;br /&gt;
We will begin by writing a small function to control the display on the keypad.&lt;br /&gt;
This is done by encapsulating several methods of changing the text into a single function,&lt;br /&gt;
which will enable us to easily add/remove text from the display later on.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
function updateDisplay(text)&lt;br /&gt;
	-- if we are passing some text&lt;br /&gt;
	if text then&lt;br /&gt;
		-- if its a digit or * or #, then append it to the end of the display&lt;br /&gt;
		if tonumber(text) or text == &amp;quot;*&amp;quot; or text == &amp;quot;#&amp;quot; then&lt;br /&gt;
			guiSetText(keypadLabelDisplay,guiGetText(keypadLabelDisplay) .. text)&lt;br /&gt;
		-- otherwise replace the display with the new text&lt;br /&gt;
		else&lt;br /&gt;
			guiSetText(keypadLabelDisplay,text)&lt;br /&gt;
		end	&lt;br /&gt;
	-- if we pass nil, clear the display entirely&lt;br /&gt;
	else&lt;br /&gt;
		guiSetText(keypadLabelDisplay,&amp;quot;&amp;quot;)&lt;br /&gt;
	end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
We can now simply call updateDisplay(our text) to change the text on the display, or updateDisplay(nil) to clear it.&lt;br /&gt;
&lt;br /&gt;
===Detecting the clicks===&lt;br /&gt;
With so many buttons that do very similar tasks on our keypad, there are two methods available to us for detecting when a player clicks on them.&lt;br /&gt;
&lt;br /&gt;
We could add [[onClientGUIClick]] events for every button individually, as we have done in previous tutorials; Or, alternatively, &lt;br /&gt;
we could add a single [[onClientGUIClick]] handle for the window (which is the parent of all our other keypad GUI elements), filter our results to include only the buttons we want and trigger our own custom event.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
For the purposes of this tutorial and in the interest of outlining multiple approaches, we will explore the second method, though either one is an acceptable solution.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
addEventHandler(&amp;quot;onClientGUIClick&amp;quot;,keypadWindow,processKeypadClicks,true)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
'''Notice the final argument is set to 'true'. This means that clicks on any other elements in the same branch of the tree will also trigger this event handle (eg. clicks on our buttons).'''&lt;br /&gt;
&lt;br /&gt;
Add this line of code into your createKeypad function, after your GUI has been created.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Now that we are detecting all clicks on our GUI, we need to filter out the ones we do not want (ie: clicks on the window or display) and trigger our custom event:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
function processKeypadClicks(button,state)&lt;br /&gt;
	if button == &amp;quot;left&amp;quot; and state == &amp;quot;up&amp;quot; then&lt;br /&gt;
		-- if the source of this event is a gui button&lt;br /&gt;
		if getElementType(source) == &amp;quot;gui-button&amp;quot; then&lt;br /&gt;
			-- trigger our custom event and send the keypad id of this keypad as an argument&lt;br /&gt;
			triggerEvent(&amp;quot;onKeypadButtonClicked&amp;quot;,source,getElementData(keypadWindow,&amp;quot;keypadID&amp;quot;))&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
As you can see, we are now triggering our custom event &amp;quot;onKeypadButtonClicked&amp;quot; whenever a button is clicked on the keypad.&lt;br /&gt;
Also note we use element data &amp;quot;keypadID&amp;quot; to differentiate between keypads. This data will need to be set whenever the player is shown a new keypad.&lt;br /&gt;
We will cover this in more detail later.&lt;br /&gt;
&lt;br /&gt;
===Handling the clicks===&lt;br /&gt;
Much like when using [[triggerServerEvent]] in previous tutorials, we now need to define the event, only this time it is purely clientside:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
addEvent(&amp;quot;onKeypadButtonClicked&amp;quot;,false)&lt;br /&gt;
addEventHandler(&amp;quot;onKeypadButtonClicked&amp;quot;,root,&lt;br /&gt;
	function(keypadID)&lt;br /&gt;
&lt;br /&gt;
	end&lt;br /&gt;
)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Note the second argument in [[addEvent]] is set to false, indicating that this event cannot be triggered from the server.&lt;br /&gt;
Also note, the function we are using in the [[addEventHandler]] does not have a name. If you contract it down and remove the spacing, you get:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
addEventHandler(&amp;quot;onKeypadButtonClicked&amp;quot;,root,function() ... end)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
This simply means instead of storing the pointer to the function in a variable, we are passing it directly as an argument.&lt;br /&gt;
Doing it this way cleans up the code and will often make it easier to follow.&lt;br /&gt;
&lt;br /&gt;
Now that the event has been created, we can fill in the code logic that will control our button presses.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
addEvent(&amp;quot;onKeypadButtonClicked&amp;quot;,false)&lt;br /&gt;
addEventHandler(&amp;quot;onKeypadButtonClicked&amp;quot;,root,&lt;br /&gt;
	function(keypadID)&lt;br /&gt;
		-- clear the display if this is the first time its being used&lt;br /&gt;
		if guiGetText(keypadLabelDisplay) == &amp;quot;Enter Keycode.&amp;quot; or guiGetText(keypadLabelDisplay) == &amp;quot;Invalid Keycode.&amp;quot; then&lt;br /&gt;
			updateDisplay()&lt;br /&gt;
		end&lt;br /&gt;
	&lt;br /&gt;
	&lt;br /&gt;
		-- if its the clear button&lt;br /&gt;
		if guiGetText(source) == &amp;quot;Clear&amp;quot; then&lt;br /&gt;
			-- clear the display&lt;br /&gt;
			updateDisplay()&lt;br /&gt;
		&lt;br /&gt;
		-- if its the enter button&lt;br /&gt;
		elseif guiGetText(source) == &amp;quot;Enter&amp;quot; then&lt;br /&gt;
			-- get the currently entered code from the display&lt;br /&gt;
			local code = guiGetText(keypadLabelDisplay)&lt;br /&gt;
			&lt;br /&gt;
			-- if they have entered a code&lt;br /&gt;
			if code then&lt;br /&gt;
				-- trigger the server so we can verify their code&lt;br /&gt;
				triggerServerEvent(&amp;quot;verifyKeypadCode&amp;quot;,getLocalPlayer(),code,keypadID)&lt;br /&gt;
			end&lt;br /&gt;
		&lt;br /&gt;
		-- if its the exit button&lt;br /&gt;
		elseif guiGetText(source) == &amp;quot;Exit&amp;quot; then&lt;br /&gt;
			-- hide the keypad and reset the display text ready for next time&lt;br /&gt;
			guiSetVisible(keypadWindow,false)&lt;br /&gt;
			updateDisplay(&amp;quot;Enter Keycode.&amp;quot;)&lt;br /&gt;
			showCursor(false,false)&lt;br /&gt;
			&lt;br /&gt;
		-- otherwise, it must be a character button&lt;br /&gt;
		else&lt;br /&gt;
			updateDisplay(guiGetText(source))	&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Note how when we are clearing the display, we simply call updateDisplay() with no arguments. We do not need to pass 'nil' to it as all parameters (and variables) are nil by default.&lt;br /&gt;
&lt;br /&gt;
==Serverside Verification==&lt;br /&gt;
For this part of the tutorial, you will need to open up a serverside lua file from your resource to work with.&lt;br /&gt;
&lt;br /&gt;
===Defining the keycode===&lt;br /&gt;
Now that we have completed the keypad clicking logic, we need to move on to verifying the code entered into the keypad.&lt;br /&gt;
To do this, we need to have the correct code stored somewhere on the server, which we can check the players code against.&lt;br /&gt;
&lt;br /&gt;
'''Do not store sensitive information, such as keycodes or passwords, in a clientside file. All clientside files will be downloaded to the clients computer and can be accessed and read by anyone who has joined your server.'''&lt;br /&gt;
&lt;br /&gt;
For the purposes of this tutorial we will simply store the code in a serverside table, however it can be done any number of ways (such as serverside xml files or MySQL databases).&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
local keypadCodes = {&lt;br /&gt;
	[&amp;quot;a51MainGateKeypadCode&amp;quot;] = &amp;quot;4455*#&amp;quot;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
This table stores an entry called &amp;quot;a51MainGateKeypadCode&amp;quot; with the code 4455*#&lt;br /&gt;
&lt;br /&gt;
'''This is the keycode that you will use to open the gate later on in this tutorial.'''&lt;br /&gt;
&lt;br /&gt;
===Verifying the code===&lt;br /&gt;
Now that we have a keycode to verify against, we can write our serverside event:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
addEvent(&amp;quot;verifyKeypadCode&amp;quot;,true)&lt;br /&gt;
addEventHandler(&amp;quot;verifyKeypadCode&amp;quot;,root,function(code,keypadID)&lt;br /&gt;
	if code then&lt;br /&gt;
		-- using the table we created earlier, check if the code supplied is the same as the code for this gate&lt;br /&gt;
		if code == keypadCodes[keypadID] then&lt;br /&gt;
			-- if it is, tell the client that it was successful&lt;br /&gt;
			triggerClientEvent(client,&amp;quot;onKeypadVerificationSuccessful&amp;quot;,client,keypadID)&lt;br /&gt;
		else&lt;br /&gt;
			-- if it is not, tell the client that it was not successful&lt;br /&gt;
			triggerClientEvent(client,&amp;quot;onKeypadVerificationFailed&amp;quot;,client,keypadID)&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
end)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Here we use our table and the keypadID supplied by the player to check if the codes match.&lt;br /&gt;
&lt;br /&gt;
If you are not using a table to store the codes, then you will need to replace 'keypadCodes[keypadID]' with your own storage method.&lt;br /&gt;
Once it is verified (or not), we can trigger the client so the appropriate information can be shown on the keypad display.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Receiving the result==&lt;br /&gt;
We have now finished the serverside section of the tutorial, so you will need to open up the clientside lua file from your resource &lt;br /&gt;
that you were previously working on.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Once our code has been verified, the server will send back the response to the client.&lt;br /&gt;
In just the same way as client -&amp;gt; server interaction, we now need to add the event that the server is going to trigger on the client.&lt;br /&gt;
&lt;br /&gt;
===Catching and processing the result===&lt;br /&gt;
First we will add the event for when the verification is successful:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
addEvent(&amp;quot;onKeypadVerificationSuccessful&amp;quot;,true)&lt;br /&gt;
addEventHandler(&amp;quot;onKeypadVerificationSuccessful&amp;quot;,root,&lt;br /&gt;
	function()&lt;br /&gt;
		-- hide the keypad and reset the display text ready for next time&lt;br /&gt;
		guiSetVisible(keypadWindow,false)&lt;br /&gt;
		updateDisplay(&amp;quot;Enter Keycode.&amp;quot;)&lt;br /&gt;
		showCursor(false,false)&lt;br /&gt;
	end&lt;br /&gt;
)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Finally we can add the event for when the verification is unsuccessful:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
addEvent(&amp;quot;onKeypadVerificationFailed&amp;quot;,true)&lt;br /&gt;
addEventHandler(&amp;quot;onKeypadVerificationFailed&amp;quot;,root,&lt;br /&gt;
	function()&lt;br /&gt;
		-- update the display text to show the code was invalid&lt;br /&gt;
		updateDisplay(&amp;quot;Invalid Keycode.&amp;quot;)&lt;br /&gt;
	end&lt;br /&gt;
)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This completes the keypad section of the tutorial.&lt;br /&gt;
&lt;br /&gt;
For an example of how to implement this into a working gate system, carry on reading the next section.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Applying the Keypad==&lt;br /&gt;
For the keypad to have any use, we need something to use it on.&lt;br /&gt;
For this tutorial we will be using gates, and as mentioned earlier we will create a main gate into A51.&lt;br /&gt;
&lt;br /&gt;
===Creating the gate===&lt;br /&gt;
First of all, we need to create the gate object.&lt;br /&gt;
For the purposes of this example, we will be using a map file to store the object. &lt;br /&gt;
While this is the recommended method for defining objects, it is not the only way to approach it.&lt;br /&gt;
&lt;br /&gt;
Navigate to your resource folder and make a new file called gate.map, then add your new map file to your meta.xml using:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;map src=&amp;quot;gate.map&amp;quot;/&amp;gt;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
''If you are unsure of map file syntax, please see the [[Writing_Gamemodes| Writing Gamemodes Tutorial]] or check the [[Object]] page for help.''&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;map&amp;gt;&lt;br /&gt;
    &amp;lt;object id=&amp;quot;a51MainGateKeypadCode&amp;quot; model=&amp;quot;971&amp;quot; posX=&amp;quot;96.736&amp;quot; posY=&amp;quot;1918.352&amp;quot; posZ=&amp;quot;20.694&amp;quot; rotX=&amp;quot;0&amp;quot; rotY=&amp;quot;0&amp;quot; rotZ=&amp;quot;270.40&amp;quot; newPosX=&amp;quot;96.751&amp;quot; newPosY=&amp;quot;1914.474&amp;quot; newPosZ=&amp;quot;20.694&amp;quot; /&amp;gt;&lt;br /&gt;
&amp;lt;/map&amp;gt;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
This will create a gate object across the A51 entrance. The object will have position and rotation data, as well as its newPosX,newPosY and newPosZ information that we need to be able to move it.&lt;br /&gt;
&lt;br /&gt;
'''Note that the object id is the same as the table entry we created earlier to hold the access code.'''&lt;br /&gt;
This is one possible method that could be accessed to link this gate with that particular keycode.&lt;br /&gt;
&lt;br /&gt;
===Opening the keypad===&lt;br /&gt;
Back in the clientside lua file again, we can now work on linking the gate and the keypad.&lt;br /&gt;
&lt;br /&gt;
Now that we have our gate, we need a way of accessing the keypad to open it.&lt;br /&gt;
For the purposes of this tutorial we will use a simple command, however you could just as easily use a colshape or button press.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
addCommandHandler(&amp;quot;a51gate&amp;quot;,function()&lt;br /&gt;
	guiSetVisible(keypadWindow,true)&lt;br /&gt;
	showCursor(true,true)&lt;br /&gt;
	setElementData(keypadWindow,&amp;quot;keypadID&amp;quot;,&amp;quot;a51MainGateKeypadCode&amp;quot;)&lt;br /&gt;
end)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Note that we set the element data &amp;quot;keypadID&amp;quot;.&lt;br /&gt;
This is very important because it allows us to keep track of which gate we are trying to open (in this case, the &amp;quot;a51MainGateKeypadCode&amp;quot; gate).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Opening the gate===&lt;br /&gt;
With our gate created and our keypad ready, all thats left now is to open the gate.&lt;br /&gt;
Having created custom events earlier for successfully and unsuccessfully verifying the code, this now becomes very easy to do.&lt;br /&gt;
All we do is add an event handler for our custom &amp;quot;success&amp;quot; event, and using the keypadID we defined earlier we can move the gate inside it:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
addEventHandler(&amp;quot;onKeypadVerificationSuccessful&amp;quot;,root,&lt;br /&gt;
	-- keypadID is sent back from the server&lt;br /&gt;
	function(keypadID)&lt;br /&gt;
		-- get the gate object (this is where the id=&amp;quot;a51MainGateKeypadCode&amp;quot; tag in the map file becomes useful)&lt;br /&gt;
		local gate = getElementByID(keypadID)&lt;br /&gt;
&lt;br /&gt;
		-- if we found the object&lt;br /&gt;
		if gate then&lt;br /&gt;
			-- get the new position (as we defined in the map file)&lt;br /&gt;
			local x = tonumber(getElementData(gate,&amp;quot;newPosX&amp;quot;))&lt;br /&gt;
			local y = tonumber(getElementData(gate,&amp;quot;newPosY&amp;quot;))&lt;br /&gt;
			local z = tonumber(getElementData(gate,&amp;quot;newPosZ&amp;quot;))&lt;br /&gt;
&lt;br /&gt;
			-- move the gate&lt;br /&gt;
			moveObject(gate,1500,x,y,z)&lt;br /&gt;
			&lt;br /&gt;
			-- get the original position&lt;br /&gt;
			x = tonumber(getElementData(gate,&amp;quot;posX&amp;quot;))&lt;br /&gt;
			y = tonumber(getElementData(gate,&amp;quot;posY&amp;quot;))&lt;br /&gt;
			z = tonumber(getElementData(gate,&amp;quot;posZ&amp;quot;))	&lt;br /&gt;
			&lt;br /&gt;
			-- set a timer to close the gate in 5 seconds&lt;br /&gt;
			setTimer(moveObject,5000,1,gate,1500,x,y,z)&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Note how by using the keypadID sent back from the server, we can use if statements and checks against the id to control any number of gates from the same function.&lt;br /&gt;
&lt;br /&gt;
You should now have a working example of a GUI Keypad controlling an A51 Gate.&lt;br /&gt;
&lt;br /&gt;
For further GUI tutorials, see [[Scripting the GUI - Tutorial 3|Tutorial 3 (Scrolling News Feed)]]&lt;br /&gt;
&lt;br /&gt;
[[Category:GUI_Tutorials]]&lt;/div&gt;</summary>
		<author><name>R3mp</name></author>
	</entry>
	<entry>
		<id>https://wiki.multitheftauto.com/index.php?title=Introduction_to_Scripting_the_GUI&amp;diff=22283</id>
		<title>Introduction to Scripting the GUI</title>
		<link rel="alternate" type="text/html" href="https://wiki.multitheftauto.com/index.php?title=Introduction_to_Scripting_the_GUI&amp;diff=22283"/>
		<updated>2010-01-15T01:20:58Z</updated>

		<summary type="html">&lt;p&gt;R3mp: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;!-- place holder --&amp;gt;&lt;br /&gt;
One important feature in MTA:SA is the ability to script customized GUI (Graphic User Interface). The GUI consists of windows, button, edit boxes, check boxes... Almost every standard form components in graphical environments. They can be displayed while the user is in game, and used for inputs and outputs in place of traditional commands. &lt;br /&gt;
&lt;br /&gt;
[[Image:AdminGUI.png|thumb|Admin Console GUI]]&lt;br /&gt;
&lt;br /&gt;
==A tutorial to make a login window==&lt;br /&gt;
In this tutorial we'll make a simple login window, with two input boxes and a button. The window appears when the player joins the game, and once the button is clicked, the player is spawned. The tutorial will continue the gamemode we made in [[Scripting Introduction|Introduction to Scripting]] ''(If you have used the [[Scripting Introduction|Introduction to Scripting]], you will need to remove or comment the [[spawnPlayer]] line in the &amp;quot;joinHandler&amp;quot; function in your code, as we will be replacing it with a gui alternative in this tutorial)''. We'll also take a look at client-side scripting. &lt;br /&gt;
&lt;br /&gt;
===Draw the window===&lt;br /&gt;
All the GUI must be made client side. It is also a good practice to keep all the client scripts in a separate folder. &lt;br /&gt;
&lt;br /&gt;
Browse to /Your MTA Server/mods/deathmatch/resources/myserver/ directory, and create a folder named &amp;quot;client&amp;quot;. Under /client/ directory, create a text file and name it &amp;quot;gui.lua&amp;quot;. &lt;br /&gt;
&lt;br /&gt;
In this file we will write a funtion that draws the window. To create a window we will use [[guiCreateWindow]]:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
function createLoginWindow()&lt;br /&gt;
	-- define the X and Y positions of the window&lt;br /&gt;
	local X = 0.375&lt;br /&gt;
	local Y = 0.375&lt;br /&gt;
	-- define the width and height of the window&lt;br /&gt;
	local Width = 0.25&lt;br /&gt;
	local Height = 0.25&lt;br /&gt;
	-- create the window and save its element value into the variable 'wdwLogin'&lt;br /&gt;
	-- click on the function's name to read its documentation&lt;br /&gt;
	wdwLogin = guiCreateWindow(X, Y, Width, Height, &amp;quot;Please Log In&amp;quot;, true)&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Relative and Absolute===&lt;br /&gt;
Note that the final argument passed to guiCreateWindow in the above example is ''true''. This indicates that the coordinates and dimensions of the window are '''relative''', meaning they are a ''percentage'' of the total screen size. This means that if the far left side of the screen is 0, and the far right is 1, an X position of 0.5 would represent the centre point of the screen. Similarly, if the top of the screen is 0 and the bottom is 1, a Y position of 0.2 would be 20% of the way down the screen. The same principles apply to both Width and Height as well (with a Width value of 0.5 meaning the window will be half as wide as the screen).&lt;br /&gt;
&lt;br /&gt;
The alternative to using relative values is using '''absolute''' (by passing ''false'' instead of true to guiCreateWindow). Absolute values are calculated as the total number of pixels from the top-left corner of the parent (if no gui element parent is specified, the parent is the screen itself). If we assume a screen resolution of 1920x1200, the far left side of the screen being 0 pixels and the far right being 1920 pixels, an X position of 960 will represent the centre point of the screen. Similarly, if the top of the screen is 0 pixels and the bottom is 1200, a Y position of 20 would be 20 pixels down from the top of the screen. The same principles apple to both Width and Height as well (with a Width value of 50 meaning the window will be 50 pixels wide). ''You can use [[guiGetScreenSize]] and a little maths to calculate certain absolute positions.''&lt;br /&gt;
&lt;br /&gt;
The differences between using relative and absolute values is quite simple; gui created using absolute values will always remain exactly the same pixel size and position, while gui created using relative values will always be a percentage of its parent's size.&lt;br /&gt;
&lt;br /&gt;
Absolute is generally easier to maintain when editing code by hand, however your choice of type depends on the situation you are using it for.&lt;br /&gt;
&lt;br /&gt;
For the purposes of this introduction we will be using relative values.&lt;br /&gt;
&lt;br /&gt;
===Adding the components===&lt;br /&gt;
Next, we'll add the text labels (saying &amp;quot;username:&amp;quot; and &amp;quot;password:&amp;quot;), edit boxes (for entering your data) and a button to log in.&lt;br /&gt;
&lt;br /&gt;
To create buttons we use [[guiCreateButton]] and to create edit boxes use [[guiCreateEdit]]:&lt;br /&gt;
&lt;br /&gt;
'''Note that we are now writing more code for our existing 'createLoginWindow' function. This is not a new function and is meant to replace what you already have.''' &lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
function createLoginWindow()&lt;br /&gt;
	local X = 0.375&lt;br /&gt;
	local Y = 0.375&lt;br /&gt;
	local Width = 0.25&lt;br /&gt;
	local Height = 0.25&lt;br /&gt;
	wdwLogin = guiCreateWindow(X, Y, Width, Height, &amp;quot;Please Log In&amp;quot;, true)&lt;br /&gt;
	&lt;br /&gt;
	-- define new X and Y positions for the first label&lt;br /&gt;
	X = 0.0825&lt;br /&gt;
	Y = 0.2&lt;br /&gt;
	-- define new Width and Height values for the first label&lt;br /&gt;
	Width = 0.25&lt;br /&gt;
	Height = 0.25&lt;br /&gt;
	-- create the first label, note the final argument passed is 'wdwLogin' meaning the window&lt;br /&gt;
	-- we created above is the parent of this label (so all the position and size values are now relative to the position of that window)&lt;br /&gt;
	guiCreateLabel(X, Y, Width, Height, &amp;quot;Username&amp;quot;, true, wdwLogin)&lt;br /&gt;
	-- alter the Y value, so the second label is slightly below the first&lt;br /&gt;
	Y = 0.5&lt;br /&gt;
	guiCreateLabel(X, Y, Width, Height, &amp;quot;Password&amp;quot;, true, wdwLogin)&lt;br /&gt;
	&lt;br /&gt;
&lt;br /&gt;
	X = 0.415&lt;br /&gt;
	Y = 0.2&lt;br /&gt;
	Width = 0.5&lt;br /&gt;
	Height = 0.15&lt;br /&gt;
	edtUser = guiCreateEdit(X, Y, Width, Height, &amp;quot;&amp;quot;, true, wdwLogin)&lt;br /&gt;
	Y = 0.5&lt;br /&gt;
	edtPass = guiCreateEdit(X, Y, Width, Height, &amp;quot;&amp;quot;, true, wdwLogin)&lt;br /&gt;
	-- set the maximum character length for the username and password fields to 50&lt;br /&gt;
	guiEditSetMaxLength(edtUser, 50)&lt;br /&gt;
	guiEditSetMaxLength(edtPass, 50)&lt;br /&gt;
	&lt;br /&gt;
	X = 0.415&lt;br /&gt;
	Y = 0.7&lt;br /&gt;
	Width = 0.25&lt;br /&gt;
	Height = 0.2&lt;br /&gt;
	btnLogin = guiCreateButton(X, Y, Width, Height, &amp;quot;Log In&amp;quot;, true, wdwLogin)&lt;br /&gt;
	&lt;br /&gt;
	-- make the window invisible&lt;br /&gt;
	guiSetVisible(wdwLogin, false)&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Note that every GUI component created is a child of the window, this is done by specifying the parent element (wdwLogin, in this case) when creating the component. &lt;br /&gt;
&lt;br /&gt;
This is very useful because not only does it mean that all the components are attached to the window and will move with it, but also that any changes done to the parent window will be applied down the tree to these child components. For example, we can now hide all of the GUI we just created by simply hiding the window:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
guiSetVisible(wdwLogin, false) --hides all the GUI we made so we can show them to the player at the appropriate moment. &lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Using the function we wrote===&lt;br /&gt;
The createLoginWindow function is now complete, but it won't do anything until we call it. It is recommended to create all GUI when the client resource starts, hide them, and show them to the player later when needed. Therefore, we'll write an event handler for &amp;quot;[[onClientResourceStart]]&amp;quot; to create the window:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
-- attach the event handler to the root element of the resource&lt;br /&gt;
-- this means it will only trigger when its own resource is started&lt;br /&gt;
addEventHandler(&amp;quot;onClientResourceStart&amp;quot;, getResourceRootElement(getThisResource()), &lt;br /&gt;
	function ()&lt;br /&gt;
		createLoginWindow()&lt;br /&gt;
	end&lt;br /&gt;
)	&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
As this is a log in window, we now need to show the window when the player joins the game. &lt;br /&gt;
This can be done using the same event, &amp;quot;[[onClientResourceStart]]&amp;quot;, so we can modify the above code to include showing the window:&lt;br /&gt;
&lt;br /&gt;
'''Note that we are now writing more code for our existing 'onClientResourceStart' handler. This is not a new event handler and is meant to replace what you already have.''' &lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
addEventHandler(&amp;quot;onClientResourceStart&amp;quot;, getResourceRootElement(getThisResource()), &lt;br /&gt;
	function ()&lt;br /&gt;
		-- create the log in window and its components&lt;br /&gt;
		createLoginWindow()&lt;br /&gt;
&lt;br /&gt;
		-- output a brief welcome message to the player&lt;br /&gt;
                outputChatBox(&amp;quot;Welcome to My MTA:SA Server, please log in.&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
		-- if the GUI was successfully created, then show the GUI to the player&lt;br /&gt;
	        if (wdwLogin ~= nil) then&lt;br /&gt;
			guiSetVisible(wdwLogin, true)&lt;br /&gt;
		else&lt;br /&gt;
			-- if the GUI hasnt been properly created, tell the player&lt;br /&gt;
			outputChatBox(&amp;quot;An unexpected error has occurred and the log in GUI has not been created.&amp;quot;)&lt;br /&gt;
	        end &lt;br /&gt;
&lt;br /&gt;
		-- enable the players cursor (so they can select and click on the components)&lt;br /&gt;
	        showCursor(true)&lt;br /&gt;
		-- set the input focus onto the GUI, allowing players (for example) to press 'T' without the chatbox opening&lt;br /&gt;
	        guiSetInputEnabled(true)&lt;br /&gt;
	end&lt;br /&gt;
)	&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Note that we have a simple security check before making the window visible, so in the unlikely event that the window has not been created, meaning wdwLogin is not a valid element, we don't get an error and just inform the player what has happened. &lt;br /&gt;
In the next step, we will create the button functionality for the log in button.&lt;br /&gt;
&lt;br /&gt;
==Scripting the button==&lt;br /&gt;
Now that we have created our GUI and shown it to the player, we need to make it work. &lt;br /&gt;
&lt;br /&gt;
===Detecting the click===&lt;br /&gt;
When the player clicks on any part of the GUI, the event &amp;quot;[[onClientGUIClick]]&amp;quot; will be triggered for the GUI component you clicked on. This allows us to easily detect any clicks on the GUI elements we want to use.&lt;br /&gt;
For example, we can attach the event to the btnLogin button to catch any clicks on it:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
-- attach the event onClientGUIClick to btnLogin and set it to trigger the 'clientSubmitLogin' function&lt;br /&gt;
addEventHandler(&amp;quot;onClientGUIClick&amp;quot;, btnLogin, clientSubmitLogin, false)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
'''Note the final argument passed is &amp;quot;false&amp;quot;. This indicates that the event will only trigger directly on btnLogin, not if the event has propagated up or down the tree. Setting this to &amp;quot;true&amp;quot; while attaching to gui elements will mean that clicking on any element in the same branch will trigger this event.'''&lt;br /&gt;
&lt;br /&gt;
This line of code can now be added inside the createLoginWindow function. It is a common mistake to try and attach events to non-existant GUI elements, so make sure you always attach your events '''after''' the gui element (in this case, the button) has been created:&lt;br /&gt;
&lt;br /&gt;
'''Note that we are now writing more code for our existing 'createLoginWindow' function.''' &lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
function createLoginWindow()&lt;br /&gt;
	-- create all our GUI elements&lt;br /&gt;
	...&lt;br /&gt;
&lt;br /&gt;
	-- now add our onClientGUIClick event to the button we just created&lt;br /&gt;
	addEventHandler(&amp;quot;onClientGUIClick&amp;quot;, btnLogin, clientSubmitLogin, false)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Managing the click===&lt;br /&gt;
Now that we can detect when the player clicks on the button, we need to write code to manage what happens when they do.&lt;br /&gt;
In our [[onClientGUIClick]] event handle, we told it to call the function clientSubmitLogin whenever btnLogin is clicked.&lt;br /&gt;
Therefore, we can now use the function clientSubmitLogin to control what happens when the button is clicked:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
-- create the function and define the 'button' and 'state' parameters&lt;br /&gt;
-- (these are passed automatically by onClientGUIClick)&lt;br /&gt;
function clientSubmitLogin(button,state)&lt;br /&gt;
	-- if our login button was clicked with the left mouse button, and the state of the mouse button is up&lt;br /&gt;
	if button == &amp;quot;left&amp;quot; and state == &amp;quot;up&amp;quot; then&lt;br /&gt;
		-- move the input focus back onto the game (allowing players to move around, open the chatbox, etc)&lt;br /&gt;
		guiSetInputEnabled(false)&lt;br /&gt;
		-- hide the window and all the components&lt;br /&gt;
		guiSetVisible(wdwLogin, false)&lt;br /&gt;
		-- hide the mouse cursor&lt;br /&gt;
		showCursor(false)&lt;br /&gt;
	end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Now, when the button is clicked, the window will be hidden and all controls will be returned to the player. Next, we will tell the server to allow the player to spawn.&lt;br /&gt;
&lt;br /&gt;
===Triggering the server===&lt;br /&gt;
Triggering the server can be done using [[triggerServerEvent]]. This allows you to trigger a specified event on the server from the client. The same can be done in reverse using [[triggerClientEvent]].&lt;br /&gt;
Here, we use the [[triggerServerEvent]] function to call our own custom event on the server, named &amp;quot;submitLogin&amp;quot;, which will then control the spawning of the player serverside.&lt;br /&gt;
&lt;br /&gt;
'''Note that we are now writing more code for our existing 'clientSubmitLogin' function. This is not a new function and is meant to replace what you already have.''' &lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
function clientSubmitLogin(button,state)&lt;br /&gt;
	if button == &amp;quot;left&amp;quot; and state == &amp;quot;up&amp;quot; then&lt;br /&gt;
		-- get the text entered in the 'username' field&lt;br /&gt;
		local username = guiGetText(edtUser)&lt;br /&gt;
		-- get the text entered in the 'password' field&lt;br /&gt;
		local password = guiGetText(edtPass)&lt;br /&gt;
&lt;br /&gt;
		-- if the username and password both exist&lt;br /&gt;
		if username and password then&lt;br /&gt;
			-- trigger the server event 'submitLogin' and pass the username and password to it&lt;br /&gt;
			triggerServerEvent(&amp;quot;submitLogin&amp;quot;, getRootElement(), username, password)&lt;br /&gt;
&lt;br /&gt;
			-- hide the gui, hide the cursor and return control to the player&lt;br /&gt;
			guiSetInputEnabled(false)&lt;br /&gt;
			guiSetVisible(wdwLogin, false)&lt;br /&gt;
			showCursor(false)&lt;br /&gt;
		else&lt;br /&gt;
			-- otherwise, output a message to the player, do not trigger the server&lt;br /&gt;
			-- and do not hide the gui&lt;br /&gt;
			outputChatBox(&amp;quot;Please enter a username and password.&amp;quot;)&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Creating the serverside event===&lt;br /&gt;
At this point we now have all the code needed on the client side, so open up your serverside 'script.lua' file (from the [[Scripting Introduction|Introduction to Scripting]]) or another suitable serverside file to work with.&lt;br /&gt;
&lt;br /&gt;
On the server side, recall that we are spawning the player as soon as they login.&lt;br /&gt;
So, first of all, we will need to define the custom event that we used before on the client. This can be done using [[addEvent]] and [[addEventHandler]].&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
-- create our loginHandler function, with username and password parameters (passed from the client gui)&lt;br /&gt;
function loginHandler(username,password)&lt;br /&gt;
&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
-- define our custom event, and allow it to be triggered from the client ('true')&lt;br /&gt;
addEvent(&amp;quot;submitLogin&amp;quot;,true)&lt;br /&gt;
-- add an event handler so that when submitLogin is triggered, the function loginHandler is called&lt;br /&gt;
addEventHandler(&amp;quot;submitLogin&amp;quot;,root,loginHandler)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Logging in===&lt;br /&gt;
Now we have a function that is called through the custom event 'submitLogin', we can start to work on logging in and spawning the player, using our 'loginHandler' function:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
function loginHandler(username,password)&lt;br /&gt;
	-- check that the username and password are correct&lt;br /&gt;
	if username == &amp;quot;user&amp;quot; and password == &amp;quot;apple&amp;quot; then&lt;br /&gt;
		-- the player has successfully logged in, so spawn them&lt;br /&gt;
		if (client) then&lt;br /&gt;
			spawnPlayer(client, 1959.55, -1714.46, 10)&lt;br /&gt;
			fadeCamera(client, true)&lt;br /&gt;
			outputChatBox(&amp;quot;Welcome to My Server.&amp;quot;, client)&lt;br /&gt;
		end&lt;br /&gt;
	else&lt;br /&gt;
		-- if the username or password are not correct, output a message to the player&lt;br /&gt;
		outputChatBox(&amp;quot;Invalid username and password. Please re-connect and try again.&amp;quot;,client)&lt;br /&gt;
        end			&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
addEvent(&amp;quot;submitLogin&amp;quot;,true)&lt;br /&gt;
addEventHandler(&amp;quot;submitLogin&amp;quot;,root,loginHandler)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
'''For the purposes of this tutorial, a very basic username and password system is shown. For a more comprehensive alternative, you can use the Account System or a MySQL database.'''&lt;br /&gt;
&lt;br /&gt;
Also note the use of the variable &amp;quot;client&amp;quot;, it's an internal variable used by MTA to identify the player who triggered the event. &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Finally, do not forget to include the new gui.lua file in the meta.xml of the main resource, and label it as a client script:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;xml&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;script src=&amp;quot;client/gui.lua&amp;quot; type=&amp;quot;client&amp;quot; /&amp;gt;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
At this point, we now have a basic login window that checks the player's username and password when the login button is clicked. If they are correct, the player is automatically spawned.&lt;br /&gt;
&lt;br /&gt;
For further help with GUI, see the [[:Category:GUI_Tutorials|GUI tutorials]].&lt;br /&gt;
&lt;br /&gt;
[[Category:GUI_Tutorials]]&lt;br /&gt;
[[it:Introduzione_allo_scripting_della_GUI]]&lt;br /&gt;
[[ru:Introduction to Scripting the GUI]]&lt;/div&gt;</summary>
		<author><name>R3mp</name></author>
	</entry>
	<entry>
		<id>https://wiki.multitheftauto.com/index.php?title=Scripting_the_GUI_-_Tutorial_1&amp;diff=22259</id>
		<title>Scripting the GUI - Tutorial 1</title>
		<link rel="alternate" type="text/html" href="https://wiki.multitheftauto.com/index.php?title=Scripting_the_GUI_-_Tutorial_1&amp;diff=22259"/>
		<updated>2010-01-08T02:46:55Z</updated>

		<summary type="html">&lt;p&gt;R3mp: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;'''Scripting the Gui - Tutorial 1 (Gridlists)'''&lt;br /&gt;
&lt;br /&gt;
In this tutorial we will explore the use of gridlists in creating a vehicle selection screen, with optional clientside vehicle xml data reading.&lt;br /&gt;
&lt;br /&gt;
'''Note that this tutorial assumes you are familiar with all the content covered in the [[Introduction to Scripting GUI|Previous tutorial]].'''&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Setting up the Vehicle Selection==&lt;br /&gt;
&lt;br /&gt;
===Creating the GUI===&lt;br /&gt;
To begin, open up a clientside lua file (if you have been following the [[Scripting Introduction]], this is gui.lua) to work with.&lt;br /&gt;
&lt;br /&gt;
In this file, we will start writing our function for creating the GUI.&lt;br /&gt;
As covered in the [[Introduction to Scripting GUI|Previous tutorial]], there are 2 value type options available when creating gui: '''relative''' and '''absolute'''.&lt;br /&gt;
&lt;br /&gt;
For the purposes of this tutorial, we will be using '''absolute''' values.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
This will create a simple GUI with a window, gridlist and button:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
function createVehicleSelection()&lt;br /&gt;
	-- get the screen width and height&lt;br /&gt;
	local sWidth, sHeight = guiGetScreenSize()&lt;br /&gt;
	&lt;br /&gt;
	-- use some simple maths to position the window in the centre of the screen&lt;br /&gt;
	local Width,Height = 376,259&lt;br /&gt;
	local X = (sWidth/2) - (Width/2)&lt;br /&gt;
	local Y = (sHeight/2) - (Height/2)&lt;br /&gt;
	windowVehicleSelection = guiCreateWindow(X,Y,Width,Height,&amp;quot;Vehicle Selection Window&amp;quot;,false)&lt;br /&gt;
	&lt;br /&gt;
	gridlistVehicleSelection = guiCreateGridList(10,26,357,192,false,windowVehicleSelection)&lt;br /&gt;
	-- add a &amp;quot;Vehicle&amp;quot; and a &amp;quot;Type&amp;quot; collumn to the gridlist&lt;br /&gt;
	guiGridListAddColumn(gridlistVehicleSelection,&amp;quot;Vehicle&amp;quot;,0.2)&lt;br /&gt;
	guiGridListAddColumn(gridlistVehicleSelection,&amp;quot;Type&amp;quot;,0.2)&lt;br /&gt;
	&lt;br /&gt;
	-- set the default width of the columns to roughly half the size of the gridlist (each)&lt;br /&gt;
	guiGridListSetColumnWidth(gridlistVehicleSelection,1,0.4,true)&lt;br /&gt;
	guiGridListSetColumnWidth(gridlistVehicleSelection,2,0.5,true)&lt;br /&gt;
	&lt;br /&gt;
	buttonCreate = guiCreateButton(121,227,120,20,&amp;quot;Create&amp;quot;,false,windowVehicleSelection)&lt;br /&gt;
	&lt;br /&gt;
	-- add the event handler for when the button is clicked&lt;br /&gt;
	addEventHandler(&amp;quot;onClientGUIClick&amp;quot;,buttonCreate,createVehicleHandler,false)&lt;br /&gt;
	&lt;br /&gt;
	-- hide the GUI&lt;br /&gt;
	guiSetVisible(windowVehicleSelection,false)&lt;br /&gt;
	&lt;br /&gt;
	-- this will add all the vehicle options onto the gridlist, it is explained later in this tutorial&lt;br /&gt;
	populateGridlist()&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
We now also need to call this function somewhere, otherwise the GUI will never be created.&lt;br /&gt;
As in previous tutorials, to do this we can use [[onClientResourceStart]].&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
-- when the resource is started, create the GUI and hide it&lt;br /&gt;
addEventHandler(&amp;quot;onClientResourceStart&amp;quot;,getResourceRootElement(getThisResource()),&lt;br /&gt;
	function()&lt;br /&gt;
		createVehicleSelection()&lt;br /&gt;
	end&lt;br /&gt;
)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Showing the GUI===&lt;br /&gt;
Unlike in previous tutorials, we want players to be able to open this window whenever they chose, not when the resource starts. &lt;br /&gt;
So, we can add a [[addCommandHandler|Command]] to do this.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
-- create the function that will show the window&lt;br /&gt;
function showVehicleSelection()&lt;br /&gt;
	-- if the window isnt visible, show it&lt;br /&gt;
	if not guiGetVisible(windowVehicleSelection) then&lt;br /&gt;
		guiSetVisible(windowVehicleSelection,true)&lt;br /&gt;
		&lt;br /&gt;
		showCursor(true,true)&lt;br /&gt;
	end&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
-- add the command /vehicleselection and set it to call the showVehicleSelection function&lt;br /&gt;
addCommandHandler(&amp;quot;vehicleselection&amp;quot;,showVehicleSelection)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Populating the Gridlist from a table===&lt;br /&gt;
Now that we have our basic GUI created, we need to fill the gridlist with all of our vehicles.&lt;br /&gt;
&lt;br /&gt;
To begin with, we will do this using a simple clientside table. &lt;br /&gt;
Later in the tutorial, we will explore expanding this method to use .xml files for storing information.&lt;br /&gt;
To begin, we must create a small table containing a selection of vehicles that we can spawn.&lt;br /&gt;
&lt;br /&gt;
The table contains vehicles in the format [&amp;quot;description&amp;quot;] = vehicle_id :&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
-- create the table and fill it with a selection of vehicle ids and names&lt;br /&gt;
local vehicleSelectionTable = {&lt;br /&gt;
	[&amp;quot;Sparrow&amp;quot;] = 469,&lt;br /&gt;
	[&amp;quot;Stuntplane&amp;quot;] = 513,&lt;br /&gt;
	[&amp;quot;BF-400&amp;quot;] = 581,&lt;br /&gt;
	[&amp;quot;Freeway&amp;quot;] = 463,&lt;br /&gt;
	[&amp;quot;Speeder&amp;quot;] = 452,&lt;br /&gt;
	[&amp;quot;Jester&amp;quot;] = 559,&lt;br /&gt;
	[&amp;quot;Sabre&amp;quot;] = 475,&lt;br /&gt;
	[&amp;quot;Police Ranger&amp;quot;] = 599,&lt;br /&gt;
	[&amp;quot;Utility Van&amp;quot;] = 552,&lt;br /&gt;
	[&amp;quot;Tug&amp;quot;] = 583&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Place this code at the very top of your file (it does not need to be inside a function).&lt;br /&gt;
&lt;br /&gt;
Next, we can write our &amp;quot;populateGridlist&amp;quot; function which will fill the Gridlist with all the vehicles in the table.&lt;br /&gt;
To do this we simply need to loop through all the values in the table, adding each one to the gridlist as we go.&lt;br /&gt;
We will also set hidden data using [[guiGridListSetItemData]] to store the vehicle id:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
function populateGridlist()&lt;br /&gt;
	-- loop through the table&lt;br /&gt;
	for name,vehicle in pairs(vehicleSelectionTable) do&lt;br /&gt;
		-- add a new row to the gridlist&lt;br /&gt;
		local row = guiGridListAddRow(gridlistVehicleSelection)&lt;br /&gt;
&lt;br /&gt;
		-- set the text in the first column to the vehicle name&lt;br /&gt;
		guiGridListSetItemText(gridlistVehicleSelection,row,1,name,false,false)&lt;br /&gt;
		-- set the text in the second column to the vehicle type&lt;br /&gt;
		guiGridListSetItemText(gridlistVehicleSelection,row,2,getVehicleType(vehicle),false,false)&lt;br /&gt;
		&lt;br /&gt;
		-- set the data for gridlist slot as the vehicle id&lt;br /&gt;
		guiGridListSetItemData(gridlistVehicleSelection,row,1,tostring(vehicle))&lt;br /&gt;
	end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt; &lt;br /&gt;
&lt;br /&gt;
===Managing the click===&lt;br /&gt;
Now that we have our GUI completed, we need to be able to catch any clicks made on the &amp;quot;create&amp;quot; button.&lt;br /&gt;
We have attached the [[onClientGUIClick]] event to buttonCreate already, so now we need to write the function that it calls.&lt;br /&gt;
In this function we do some basic error checking, such as making sure a vehicle has been selected in the list. &lt;br /&gt;
We can then use some maths to find a position infront of the player and send the server this information to spawn the vehicle (using [[triggerServerEvent]]) &lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
function createVehicleHandler(button,state)&lt;br /&gt;
	if button == &amp;quot;left&amp;quot; and state == &amp;quot;up&amp;quot; then&lt;br /&gt;
		-- get the selected item in the gridlist&lt;br /&gt;
		local row,col = guiGridListGetSelectedItem(gridlistVehicleSelection)&lt;br /&gt;
		&lt;br /&gt;
		-- if something is selected&lt;br /&gt;
		if row and col and row ~= -1 and col ~= -1 then&lt;br /&gt;
			-- get the vehicle id data from the gridlist that is selected&lt;br /&gt;
			local selected = guiGridListGetItemData(gridlistVehicleSelection,row,col)&lt;br /&gt;
			&lt;br /&gt;
			-- make sure the vehicle id is a number not a string&lt;br /&gt;
			selected = tonumber(selected)&lt;br /&gt;
						&lt;br /&gt;
			-- get the players position and rotation&lt;br /&gt;
			local rotz = getPedRotation(getLocalPlayer())&lt;br /&gt;
			local x,y,z = getElementPosition(getLocalPlayer())&lt;br /&gt;
			-- find the position directly infront of the player&lt;br /&gt;
			x = x + ( math.cos ( math.rad ( rotz+90 ) ) * 3)&lt;br /&gt;
			y = y + ( math.sin ( math.rad ( rotz+90 ) ) * 3)&lt;br /&gt;
			&lt;br /&gt;
			if selected and x and y and z then&lt;br /&gt;
				-- trigger the server&lt;br /&gt;
				triggerServerEvent(&amp;quot;createVehicleFromGUI&amp;quot;,getRootElement(),selected,x,y,z)&lt;br /&gt;
				&lt;br /&gt;
				-- hide the gui and the cursor&lt;br /&gt;
				guiSetVisible(windowVehicleSelection,false)&lt;br /&gt;
				showCursor(false,false)&lt;br /&gt;
			else&lt;br /&gt;
				outputChatBox(&amp;quot;Invalid arguments.&amp;quot;)&lt;br /&gt;
			end&lt;br /&gt;
		else&lt;br /&gt;
			-- otherwise, output a message to the player&lt;br /&gt;
			outputChatBox(&amp;quot;Please select a vehicle.&amp;quot;)&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Creating the Vehicle===&lt;br /&gt;
At this point we now have all the code needed on the client side, so open up a serverside .lua file to work with. &lt;br /&gt;
&lt;br /&gt;
On the server side, we will first of all need to define the custom event that we triggered before from the client. This can be done using [[addEvent]] and [[addEventHandler]].&lt;br /&gt;
Finally we will need a small function for creating the vehicle:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
function createMyVehicle(vehicleid,x,y,z)&lt;br /&gt;
	-- check all the arguments exist&lt;br /&gt;
	if vehicleid and x and y and z then&lt;br /&gt;
		createVehicle(vehicleid,x,y,z)&lt;br /&gt;
	end&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
addEvent(&amp;quot;createVehicleFromGUI&amp;quot;,true)&lt;br /&gt;
addEventHandler(&amp;quot;createVehicleFromGUI&amp;quot;,root,createMyVehicle)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Note the use of the &amp;quot;root&amp;quot; variable. This is an MTA variable containing the root element; every resource has one.&lt;br /&gt;
&lt;br /&gt;
This completes the first section of the tutorial. You should now have a basic, working vehicle spawn script.&lt;br /&gt;
&lt;br /&gt;
In the second section, we will cover collapsible gridlist data and clientside xml file reading.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Expanding the code==&lt;br /&gt;
This section will detail several ways to improve upon the code you now have.&lt;br /&gt;
&lt;br /&gt;
===Importing Data===&lt;br /&gt;
One big improvement over the previously mentioned method is to use external files to store the vehicle information, allowing us to much more quickly and easily manage large amounts of data.&lt;br /&gt;
For this tutorial, we will use a clientside xml file to hold the information.&lt;br /&gt;
&lt;br /&gt;
First of all you will need to create your xml file, so navigate to your resources directory and create a new file named vehicles.xml:&lt;br /&gt;
&lt;br /&gt;
''For the purpose of this example, we will include only a small fraction of the total vehicles, however the file can easily be expanded to include them all.''&lt;br /&gt;
&lt;br /&gt;
If you are unsure of xml data structures, you can browse the [[Server_Scripting_Functions#XML_functions| MTA xml functions]] for help.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;root&amp;gt;&lt;br /&gt;
	&amp;lt;group type=&amp;quot;Bikes&amp;quot;&amp;gt;&lt;br /&gt;
		&amp;lt;vehicle id=&amp;quot;581&amp;quot; name=&amp;quot;BF-400&amp;quot;/&amp;gt;&lt;br /&gt;
		&amp;lt;vehicle id=&amp;quot;463&amp;quot; name=&amp;quot;Freeway&amp;quot;/&amp;gt;&lt;br /&gt;
		&amp;lt;vehicle id=&amp;quot;481&amp;quot; name=&amp;quot;BMX&amp;quot;/&amp;gt;&lt;br /&gt;
	&amp;lt;/group&amp;gt;&lt;br /&gt;
	&amp;lt;group type=&amp;quot;Boats&amp;quot;&amp;gt;&lt;br /&gt;
		&amp;lt;vehicle id=&amp;quot;472&amp;quot; name=&amp;quot;Coastguard&amp;quot;/&amp;gt;&lt;br /&gt;
		&amp;lt;vehicle id=&amp;quot;452&amp;quot; name=&amp;quot;Speeder&amp;quot;/&amp;gt;&lt;br /&gt;
	&amp;lt;/group&amp;gt;&lt;br /&gt;
	&amp;lt;group type=&amp;quot;Helicopters&amp;quot;&amp;gt;&lt;br /&gt;
		&amp;lt;vehicle id=&amp;quot;487&amp;quot; name=&amp;quot;Maverick&amp;quot;/&amp;gt;&lt;br /&gt;
		&amp;lt;vehicle id=&amp;quot;469&amp;quot; name=&amp;quot;Sparrow&amp;quot;/&amp;gt;	&lt;br /&gt;
	&amp;lt;/group&amp;gt;&lt;br /&gt;
	&amp;lt;group type=&amp;quot;Planes&amp;quot;&amp;gt;&lt;br /&gt;
		&amp;lt;vehicle id=&amp;quot;593&amp;quot; name=&amp;quot;Dodo&amp;quot;/&amp;gt;&lt;br /&gt;
		&amp;lt;vehicle id=&amp;quot;513&amp;quot; name=&amp;quot;Stuntplane&amp;quot;/&amp;gt;	&lt;br /&gt;
	&amp;lt;/group&amp;gt;&lt;br /&gt;
	&amp;lt;group type=&amp;quot;Sports Cars&amp;quot;&amp;gt;&lt;br /&gt;
		&amp;lt;vehicle id=&amp;quot;565&amp;quot; name=&amp;quot;Flash&amp;quot;/&amp;gt;&lt;br /&gt;
		&amp;lt;vehicle id=&amp;quot;559&amp;quot; name=&amp;quot;Jester&amp;quot;/&amp;gt;&lt;br /&gt;
		&amp;lt;vehicle id=&amp;quot;477&amp;quot; name=&amp;quot;ZR-350&amp;quot;/&amp;gt;	&lt;br /&gt;
	&amp;lt;/group&amp;gt;&lt;br /&gt;
	&amp;lt;group type=&amp;quot;2-Door&amp;quot;&amp;gt;&lt;br /&gt;
		&amp;lt;vehicle id=&amp;quot;474&amp;quot; name=&amp;quot;Hermes&amp;quot;/&amp;gt;&lt;br /&gt;
		&amp;lt;vehicle id=&amp;quot;475&amp;quot; name=&amp;quot;Sabre&amp;quot;/&amp;gt;&lt;br /&gt;
	&amp;lt;/group&amp;gt;&lt;br /&gt;
	&amp;lt;group type=&amp;quot;Emergency&amp;quot;&amp;gt;&lt;br /&gt;
		&amp;lt;vehicle id=&amp;quot;416&amp;quot; name=&amp;quot;Ambulance&amp;quot;/&amp;gt;&lt;br /&gt;
		&amp;lt;vehicle id=&amp;quot;599&amp;quot; name=&amp;quot;Police ranger&amp;quot;/&amp;gt;&lt;br /&gt;
	&amp;lt;/group&amp;gt;&lt;br /&gt;
	&amp;lt;group type=&amp;quot;Industrial&amp;quot;&amp;gt;&lt;br /&gt;
		&amp;lt;vehicle id=&amp;quot;573&amp;quot; name=&amp;quot;Dune&amp;quot;/&amp;gt;&lt;br /&gt;
		&amp;lt;vehicle id=&amp;quot;552&amp;quot; name=&amp;quot;Utility van&amp;quot;/&amp;gt;	&lt;br /&gt;
	&amp;lt;/group&amp;gt;&lt;br /&gt;
	&amp;lt;group type=&amp;quot;Misc&amp;quot;&amp;gt;&lt;br /&gt;
		&amp;lt;vehicle id=&amp;quot;457&amp;quot; name=&amp;quot;Caddy&amp;quot;/&amp;gt;&lt;br /&gt;
		&amp;lt;vehicle id=&amp;quot;583&amp;quot; name=&amp;quot;Tug&amp;quot;/&amp;gt;&lt;br /&gt;
	&amp;lt;/group&amp;gt;&lt;br /&gt;
&amp;lt;/root&amp;gt;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Once you have created your file, do not forget to add it to the meta.xml of your resource with the appropriate client tag.&lt;br /&gt;
&lt;br /&gt;
Note the group &amp;quot;type&amp;quot; tag. This is an arbitrary description of the vehicles contained within the group and can be renamed or added as any text.&lt;br /&gt;
Similarly, the vehicle &amp;quot;name&amp;quot; tag is also just a textual description of the vehicle and does not need to be the exact vehicle name.&lt;br /&gt;
&lt;br /&gt;
Now that we have the data, we can import it into the game and display it in the GUI.&lt;br /&gt;
'''If you are following on from the first section of this tutorial, this new code will replace what is inside your existing 'populateGridlist' function.'''&lt;br /&gt;
First, we need to load the file:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
function populateGridlist()&lt;br /&gt;
	-- load the file and save the root node value it returns&lt;br /&gt;
	local rootnode = xmlLoadFile(&amp;quot;vehicles.xml&amp;quot;)&lt;br /&gt;
	&lt;br /&gt;
	-- check that the file exists and has been correctly loaded&lt;br /&gt;
	if rootnode then		&lt;br /&gt;
		-- unload the xml file&lt;br /&gt;
		xmlUnloadFile(rootnode)&lt;br /&gt;
	end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Always make sure you unload any files once you are finished using them.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
We can now start collecting the data from the file and entering it into our gridlist.&lt;br /&gt;
We can do this by looping through the xml data (in a similar manner to looping through the vehicle table earlier in this tutorial) and adding each entry into the list.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
function populateGridlist()&lt;br /&gt;
	local rootnode = xmlLoadFile(&amp;quot;vehicles.xml&amp;quot;)&lt;br /&gt;
	&lt;br /&gt;
	if rootnode then		&lt;br /&gt;
		-- first, we find every &amp;quot;group&amp;quot; node (they are direct children of the root)&lt;br /&gt;
		for _,group in ipairs(xmlNodeGetChildren(rootnode)) do&lt;br /&gt;
			-- add a new row to the gridlist&lt;br /&gt;
			local row = guiGridListAddRow(gridlistVehicleSelection)&lt;br /&gt;
&lt;br /&gt;
			-- get the group name&lt;br /&gt;
			local name = xmlNodeGetAttribute(group,&amp;quot;type&amp;quot;)&lt;br /&gt;
			&lt;br /&gt;
			-- set the text in the first column to the group type and indicate it is a section ('true')&lt;br /&gt;
			-- (sections on gridlists show up in bold and cannot be clicked)&lt;br /&gt;
			guiGridListSetItemText(gridlistVehicleSelection,row,1,name,true,false)			&lt;br /&gt;
		&lt;br /&gt;
			-- then, for every group that we find, loop all of its children (the vehicle nodes)&lt;br /&gt;
			-- and add them into the gridlist&lt;br /&gt;
			for _,vehicle in ipairs(xmlNodeGetChildren(group)) do&lt;br /&gt;
				-- add a new row to the gridlist&lt;br /&gt;
				row = guiGridListAddRow(gridlistVehicleSelection)&lt;br /&gt;
&lt;br /&gt;
				-- get the vehicle name and id&lt;br /&gt;
				name = xmlNodeGetAttribute(vehicle,&amp;quot;name&amp;quot;)&lt;br /&gt;
				local id = xmlNodeGetAttribute(vehicle,&amp;quot;id&amp;quot;)&lt;br /&gt;
				&lt;br /&gt;
				-- set the text in the first column to the vehicle name&lt;br /&gt;
				guiGridListSetItemText(gridlistVehicleSelection,row,1,name,false,false)&lt;br /&gt;
				-- set the text in the second column to the vehicle type&lt;br /&gt;
				guiGridListSetItemText(gridlistVehicleSelection,row,2,getVehicleType(tonumber(id)),false,false)		&lt;br /&gt;
				&lt;br /&gt;
				-- finally, set the vehicle id as data so we can access it later&lt;br /&gt;
				guiGridListSetItemData(gridlistVehicleSelection,row,1,tostring(id))&lt;br /&gt;
			end&lt;br /&gt;
		end	&lt;br /&gt;
	&lt;br /&gt;
		-- unload the xml file now that we are finished&lt;br /&gt;
		xmlUnloadFile(rootnode)&lt;br /&gt;
	end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Note the use of for loops in the code with [[xmlNodeGetChildren]]. This saves us a lot of time and effort as we do not have to manually code each group and vehicle into the list.&lt;br /&gt;
&lt;br /&gt;
You should now have a fully working vehicle selection menu, reading all of its data from a clientside xml file.&lt;br /&gt;
Next, we will examine how to generate the appearance of collapsing and expanding sections in a gridlist.&lt;br /&gt;
&lt;br /&gt;
===Collapsing/Expanding the Gridlist===&lt;br /&gt;
Allowing sections of the gridlist to be collapsed or expanded gives much more control over the visible content to the user.&lt;br /&gt;
This frees up space on the screen and makes the whole menu much more comfortable to use.&lt;br /&gt;
&lt;br /&gt;
===Loading the data===&lt;br /&gt;
To be able to achieve this effect (as it is not a natural feature of gridlists) we will need to load the vehicle information into a table (from the xml file), rather than directly including it all in the gridlist.&lt;br /&gt;
'''If you are following on from a previous section of this tutorial, this new code will replace what is inside your existing 'populateGridlist' function.'''&lt;br /&gt;
&lt;br /&gt;
This works in much the same way the previous xml loading example does, only this time instead of saving the data into the gridlist, we save it into a table entry instead.&lt;br /&gt;
We also set the custom data &amp;quot;header&amp;quot; on the gridlist slots to denote which gridlist entries are our &amp;quot;group&amp;quot; entries and which are vehicles.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
function populateGridlist()&lt;br /&gt;
	local rootnode = xmlLoadFile(&amp;quot;vehicles.xml&amp;quot;)&lt;br /&gt;
	&lt;br /&gt;
	-- create a blank global table to store our imported data&lt;br /&gt;
	vehicleTable = {}&lt;br /&gt;
	&lt;br /&gt;
	if rootnode then		&lt;br /&gt;
		for _,group in ipairs(xmlNodeGetChildren(rootnode)) do&lt;br /&gt;
			-- create an entry in the gridlist for every vehicle &amp;quot;group&amp;quot;&lt;br /&gt;
			local row = guiGridListAddRow(gridlistVehicleSelection)&lt;br /&gt;
&lt;br /&gt;
			local name = xmlNodeGetAttribute(group,&amp;quot;type&amp;quot;)&lt;br /&gt;
			&lt;br /&gt;
			guiGridListSetItemText(gridlistVehicleSelection,row,1,name,false,false)	&lt;br /&gt;
&lt;br /&gt;
			-- add an entry containing the group name into the table&lt;br /&gt;
			vehicleTable[name] = {}&lt;br /&gt;
			&lt;br /&gt;
			-- we will use the custom data &amp;quot;header&amp;quot; to indicate that this entry can be expanded/collapsed&lt;br /&gt;
			guiGridListSetItemData(gridlistVehicleSelection,row,1,&amp;quot;header&amp;quot;)	&lt;br /&gt;
		&lt;br /&gt;
			-- then, for every group that we find, loop all of its children (the vehicle nodes) and store them in a table&lt;br /&gt;
			for _,vehicle in ipairs(xmlNodeGetChildren(group)) do&lt;br /&gt;
				local vname = xmlNodeGetAttribute(vehicle,&amp;quot;name&amp;quot;)&lt;br /&gt;
				local id = xmlNodeGetAttribute(vehicle,&amp;quot;id&amp;quot;)			&lt;br /&gt;
			&lt;br /&gt;
				-- insert both the vehicle id and the vehicle description into the table&lt;br /&gt;
				table.insert(vehicleTable[name],{id,vname})&lt;br /&gt;
			end&lt;br /&gt;
		end	&lt;br /&gt;
	&lt;br /&gt;
		-- set element data on the gridlist so we know which group is currently showing&lt;br /&gt;
		setElementData(gridlistVehicleSelection,&amp;quot;expanded&amp;quot;,&amp;quot;none&amp;quot;)&lt;br /&gt;
	&lt;br /&gt;
		-- unload the xml file now that we are finished&lt;br /&gt;
		xmlUnloadFile(rootnode)&lt;br /&gt;
	end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Now that we have all the data stored, we can quickly manipulate it when neccessary.&lt;br /&gt;
&lt;br /&gt;
===Managing the double click===&lt;br /&gt;
To enable the player to simply double click on a group name to expand/collapse it we need to use the [[onClientGUIDoubleClick]] event.&lt;br /&gt;
If we attach it to the gridlist, we can then catch any double clicks on the group names in it:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
-- attach the onClientGUIDoubleClick event to the gridlist and set it to call processDoubleClick&lt;br /&gt;
addEventHandler(&amp;quot;onClientGUIDoubleClick&amp;quot;,gridlistVehicleSelection,processDoubleClick,false)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Add this line of code in your createVehicleSelection, after the gridlist has been created.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
As the gridlist items are not separate GUI elements, we must capture all clicks from anywhere on the gridlist then process them to filter out the ones we do not want.&lt;br /&gt;
This can be done by checking if an item is selected, then checking if the item is one of our &amp;quot;group&amp;quot; values (using our previously mentioned &amp;quot;header&amp;quot; data):&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
function processDoubleClick(button,state)&lt;br /&gt;
	if button == &amp;quot;left&amp;quot; and state == &amp;quot;up&amp;quot; then&lt;br /&gt;
		local row,col = guiGridListGetSelectedItem(gridlistVehicleSelection)&lt;br /&gt;
		&lt;br /&gt;
		-- if something in the gridlist has been selected&lt;br /&gt;
		if row and col and row ~= -1 and col ~= -1 then		&lt;br /&gt;
			-- if it is a header&lt;br /&gt;
			if guiGridListGetItemData(gridlistVehicleSelection,row,col) == &amp;quot;header&amp;quot; then&lt;br /&gt;
				local selected = guiGridListGetItemText(gridlistVehicleSelection,row,col)&lt;br /&gt;
				&lt;br /&gt;
				-- call the function to collapse or expand the menu and pass which section it is as an argument&lt;br /&gt;
				changeGridlistState(selected)&lt;br /&gt;
			end&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Once we have narrowed down the double clicks to only those done on our group headers, we can expand/collapse them appropriately.&lt;br /&gt;
This can be done by simply setting new text values in the gridlist according to the newly expanded/collapsed group, which creates the convincing illusion of collapsable menus.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Note that much of the following code is reused from previous areas of this tutorial. While it is generally bad practice to clone sections of code in this way, for the purposes of this example it is far easier to understand.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
function changeGridlistState(group)&lt;br /&gt;
	if group then&lt;br /&gt;
		-- if the group is already expanded, we want to collapse it&lt;br /&gt;
		if getElementData(gridlistVehicleSelection,&amp;quot;expanded&amp;quot;) == group then&lt;br /&gt;
			-- first, we clear all previous data from the gridlist&lt;br /&gt;
			guiGridListClear(gridlistVehicleSelection)&lt;br /&gt;
			&lt;br /&gt;
			-- now, loop all the group entries in the vehicle table that we created earlier&lt;br /&gt;
			for group,_ in pairs(vehicleTable) do&lt;br /&gt;
				-- add each group to the list and mark them with &amp;quot;header&amp;quot;			&lt;br /&gt;
				local row = guiGridListAddRow(gridlistVehicleSelection)&lt;br /&gt;
				&lt;br /&gt;
				guiGridListSetItemText(gridlistVehicleSelection,row,1,group,false,false)	&lt;br /&gt;
				guiGridListSetItemData(gridlistVehicleSelection,row,1,&amp;quot;header&amp;quot;)	&lt;br /&gt;
			end&lt;br /&gt;
			&lt;br /&gt;
			-- update the data to indicate that no groups are currently expanded&lt;br /&gt;
			setElementData(gridlistVehicleSelection,&amp;quot;expanded&amp;quot;,&amp;quot;none&amp;quot;)&lt;br /&gt;
			&lt;br /&gt;
		-- otherwise, we want to expand it&lt;br /&gt;
		else&lt;br /&gt;
			guiGridListClear(gridlistVehicleSelection)&lt;br /&gt;
			&lt;br /&gt;
			local row = guiGridListAddRow(gridlistVehicleSelection)&lt;br /&gt;
			&lt;br /&gt;
			guiGridListSetItemText(gridlistVehicleSelection,row,1,group,false,false)	&lt;br /&gt;
			guiGridListSetItemData(gridlistVehicleSelection,row,1,&amp;quot;header&amp;quot;)				&lt;br /&gt;
			&lt;br /&gt;
			-- loop every vehicle in the specified groups table&lt;br /&gt;
			for _,vehicle in ipairs(vehicleTable[group]) do&lt;br /&gt;
				-- add them to the gridlist and set the vehicle id as data&lt;br /&gt;
				row = guiGridListAddRow(gridlistVehicleSelection)&lt;br /&gt;
			&lt;br /&gt;
				-- format a &amp;quot;-&amp;quot; into the string to make it visually easier to distinguish between groups and vehicles&lt;br /&gt;
				guiGridListSetItemText(gridlistVehicleSelection,row,1,&amp;quot;- &amp;quot;..vehicle[2],false,false)	&lt;br /&gt;
				guiGridListSetItemText(gridlistVehicleSelection,row,2,getVehicleType(tonumber(vehicle[1])),false,false)	&lt;br /&gt;
											&lt;br /&gt;
				guiGridListSetItemData(gridlistVehicleSelection,row,1,tostring(vehicle[1]))&lt;br /&gt;
			end	&lt;br /&gt;
&lt;br /&gt;
			-- update the data to indicate which group is currently expanded&lt;br /&gt;
			setElementData(gridlistVehicleSelection,&amp;quot;expanded&amp;quot;,group)			&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This comletes the second section of the tutorial.&lt;br /&gt;
&lt;br /&gt;
For further GUI tutorials, see [[Scripting the GUI - Tutorial 2|Tutorial 2 (Gates and Keypads)]]&lt;br /&gt;
&lt;br /&gt;
[[Category:GUI_Tutorials]]&lt;/div&gt;</summary>
		<author><name>R3mp</name></author>
	</entry>
	<entry>
		<id>https://wiki.multitheftauto.com/index.php?title=Introduction_to_Scripting_the_GUI_-_Part_3&amp;diff=22258</id>
		<title>Introduction to Scripting the GUI - Part 3</title>
		<link rel="alternate" type="text/html" href="https://wiki.multitheftauto.com/index.php?title=Introduction_to_Scripting_the_GUI_-_Part_3&amp;diff=22258"/>
		<updated>2010-01-08T01:53:21Z</updated>

		<summary type="html">&lt;p&gt;R3mp: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;'''Introduction to Scripting the GUI - Part 3 (Teleport Window)'''&lt;br /&gt;
&lt;br /&gt;
In this tutorial we will make a simple city teleport window, with 3 buttons (one for each city) that when clicked will teleport you to that city.&lt;br /&gt;
&lt;br /&gt;
'''Note that this tutorial builds on content covered in the [[Introduction to Scripting the GUI|GUI Scripting Introduction]].'''&lt;br /&gt;
&lt;br /&gt;
[[Image:Gui_teleport_tutorial.PNG|thumb|GUI Teleport Window]]&lt;br /&gt;
&lt;br /&gt;
==Making the GUI==&lt;br /&gt;
&lt;br /&gt;
===Getting set up===&lt;br /&gt;
The first thing we need to do is create our GUI elements.&lt;br /&gt;
For this tutorial we will be using one [[Element/GUI/Window|window]], three [[Element/GUI/Button|buttons]] and one [[Element/GUI/Text_label|label]].&lt;br /&gt;
We will be using '''absolute''' position values.&lt;br /&gt;
&lt;br /&gt;
As noted in [[:Category:GUI_Tutorials|Previous tutorials]], all the GUI must be made client side. &lt;br /&gt;
&lt;br /&gt;
If you are following on from that tutorial, open up your gui.lua file to work with.&lt;br /&gt;
&lt;br /&gt;
If you are not, browse to /Your MTA Server/mods/deathmatch/resources/myserver/ directory, and create a folder named &amp;quot;client&amp;quot;. &lt;br /&gt;
Under /client/ directory, create a text file and name it &amp;quot;gui.lua&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
If you have not already done so, do not forget to include the new gui.lua file in the meta.xml of the main resource, and label it as a client script:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;xml&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;script src=&amp;quot;client/gui.lua&amp;quot; type=&amp;quot;client&amp;quot; /&amp;gt;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Making the window===&lt;br /&gt;
In this file we will now write a funtion that creates the window.&lt;br /&gt;
To create a window we will use [[guiCreateWindow]]:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
-- create the function that will hold our gui creation code&lt;br /&gt;
function createTeleportWindow()&lt;br /&gt;
	-- get the screen width and height&lt;br /&gt;
	local sWidth, sHeight = guiGetScreenSize()&lt;br /&gt;
 &lt;br /&gt;
	-- create the window, using some maths to find the centre of the screen&lt;br /&gt;
	local Width,Height = 231,188&lt;br /&gt;
	local X = (sWidth/2) - (Width/2)&lt;br /&gt;
	local Y = (sHeight/2) - (Height/2)&lt;br /&gt;
 &lt;br /&gt;
	-- create the window&lt;br /&gt;
	teleportWindow = guiCreateWindow(X,Y,Width,Height,&amp;quot;City Teleporter&amp;quot;,false)&lt;br /&gt;
 &lt;br /&gt;
	-- stop players from being able to resize the window&lt;br /&gt;
	guiWindowSetSizable(teleportWindow,false)&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
This will create a basic window in the centre of the screen that cannot be resized, with the title &amp;quot;City Teleporter&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
===Making the label===&lt;br /&gt;
Next, we will add the label describing what the buttons do.&lt;br /&gt;
To create a label we will use [[guiCreateLabel]]:&lt;br /&gt;
&lt;br /&gt;
'''Note that we are now writing more code for our existing 'createTeleportWindow' function. This is not a new function and is meant to replace what you already have.'''&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
function createTeleportWindow()&lt;br /&gt;
	local sWidth, sHeight = guiGetScreenSize()&lt;br /&gt;
 &lt;br /&gt;
	local Width,Height = 231,188&lt;br /&gt;
	local X = (sWidth/2) - (Width/2)&lt;br /&gt;
	local Y = (sHeight/2) - (Height/2)&lt;br /&gt;
 &lt;br /&gt;
	teleportWindow = guiCreateWindow(X,Y,Width,Height,&amp;quot;City Teleporter&amp;quot;,false)&lt;br /&gt;
 &lt;br /&gt;
	guiWindowSetSizable(teleportWindow,false)&lt;br /&gt;
	&lt;br /&gt;
	-- create a label with our instructions on&lt;br /&gt;
	teleportLabel = guiCreateLabel(18,23,191,33,&amp;quot;Click a button to teleport to that location&amp;quot;,false,teleportWindow)&lt;br /&gt;
	&lt;br /&gt;
	-- set the horizontal alignment of the label to center (ie: in the middle of the window)&lt;br /&gt;
	-- also note the final argument &amp;quot;true&amp;quot; &lt;br /&gt;
	-- this turns on wordwrap so if your text goes over the edge of the label, it will wrap around and start a new line automatically&lt;br /&gt;
	guiLabelSetHorizontalAlign(teleportLabel,&amp;quot;center&amp;quot;,true)	&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
You will now have a simple window with some centered instructions at the top.&lt;br /&gt;
&lt;br /&gt;
===Making the buttons===&lt;br /&gt;
Now we need to add the city teleport buttons.&lt;br /&gt;
To create a button we will use [[guiCreateButton]]:&lt;br /&gt;
&lt;br /&gt;
'''Note that we are now writing more code for our existing 'createTeleportWindow' function. This is not a new function and is meant to replace what you already have.'''&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
function createTeleportWindow()&lt;br /&gt;
	local sWidth, sHeight = guiGetScreenSize()&lt;br /&gt;
 &lt;br /&gt;
	local Width,Height = 231,188&lt;br /&gt;
	local X = (sWidth/2) - (Width/2)&lt;br /&gt;
	local Y = (sHeight/2) - (Height/2)&lt;br /&gt;
 &lt;br /&gt;
	teleportWindow = guiCreateWindow(X,Y,Width,Height,&amp;quot;City Teleporter&amp;quot;,false)&lt;br /&gt;
 &lt;br /&gt;
	guiWindowSetSizable(teleportWindow,false)&lt;br /&gt;
	&lt;br /&gt;
	teleportLabel = guiCreateLabel(18,23,191,33,&amp;quot;Click a button to teleport to that location&amp;quot;,false,teleportWindow)&lt;br /&gt;
	&lt;br /&gt;
	guiLabelSetHorizontalAlign(teleportLabel,&amp;quot;center&amp;quot;,true)	&lt;br /&gt;
	&lt;br /&gt;
	-- create the button for teleporting to Los Santos&lt;br /&gt;
	teleportButtonLS = guiCreateButton(18,63,195,35,&amp;quot;Los Santos&amp;quot;,false,teleportWindow)&lt;br /&gt;
	&lt;br /&gt;
	-- slightly below that, create another button for teleporting to San Fierro&lt;br /&gt;
	teleportButtonSF = guiCreateButton(18,103,195,35,&amp;quot;San Fierro&amp;quot;,false,teleportWindow)&lt;br /&gt;
	&lt;br /&gt;
	-- slightly below that again, create another button for teleport to Las Venturas&lt;br /&gt;
	teleportButtonLV = guiCreateButton(18,143,195,35,&amp;quot;Las Venturas&amp;quot;,false,teleportWindow)	&lt;br /&gt;
	&lt;br /&gt;
	-- hide the gui&lt;br /&gt;
	guiSetVisible(teleportWindow,false)&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Using the function we wrote===&lt;br /&gt;
Now our 'createTeleportWindow' function is ready, but it wont do anything until we call it.&lt;br /&gt;
It is recommended to create all GUI when the client resource starts, hide them, and show them to the player later when needed. &lt;br /&gt;
&lt;br /&gt;
Therefore, we'll write an event handler for [[onClientResourceStart]] to create the window:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
-- add our event handler, using the root element of the resource&lt;br /&gt;
-- this means it will only trigger when its own resource is started&lt;br /&gt;
addEventHandler(&amp;quot;onClientResourceStart&amp;quot;, getResourceRootElement(getThisResource()), &lt;br /&gt;
	function ()&lt;br /&gt;
		-- call the createTeleportWindow function to create our gui&lt;br /&gt;
		createTeleportWindow()&lt;br /&gt;
	end&lt;br /&gt;
)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Now that we have our GUI created, we need a way for the players to open the window.&lt;br /&gt;
&lt;br /&gt;
===Opening the GUI===&lt;br /&gt;
There are several ways this could be done, depending on your personal preference or the particulars of the situation.&lt;br /&gt;
For this tutorial, we will use a simple [[addCommandHandler|command]].&lt;br /&gt;
&lt;br /&gt;
To open the GUI, we will use the command /teleportme :&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
-- create our function&lt;br /&gt;
function openTeleportWindow()&lt;br /&gt;
	-- show the window&lt;br /&gt;
	guiSetVisible(teleportWindow,true)&lt;br /&gt;
		&lt;br /&gt;
	-- show the mouse cursor&lt;br /&gt;
	showCursor(true,true)&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
-- define the command /teleportme to call the openTeleportWindow function&lt;br /&gt;
addCommandHandler(&amp;quot;teleportme&amp;quot;,openTeleportWindow)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Next, we need to make the buttons actually teleport the player.&lt;br /&gt;
&lt;br /&gt;
==Scripting the button==&lt;br /&gt;
&lt;br /&gt;
Now that we have created our GUI and the players are able to open it, we need to make it work. &lt;br /&gt;
&lt;br /&gt;
===Detecting the click===&lt;br /&gt;
As described in previous tutorials, when the player clicks on any part of the GUI, the event &amp;quot;onClientGUIClick&amp;quot; will be triggered for the GUI component you clicked on. &lt;br /&gt;
With that in mind, we will attach an event handler to each of our 3 teleport buttons: &lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
-- attach the event onClientGUIClick to teleportButtonLS and set it to trigger the 'teleportPlayer' function&lt;br /&gt;
addEventHandler(&amp;quot;onClientGUIClick&amp;quot;, teleportButtonLS, teleportPlayer, false)&lt;br /&gt;
&lt;br /&gt;
-- attach the event onClientGUIClick to teleportButtonSF and set it to trigger the 'teleportPlayer' function&lt;br /&gt;
addEventHandler(&amp;quot;onClientGUIClick&amp;quot;, teleportButtonSF, teleportPlayer, false)&lt;br /&gt;
&lt;br /&gt;
-- attach the event onClientGUIClick to teleportButtonLV and set it to trigger the 'teleportPlayer' function&lt;br /&gt;
addEventHandler(&amp;quot;onClientGUIClick&amp;quot;, teleportButtonLV, teleportPlayer, false)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Put this code into your 'createTeleportWindow' function, '''after''' the buttons have been created.&lt;br /&gt;
&lt;br /&gt;
Note how we have set all 3 buttons to trigger the 'teleportPlayer' function.&lt;br /&gt;
&lt;br /&gt;
This allows us to easily expand our code later on (for example, to add more teleport locations) with a simple if statement in the function.&lt;br /&gt;
&lt;br /&gt;
===Managing the clicks===&lt;br /&gt;
Now that we can detect clicks on all our buttons, we need to manage what happens when we do.&lt;br /&gt;
&lt;br /&gt;
As we just noted, we will do this using the 'teleportPlayer' function.&lt;br /&gt;
We will use if statements to check which button has been clicked, then trigger a custom server event with the specified teleport coordinates to move the player:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
-- create our function, and add button and state parameters (these are passed automatically with onClickGUIClick)&lt;br /&gt;
function teleportPlayer(button,state)&lt;br /&gt;
	-- if our button was clicked with the left mouse button, and the state of the mouse button is up&lt;br /&gt;
	if button == &amp;quot;left&amp;quot; and state == &amp;quot;up&amp;quot; then&lt;br /&gt;
		-- if the player clicked on the LS teleport button&lt;br /&gt;
		if source == teleportButtonLS then&lt;br /&gt;
		&lt;br /&gt;
			-- trigger the server with our Los Santos coordinates&lt;br /&gt;
			triggerServerEvent(&amp;quot;movePlayerToPosition&amp;quot;,getLocalPlayer(),1479.6,-1612.8,14.0,0)&lt;br /&gt;
			&lt;br /&gt;
			-- output a message to the player&lt;br /&gt;
			outputChatBox(&amp;quot;Welcome to Los Santos!&amp;quot;)&lt;br /&gt;
			&lt;br /&gt;
		-- otherwise, if the player clicked on the SF teleport button&lt;br /&gt;
		elseif source == teleportButtonSF then&lt;br /&gt;
		&lt;br /&gt;
			-- trigger the server with our San Fierro coordinates&lt;br /&gt;
			triggerServerEvent(&amp;quot;movePlayerToPosition&amp;quot;,getLocalPlayer(),-2265.5,534.0,35.0,270)&lt;br /&gt;
&lt;br /&gt;
			-- output a message to the player&lt;br /&gt;
			outputChatBox(&amp;quot;Welcome to San Fierro!&amp;quot;)&lt;br /&gt;
			&lt;br /&gt;
		-- otherwise, if the player clicked on the LV teleport button&lt;br /&gt;
		elseif source == teleportButtonLV then&lt;br /&gt;
		&lt;br /&gt;
			-- trigger the server with our Las Venturas coordinates&lt;br /&gt;
			triggerServerEvent(&amp;quot;movePlayerToPosition&amp;quot;,getLocalPlayer(),2036.9,1545.2,10.8,270)&lt;br /&gt;
&lt;br /&gt;
			-- output a message to the player&lt;br /&gt;
			outputChatBox(&amp;quot;Welcome to Las Venturas!&amp;quot;)&lt;br /&gt;
			&lt;br /&gt;
		end&lt;br /&gt;
		&lt;br /&gt;
		-- hide the window and all the components&lt;br /&gt;
		guiSetVisible(teleportWindow, false)&lt;br /&gt;
		&lt;br /&gt;
		-- hide the mouse cursor&lt;br /&gt;
		showCursor(false)		&lt;br /&gt;
	end	&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
If you wanted to add more locations, you could simply add a new button to your GUI and check for it in this function using another if statement.&lt;br /&gt;
For example:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
function teleportPlayer(button,state)&lt;br /&gt;
	if button == &amp;quot;left&amp;quot; and state == &amp;quot;up&amp;quot; then&lt;br /&gt;
		...&lt;br /&gt;
		&lt;br /&gt;
		elseif source == yourNewButton then&lt;br /&gt;
			triggerServerEvent(&amp;quot;movePlayerToPosition&amp;quot;,getLocalPlayer(),xCoord,yCoord,zCoord,rotation)&lt;br /&gt;
		end&lt;br /&gt;
		...&lt;br /&gt;
	end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Creating the serverside event===&lt;br /&gt;
At this point we now have all the code needed on the client side, &lt;br /&gt;
so open up your serverside 'script.lua' file (from the [[Scripting Introduction|Introduction to Scripting]]) or another suitable serverside file to work with.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
On the clientside, we are triggering the server event &amp;quot;movePlayerToPosition&amp;quot;. So, we will first define that event.&lt;br /&gt;
To do that we will use [[addEvent]], then [[addEventHandler]]:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
-- create our function, with the x,y and z values we passed from the client&lt;br /&gt;
function moveThePlayer(x,y,z)&lt;br /&gt;
&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
-- define our custom event, and allow it to be triggered from the client ('true')&lt;br /&gt;
addEvent(&amp;quot;movePlayerToPosition&amp;quot;,true)&lt;br /&gt;
-- add an event handler so that when movePlayerToPosition is triggered, the function moveThePlayer is called&lt;br /&gt;
addEventHandler(&amp;quot;movePlayerToPosition&amp;quot;,root,moveThePlayer)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Moving the player===&lt;br /&gt;
Now all that is left is to move the player to their new position.&lt;br /&gt;
&lt;br /&gt;
'''Note that we are now writing more code for our existing 'moveThePlayer' function. This is not a new function and is meant to replace what you already have.'''&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
-- create our function, with the x,y and z values we passed from the client&lt;br /&gt;
function moveThePlayer(x,y,z,rotation)&lt;br /&gt;
	-- check we have a position and rotation&lt;br /&gt;
	if x and y and z and rotation then&lt;br /&gt;
		-- get the players current skin, so we can spawn them again without losing it&lt;br /&gt;
		local skin = getElementModel(client)&lt;br /&gt;
		&lt;br /&gt;
		-- spawn the player&lt;br /&gt;
		spawnPlayer(client,x,y,z,rotation,skin)&lt;br /&gt;
		&lt;br /&gt;
		-- make sure the players camera is on his character&lt;br /&gt;
		setCameraTarget(client,client)&lt;br /&gt;
	end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Note the use of [[spawnPlayer]] rather than, for example, [[setElementPosition]].&lt;br /&gt;
Using [[spawnPlayer]] has several advantages, such as being able to set the position when 'de-spawned' or dead, and automatically refilling health.&lt;br /&gt;
Of course, [[setElementPosition]] would work just as well to simply move them, so the choice is yours.&lt;br /&gt;
&lt;br /&gt;
Also note the use of the variable &amp;quot;client&amp;quot;, it's an internal variable used by MTA to identify the player who triggered the event.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
At this point, you should have a basic teleport window, allowing the player to teleport to any of the 3 major cities in San Andreas.&lt;br /&gt;
&lt;br /&gt;
For further help with GUI, see the [[:Category:GUI_Tutorials|GUI tutorials]].&lt;br /&gt;
&lt;br /&gt;
[[Category:GUI_Tutorials]]&lt;/div&gt;</summary>
		<author><name>R3mp</name></author>
	</entry>
	<entry>
		<id>https://wiki.multitheftauto.com/index.php?title=Introduction_to_Scripting_the_GUI&amp;diff=22257</id>
		<title>Introduction to Scripting the GUI</title>
		<link rel="alternate" type="text/html" href="https://wiki.multitheftauto.com/index.php?title=Introduction_to_Scripting_the_GUI&amp;diff=22257"/>
		<updated>2010-01-08T01:48:19Z</updated>

		<summary type="html">&lt;p&gt;R3mp: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;!-- place holder --&amp;gt;&lt;br /&gt;
One important feature in MTA:SA is the ability to script customized GUI (Graphic User Interface). The GUI consists of windows, button, edit boxes, check boxes... Almost every standard form components in graphical environments. They can be displayed while the user is in game, and used for inputs and outputs in place of traditional commands. &lt;br /&gt;
&lt;br /&gt;
[[Image:AdminGUI.png|thumb|Admin Console GUI]]&lt;br /&gt;
&lt;br /&gt;
==A tutorial to make a login window==&lt;br /&gt;
In this tutorial we'll make a simple login window, with two input boxes and a button. The window appears when the player joins the game, and once the button is clicked, the player is spawned. The tutorial will continue the gamemode we made in [[Scripting Introduction|Introduction to Scripting]] ''(If you have used the [[Scripting Introduction|Introduction to Scripting]], you will need to remove or comment the [[spawnPlayer]] line in the &amp;quot;joinHandler&amp;quot; function in your code, as we will be replacing it with a gui alternative in this tutorial)''. We'll also take a look at client-side scripting. &lt;br /&gt;
&lt;br /&gt;
===Draw the window===&lt;br /&gt;
All the GUI must be made client side. It is also a good practice to keep all the client scripts in a separate folder. &lt;br /&gt;
&lt;br /&gt;
Browse to /Your MTA Server/mods/deathmatch/resources/myserver/ directory, and create a folder named &amp;quot;client&amp;quot;. Under /client/ directory, create a text file and name it &amp;quot;gui.lua&amp;quot;. &lt;br /&gt;
&lt;br /&gt;
In this file we will write a funtion that draws the window. To create a window we will use [[guiCreateWindow]]:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
function createLoginWindow()&lt;br /&gt;
	-- define the X and Y positions of the window&lt;br /&gt;
	local X = 0.375&lt;br /&gt;
	local Y = 0.375&lt;br /&gt;
	-- define the width and height of the window&lt;br /&gt;
	local Width = 0.25&lt;br /&gt;
	local Height = 0.25&lt;br /&gt;
	-- create the window and save its element value into the variable 'wdwLogin'&lt;br /&gt;
	-- click on the function's name to read its documentation&lt;br /&gt;
	wdwLogin = guiCreateWindow(X, Y, Width, Height, &amp;quot;Please Log In&amp;quot;, true)&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Relative and Absolute===&lt;br /&gt;
Note that the final argument passed to guiCreateWindow in the above example is ''true''. This indicates that the coordinates and dimensions of the window are '''relative''', meaning they are a ''percentage'' of the total screen size. This means that if the far left side of the screen is 0, and the far right is 1, an X position of 0.5 would represent the centre point of the screen. Similarly, if the top of the screen is 0 and the bottom is 1, a Y position of 0.2 would be 20% of the way down the screen. The same principles apply to both Width and Height as well (with a Width value of 0.5 meaning the window will be half as wide as the screen).&lt;br /&gt;
&lt;br /&gt;
The alternative to using relative values is using '''absolute''' (by passing ''false'' instead of true to guiCreateWindow). Absolute values are calculated as the total number of pixels from the top-left corner of the parent (if no gui element parent is specified, the parent is the screen itself). If we assume a screen resolution of 1920x1200, the far left side of the screen being 0 pixels and the far right being 1920 pixels, an X position of 960 will represent the centre point of the screen. Similarly, if the top of the screen is 0 pixels and the bottom is 1200, a Y position of 20 would be 20 pixels down from the top of the screen. The same principles apple to both Width and Height as well (with a Width value of 50 meaning the window will be 50 pixels wide). ''You can use [[guiGetScreenSize]] and a little maths to calculate certain absolute positions.''&lt;br /&gt;
&lt;br /&gt;
The differences between using relative and absolute values is quite simple; gui created using absolute values will always remain exactly the same pixel size and position, while gui created using relative values will always be a percentage of its parent's size.&lt;br /&gt;
&lt;br /&gt;
Absolute is generally easier to maintain when editing code by hand, however your choice of type depends on the situation you are using it for.&lt;br /&gt;
&lt;br /&gt;
For the purposes of this introduction we will be using relative values.&lt;br /&gt;
&lt;br /&gt;
===Adding the components===&lt;br /&gt;
Next, we'll add the text labels (saying &amp;quot;username:&amp;quot; and &amp;quot;password:&amp;quot;), edit boxes (for entering your data) and a button to log in.&lt;br /&gt;
&lt;br /&gt;
To create buttons we use [[guiCreateButton]] and to create edit boxes use [[guiCreateEdit]]: &lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
function createLoginWindow()&lt;br /&gt;
	local X = 0.375&lt;br /&gt;
	local Y = 0.375&lt;br /&gt;
	local Width = 0.25&lt;br /&gt;
	local Height = 0.25&lt;br /&gt;
	wdwLogin = guiCreateWindow(X, Y, Width, Height, &amp;quot;Please Log In&amp;quot;, true)&lt;br /&gt;
	&lt;br /&gt;
	-- define new X and Y positions for the first label&lt;br /&gt;
	X = 0.0825&lt;br /&gt;
	Y = 0.2&lt;br /&gt;
	-- define new Width and Height values for the first label&lt;br /&gt;
	Width = 0.25&lt;br /&gt;
	Height = 0.25&lt;br /&gt;
	-- create the first label, note the final argument passed is 'wdwLogin' meaning the window&lt;br /&gt;
	-- we created above is the parent of this label (so all the position and size values are now relative to the position of that window)&lt;br /&gt;
	guiCreateLabel(X, Y, Width, Height, &amp;quot;Username&amp;quot;, true, wdwLogin)&lt;br /&gt;
	-- alter the Y value, so the second label is slightly below the first&lt;br /&gt;
	Y = 0.5&lt;br /&gt;
	guiCreateLabel(X, Y, Width, Height, &amp;quot;Password&amp;quot;, true, wdwLogin)&lt;br /&gt;
	&lt;br /&gt;
&lt;br /&gt;
	X = 0.415&lt;br /&gt;
	Y = 0.2&lt;br /&gt;
	Width = 0.5&lt;br /&gt;
	Height = 0.15&lt;br /&gt;
	edtUser = guiCreateEdit(X, Y, Width, Height, &amp;quot;&amp;quot;, true, wdwLogin)&lt;br /&gt;
	Y = 0.5&lt;br /&gt;
	edtPass = guiCreateEdit(X, Y, Width, Height, &amp;quot;&amp;quot;, true, wdwLogin)&lt;br /&gt;
	-- set the maximum character length for the username and password fields to 50&lt;br /&gt;
	guiEditSetMaxLength(edtUser, 50)&lt;br /&gt;
	guiEditSetMaxLength(edtPass, 50)&lt;br /&gt;
	&lt;br /&gt;
	X = 0.415&lt;br /&gt;
	Y = 0.7&lt;br /&gt;
	Width = 0.25&lt;br /&gt;
	Height = 0.2&lt;br /&gt;
	btnLogin = guiCreateButton(X, Y, Width, Height, &amp;quot;Log In&amp;quot;, true, wdwLogin)&lt;br /&gt;
	&lt;br /&gt;
	-- make the window invisible&lt;br /&gt;
	guiSetVisible(wdwLogin, false)&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Note that every GUI component created is a child of the window, this is done by specifying the parent element (wdwLogin, in this case) when creating the component. &lt;br /&gt;
&lt;br /&gt;
This is very useful because not only does it mean that all the components are attached to the window and will move with it, but also that any changes done to the parent window will be applied down the tree to these child components. For example, we can now hide all of the GUI we just created by simply hiding the window:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
guiSetVisible(wdwLogin, false) --hides all the GUI we made so we can show them to the player at the appropriate moment. &lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Using the function we wrote===&lt;br /&gt;
The createLoginWindow function is now complete, but it won't do anything until we call it. It is recommended to create all GUI when the client resource starts, hide them, and show them to the player later when needed. Therefore, we'll write an event handler for &amp;quot;[[onClientResourceStart]]&amp;quot; to create the window:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
-- attach the event handler to the root element of the resource&lt;br /&gt;
-- this means it will only trigger when its own resource is started&lt;br /&gt;
addEventHandler(&amp;quot;onClientResourceStart&amp;quot;, getResourceRootElement(getThisResource()), &lt;br /&gt;
	function ()&lt;br /&gt;
		createLoginWindow()&lt;br /&gt;
	end&lt;br /&gt;
)	&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
As this is a log in window, we now need to show the window when the player joins the game. &lt;br /&gt;
This can be done using the same event, &amp;quot;[[onClientResourceStart]]&amp;quot;, so we can modify the above code to include showing the window:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
addEventHandler(&amp;quot;onClientResourceStart&amp;quot;, getResourceRootElement(getThisResource()), &lt;br /&gt;
	function ()&lt;br /&gt;
		-- create the log in window and its components&lt;br /&gt;
		createLoginWindow()&lt;br /&gt;
&lt;br /&gt;
		-- output a brief welcome message to the player&lt;br /&gt;
                outputChatBox(&amp;quot;Welcome to My MTA:SA Server, please log in.&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
		-- if the GUI was successfully created, then show the GUI to the player&lt;br /&gt;
	        if (wdwLogin ~= nil) then&lt;br /&gt;
			guiSetVisible(wdwLogin, true)&lt;br /&gt;
		else&lt;br /&gt;
			-- if the GUI hasnt been properly created, tell the player&lt;br /&gt;
			outputChatBox(&amp;quot;An unexpected error has occurred and the log in GUI has not been created.&amp;quot;)&lt;br /&gt;
	        end &lt;br /&gt;
&lt;br /&gt;
		-- enable the players cursor (so they can select and click on the components)&lt;br /&gt;
	        showCursor(true)&lt;br /&gt;
		-- set the input focus onto the GUI, allowing players (for example) to press 'T' without the chatbox opening&lt;br /&gt;
	        guiSetInputEnabled(true)&lt;br /&gt;
	end&lt;br /&gt;
)	&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Note that we have a simple security check before making the window visible, so in the unlikely event that the window has not been created, meaning wdwLogin is not a valid element, we don't get an error and just inform the player what has happened. &lt;br /&gt;
In the next step, we will create the button functionality for the log in button.&lt;br /&gt;
&lt;br /&gt;
==Scripting the button==&lt;br /&gt;
Now that we have created our GUI and shown it to the player, we need to make it work. &lt;br /&gt;
&lt;br /&gt;
===Detecting the click===&lt;br /&gt;
When the player clicks on any part of the GUI, the event &amp;quot;[[onClientGUIClick]]&amp;quot; will be triggered for the GUI component you clicked on. This allows us to easily detect any clicks on the GUI elements we want to use.&lt;br /&gt;
For example, we can attach the event to the btnLogin button to catch any clicks on it:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
-- attach the event onClientGUIClick to btnLogin and set it to trigger the 'clientSubmitLogin' function&lt;br /&gt;
addEventHandler(&amp;quot;onClientGUIClick&amp;quot;, btnLogin, clientSubmitLogin, false)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
'''Note the final argument passed is &amp;quot;false&amp;quot;. This indicates that the event will only trigger directly on btnLogin, not if the event has propagated up or down the tree. Setting this to &amp;quot;true&amp;quot; while attaching to gui elements will mean that clicking on any element in the same branch will trigger this event.'''&lt;br /&gt;
&lt;br /&gt;
This line of code can now be added inside the createLoginWindow function. It is a common mistake to try and attach events to non-existant GUI elements, so make sure you always attach your events '''after''' the gui element (in this case, the button) has been created:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
function createLoginWindow()&lt;br /&gt;
	-- create all our GUI elements&lt;br /&gt;
	...&lt;br /&gt;
&lt;br /&gt;
	-- now add our onClientGUIClick event to the button we just created&lt;br /&gt;
	addEventHandler(&amp;quot;onClientGUIClick&amp;quot;, btnLogin, clientSubmitLogin, false)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Managing the click===&lt;br /&gt;
Now that we can detect when the player clicks on the button, we need to write code to manage what happens when they do.&lt;br /&gt;
In our [[onClientGUIClick]] event handle, we told it to call the function clientSubmitLogin whenever btnLogin is clicked.&lt;br /&gt;
Therefore, we can now use the function clientSubmitLogin to control what happens when the button is clicked:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
-- create the function and define the 'button' and 'state' parameters&lt;br /&gt;
-- (these are passed automatically by onClientGUIClick)&lt;br /&gt;
function clientSubmitLogin(button,state)&lt;br /&gt;
	-- if our login button was clicked with the left mouse button, and the state of the mouse button is up&lt;br /&gt;
	if button == &amp;quot;left&amp;quot; and state == &amp;quot;up&amp;quot; then&lt;br /&gt;
		-- move the input focus back onto the game (allowing players to move around, open the chatbox, etc)&lt;br /&gt;
		guiSetInputEnabled(false)&lt;br /&gt;
		-- hide the window and all the components&lt;br /&gt;
		guiSetVisible(wdwLogin, false)&lt;br /&gt;
		-- hide the mouse cursor&lt;br /&gt;
		showCursor(false)&lt;br /&gt;
	end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Now, when the button is clicked, the window will be hidden and all controls will be returned to the player. Next, we will tell the server to allow the player to spawn.&lt;br /&gt;
&lt;br /&gt;
===Triggering the server===&lt;br /&gt;
Triggering the server can be done using [[triggerServerEvent]]. This allows you to trigger a specified event on the server from the client. The same can be done in reverse using [[triggerClientEvent]].&lt;br /&gt;
Here, we use the [[triggerServerEvent]] function to call our own custom event on the server, named &amp;quot;submitLogin&amp;quot;, which will then control the spawning of the player serverside.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
function clientSubmitLogin(button,state)&lt;br /&gt;
	if button == &amp;quot;left&amp;quot; and state == &amp;quot;up&amp;quot; then&lt;br /&gt;
		-- get the text entered in the 'username' field&lt;br /&gt;
		local username = guiGetText(edtUser)&lt;br /&gt;
		-- get the text entered in the 'password' field&lt;br /&gt;
		local password = guiGetText(edtPass)&lt;br /&gt;
&lt;br /&gt;
		-- if the username and password both exist&lt;br /&gt;
		if username and password then&lt;br /&gt;
			-- trigger the server event 'submitLogin' and pass the username and password to it&lt;br /&gt;
			triggerServerEvent(&amp;quot;submitLogin&amp;quot;, getRootElement(), username, password)&lt;br /&gt;
&lt;br /&gt;
			-- hide the gui, hide the cursor and return control to the player&lt;br /&gt;
			guiSetInputEnabled(false)&lt;br /&gt;
			guiSetVisible(wdwLogin, false)&lt;br /&gt;
			showCursor(false)&lt;br /&gt;
		else&lt;br /&gt;
			-- otherwise, output a message to the player, do not trigger the server&lt;br /&gt;
			-- and do not hide the gui&lt;br /&gt;
			outputChatBox(&amp;quot;Please enter a username and password.&amp;quot;)&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Creating the serverside event===&lt;br /&gt;
At this point we now have all the code needed on the client side, so open up your serverside 'script.lua' file (from the [[Scripting Introduction|Introduction to Scripting]]) or another suitable serverside file to work with.&lt;br /&gt;
&lt;br /&gt;
On the server side, recall that we are spawning the player as soon as they login.&lt;br /&gt;
So, first of all, we will need to define the custom event that we used before on the client. This can be done using [[addEvent]] and [[addEventHandler]].&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
-- create our loginHandler function, with username and password parameters (passed from the client gui)&lt;br /&gt;
function loginHandler(username,password)&lt;br /&gt;
&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
-- define our custom event, and allow it to be triggered from the client ('true')&lt;br /&gt;
addEvent(&amp;quot;submitLogin&amp;quot;,true)&lt;br /&gt;
-- add an event handler so that when submitLogin is triggered, the function loginHandler is called&lt;br /&gt;
addEventHandler(&amp;quot;submitLogin&amp;quot;,root,loginHandler)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Logging in===&lt;br /&gt;
Now we have a function that is called through the custom event 'submitLogin', we can start to work on logging in and spawning the player, using our 'loginHandler' function:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
function loginHandler(username,password)&lt;br /&gt;
	-- check that the username and password are correct&lt;br /&gt;
	if username == &amp;quot;user&amp;quot; and password == &amp;quot;apple&amp;quot; then&lt;br /&gt;
		-- the player has successfully logged in, so spawn them&lt;br /&gt;
		if (client) then&lt;br /&gt;
			spawnPlayer(client, 1959.55, -1714.46, 10)&lt;br /&gt;
			fadeCamera(client, true)&lt;br /&gt;
			outputChatBox(&amp;quot;Welcome to My Server.&amp;quot;, client)&lt;br /&gt;
		end&lt;br /&gt;
	else&lt;br /&gt;
		-- if the username or password are not correct, output a message to the player&lt;br /&gt;
		outputChatBox(&amp;quot;Invalid username and password. Please re-connect and try again.&amp;quot;,client)&lt;br /&gt;
        end			&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
addEvent(&amp;quot;submitLogin&amp;quot;,true)&lt;br /&gt;
addEventHandler(&amp;quot;submitLogin&amp;quot;,root,loginHandler)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
'''For the purposes of this tutorial, a very basic username and password system is shown. For a more comprehensive alternative, you can use the Account System or a MySQL database.'''&lt;br /&gt;
&lt;br /&gt;
Also note the use of the variable &amp;quot;client&amp;quot;, it's an internal variable used by MTA to identify the player who triggered the event. &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Finally, do not forget to include the new gui.lua file in the meta.xml of the main resource, and label it as a client script:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;xml&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;script src=&amp;quot;client/gui.lua&amp;quot; type=&amp;quot;client&amp;quot; /&amp;gt;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
At this point, we now have a basic login window that checks the player's username and password when the login button is clicked. If they are correct, the player is automatically spawned.&lt;br /&gt;
&lt;br /&gt;
For further help with GUI, see the [[:Category:GUI_Tutorials|GUI tutorials]].&lt;br /&gt;
&lt;br /&gt;
[[Category:GUI_Tutorials]]&lt;br /&gt;
[[it:Introduzione_allo_scripting_della_GUI]]&lt;br /&gt;
[[ru:Introduction to Scripting the GUI]]&lt;/div&gt;</summary>
		<author><name>R3mp</name></author>
	</entry>
	<entry>
		<id>https://wiki.multitheftauto.com/index.php?title=Introduction_to_Scripting_the_GUI_-_Part_2&amp;diff=22256</id>
		<title>Introduction to Scripting the GUI - Part 2</title>
		<link rel="alternate" type="text/html" href="https://wiki.multitheftauto.com/index.php?title=Introduction_to_Scripting_the_GUI_-_Part_2&amp;diff=22256"/>
		<updated>2010-01-08T01:45:25Z</updated>

		<summary type="html">&lt;p&gt;R3mp: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;In this tutorial we will make a simple rules window, with an accept button and a list of all the server rules &amp;amp; information.&lt;br /&gt;
&lt;br /&gt;
'''Note that this tutorial builds on content covered in the [[Introduction to Scripting the GUI|GUI Scripting Introduction]].'''&lt;br /&gt;
&lt;br /&gt;
==Making the GUI==&lt;br /&gt;
&lt;br /&gt;
===Getting set up===&lt;br /&gt;
The first thing we need to do is create our GUI elements.&lt;br /&gt;
For this tutorial we will be using one [[Element/GUI/Window|window]], one [[Element/GUI/Button|button]] and one [[Element/GUI/Text_label|label]].&lt;br /&gt;
We will be using '''absolute''' position values.&lt;br /&gt;
&lt;br /&gt;
As noted in the [[Introduction to Scripting the GUI|Previous tutorial]], all the GUI must be made client side. &lt;br /&gt;
&lt;br /&gt;
If you are following on from that tutorial, open up your gui.lua file to work with.&lt;br /&gt;
&lt;br /&gt;
If you are not, browse to /Your MTA Server/mods/deathmatch/resources/myserver/ directory, and create a folder named &amp;quot;client&amp;quot;. &lt;br /&gt;
Under /client/ directory, create a text file and name it &amp;quot;gui.lua&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
If you have not already done so, do not forget to include the new gui.lua file in the meta.xml of the main resource, and label it as a client script:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;xml&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;script src=&amp;quot;client/gui.lua&amp;quot; type=&amp;quot;client&amp;quot; /&amp;gt;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Making the window===&lt;br /&gt;
In this file we will write a funtion that draws the window:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
-- create the function that will hold our gui creation code&lt;br /&gt;
function createRulesWindow()&lt;br /&gt;
	-- get the screen width and height&lt;br /&gt;
	local sWidth, sHeight = guiGetScreenSize()&lt;br /&gt;
 &lt;br /&gt;
	-- create the window, using some maths to find the centre of the screen&lt;br /&gt;
	local Width,Height = 445,445&lt;br /&gt;
	local X = (sWidth/2) - (Width/2)&lt;br /&gt;
	local Y = (sHeight/2) - (Height/2)&lt;br /&gt;
&lt;br /&gt;
	-- create the window&lt;br /&gt;
	rulesWindow = guiCreateWindow(X,Y,Width,Height,&amp;quot;Rules&amp;quot;,false)&lt;br /&gt;
	&lt;br /&gt;
	-- stop players from being able to simply move the window out of the way&lt;br /&gt;
	guiWindowSetMovable(rulesWindow,false)&lt;br /&gt;
	&lt;br /&gt;
	-- stop players from being able to resize the window&lt;br /&gt;
	guiWindowSetSizable(rulesWindow,false)&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
This will create a basic window in the centre of the screen that cannot be moved and cannot be resized.&lt;br /&gt;
&lt;br /&gt;
===Making the button===&lt;br /&gt;
Next, we will add the button to the bottom of our window that players can click on to accept the rules:&lt;br /&gt;
&lt;br /&gt;
'''Note that we are now writing more code for our existing 'createRulesWindow' function. This is not a new function and is meant to replace what you already have.'''&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
function createRulesWindow()&lt;br /&gt;
	-- get the screen width and height&lt;br /&gt;
	local sWidth, sHeight = guiGetScreenSize()&lt;br /&gt;
 &lt;br /&gt;
	-- create the window, using some maths to find the centre of the screen&lt;br /&gt;
	local Width,Height = 445,445&lt;br /&gt;
	local X = (sWidth/2) - (Width/2)&lt;br /&gt;
	local Y = (sHeight/2) - (Height/2)&lt;br /&gt;
&lt;br /&gt;
	-- create the window and save the window gui element in a variable called 'rulesWindow'&lt;br /&gt;
	rulesWindow = guiCreateWindow(X,Y,Width,Height,&amp;quot;Rules&amp;quot;,false)&lt;br /&gt;
	&lt;br /&gt;
	-- stop players from being able to simply move the window out of the way&lt;br /&gt;
	-- note that we use our 'rulesWindow' variable to make changes to the window&lt;br /&gt;
	guiWindowSetMovable(rulesWindow,false)&lt;br /&gt;
	&lt;br /&gt;
	-- stop players from being able to resize the window&lt;br /&gt;
	guiWindowSetSizable(rulesWindow,false)&lt;br /&gt;
	&lt;br /&gt;
	-- create the button and save the button gui element in a variable called 'rulesButton'&lt;br /&gt;
	rulesButton = guiCreateButton(137,394,158,37,&amp;quot;Accept&amp;quot;,false,rulesWindow)&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Making the label===&lt;br /&gt;
Next, we will add the label to the centre of our window that our rules will be displayed on:&lt;br /&gt;
&lt;br /&gt;
'''Note that we are now writing more code for our existing 'createRulesWindow' function. This is not a new function and is meant to replace what you already have.'''&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
function createRulesWindow()&lt;br /&gt;
	-- get the screen width and height&lt;br /&gt;
	local sWidth, sHeight = guiGetScreenSize()&lt;br /&gt;
 &lt;br /&gt;
	-- create the window, using some maths to find the centre of the screen&lt;br /&gt;
	local Width,Height = 445,445&lt;br /&gt;
	local X = (sWidth/2) - (Width/2)&lt;br /&gt;
	local Y = (sHeight/2) - (Height/2)&lt;br /&gt;
&lt;br /&gt;
	-- create the window and save the window gui element in a variable called 'rulesWindow'&lt;br /&gt;
	rulesWindow = guiCreateWindow(X,Y,Width,Height,&amp;quot;Rules&amp;quot;,false)&lt;br /&gt;
	&lt;br /&gt;
	-- stop players from being able to simply move the window out of the way&lt;br /&gt;
	-- note that we use our 'rulesWindow' variable to make changes to the window&lt;br /&gt;
	guiWindowSetMovable(rulesWindow,false)&lt;br /&gt;
	&lt;br /&gt;
	-- stop players from being able to resize the window&lt;br /&gt;
	guiWindowSetSizable(rulesWindow,false)&lt;br /&gt;
	&lt;br /&gt;
	-- create the button and save the button gui element in a variable called 'rulesButton'&lt;br /&gt;
	rulesButton = guiCreateButton(137,394,158,37,&amp;quot;Accept&amp;quot;,false,rulesWindow)&lt;br /&gt;
	&lt;br /&gt;
	-- create the label and save the label gui element in a variable called 'rulesLabel'&lt;br /&gt;
	-- we set the text of the label to our rules&lt;br /&gt;
	rulesLabel = guiCreateLabel(10,25,425,359,[[&lt;br /&gt;
	Welcome to my MTA Server!&lt;br /&gt;
&lt;br /&gt;
	Please carefully read the rules before accepting.&lt;br /&gt;
&lt;br /&gt;
	By accepting the rules, you are agreeing to play by them.&lt;br /&gt;
	Anyone caught breaking these rules will be kicked and/or banned from this server.&lt;br /&gt;
&lt;br /&gt;
	If you do not accept the rules within 90 seconds, you will be kicked.&lt;br /&gt;
&lt;br /&gt;
	1: No cheating.&lt;br /&gt;
&lt;br /&gt;
	2: No bug abuse.&lt;br /&gt;
&lt;br /&gt;
	3: No mods to your game.&lt;br /&gt;
&lt;br /&gt;
	4: No flaming.&lt;br /&gt;
&lt;br /&gt;
	5: Respect other players.&lt;br /&gt;
&lt;br /&gt;
	6: Be nice!]],false,rulesWindow)&lt;br /&gt;
	&lt;br /&gt;
	-- set the horizontal alignment of the label to center (ie: in the middle of the window)&lt;br /&gt;
	-- also note the final argument &amp;quot;true&amp;quot; &lt;br /&gt;
	-- this turns on wordwrap so if your text goes over the edge of the label, it will wrap around and start a new line automatically&lt;br /&gt;
	guiLabelSetHorizontalAlign(rulesLabel,&amp;quot;center&amp;quot;,true)	&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
''Note that the text is added in a different way to usual (we are not using quotation marks, &amp;quot;&amp;quot;).''&lt;br /&gt;
&lt;br /&gt;
===Text===&lt;br /&gt;
There are ''two'' ways to define text for a label.&lt;br /&gt;
For most situations, the recommended method is to enter all your text between quotation marks:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
guiSetText(guiElement,&amp;quot;My text here&amp;quot;)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
However, when we want to have more than 1 line in our text, it becomes just as easy to use the second method. &lt;br /&gt;
It is purely dependant on situation and personal choice which method you chose.&lt;br /&gt;
For clarity's sake, i will briefly outline both here.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
When using quotation marks, we can make use of the newline character: &amp;quot;\n&amp;quot;&lt;br /&gt;
This allows us to break onto a new line in our text by entering &amp;quot;\n&amp;quot;. For example:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
guiSetText(guiElement,&amp;quot;This is line 1. \n This is line 2. \n This is line 3.&amp;quot;)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
However, if we use brackets to enclose the text instead of quotation marks, we do not need to worry about entering any extra characters.&lt;br /&gt;
We can simply type the text out as we want it to appear in the label. For example:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
guiSetText(guiElement,[[This is line 1.&lt;br /&gt;
This is line 2.&lt;br /&gt;
This is line 3.]])&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Both of these examples will create exactly the same text on the label.&lt;br /&gt;
It is entirely up to you which method you chose to use.&lt;br /&gt;
&lt;br /&gt;
===Using the function we wrote===&lt;br /&gt;
The createRulesWindow function is now complete, but it won't do anything until we call it. &lt;br /&gt;
It is recommended to create all GUI when the client resource starts, hide them, and show them to the player later when needed. &lt;br /&gt;
&lt;br /&gt;
Therefore, we'll write an event handler for [[onClientResourceStart]] to create the window:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
-- attach the event handler to the root element of the resource&lt;br /&gt;
-- this means it will only trigger when its own resource is started&lt;br /&gt;
addEventHandler(&amp;quot;onClientResourceStart&amp;quot;, getResourceRootElement(getThisResource()), &lt;br /&gt;
	function ()&lt;br /&gt;
		-- call the createRulesWindow function to create our gui&lt;br /&gt;
		createRulesWindow()&lt;br /&gt;
	end&lt;br /&gt;
)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
As this is a rules window, we need to show the window when the player joins the game. &lt;br /&gt;
Fortunately, GUI elements are visible by default so we do not need to write any more code to achieve this.&lt;br /&gt;
&lt;br /&gt;
However, we will also need to show the cursor for the player. &lt;br /&gt;
This can be done using the same event, [[onClientResourceStart]], so we can modify the above code to include showing the cursor:&lt;br /&gt;
&lt;br /&gt;
'''Note that we are now writing more code for our 'onClientResourceStart' event. This is not a new function and is meant to replace what you already have.'''&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
-- attach the event handler to the root element of the resource&lt;br /&gt;
-- this means it will only trigger when its own resource is started&lt;br /&gt;
addEventHandler(&amp;quot;onClientResourceStart&amp;quot;, getResourceRootElement(getThisResource()), &lt;br /&gt;
	function ()&lt;br /&gt;
		-- call the createRulesWindow function to create our gui&lt;br /&gt;
		createRulesWindow()&lt;br /&gt;
		&lt;br /&gt;
		-- show the cursor to the player&lt;br /&gt;
		showCursor(true,true)&lt;br /&gt;
	end&lt;br /&gt;
)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
We now have a completed GUI rules window. Next, we need to write the button functionality for the accept button.&lt;br /&gt;
&lt;br /&gt;
==Scripting the Button==&lt;br /&gt;
Now that we have created our GUI, we need to make it work.&lt;br /&gt;
&lt;br /&gt;
===Detecting the click===&lt;br /&gt;
When the player clicks on any part of the GUI, the event &amp;quot;[[onClientGUIClick]]&amp;quot; will be triggered for the GUI component you clicked on. This allows us to easily detect any clicks on the GUI elements we want to use.&lt;br /&gt;
For example, we can attach the event to the 'rulesButton' button to catch any clicks on it:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
-- attach the event onClientGUIClick to rulesButton and set it to trigger the 'acceptRules' function&lt;br /&gt;
addEventHandler(&amp;quot;onClientGUIClick&amp;quot;, rulesButton, acceptRules, false)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
'''Note the final argument passed is &amp;quot;false&amp;quot;. This indicates that the event will only trigger directly on rulesButton, not if the event has propagated up or down the tree. Setting this to &amp;quot;true&amp;quot; while attaching to gui elements will mean that clicking on any element in the same branch will trigger this event.'''&lt;br /&gt;
&lt;br /&gt;
This line of code can now be added inside the 'createRulesWindow' function. It is a common mistake to try and attach events to non-existant GUI elements, so make sure you always attach your events '''after''' the GUI element (in this case, the button) has been created:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
function createRulesWindow()&lt;br /&gt;
	-- create all our GUI elements&lt;br /&gt;
	...&lt;br /&gt;
&lt;br /&gt;
	-- now add our onClientGUIClick event to the button we just created&lt;br /&gt;
	addEventHandler(&amp;quot;onClientGUIClick&amp;quot;, rulesButton, acceptRules, false)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Managing the click===&lt;br /&gt;
Now that we can detect when the player clicks on the button, we need to write code to manage what happens when they do.&lt;br /&gt;
In our [[onClientGUIClick]] event handle, we told it to call the function 'acceptRules' whenever 'rulesButton' is clicked.&lt;br /&gt;
Therefore, we can now use the function 'acceptRules' to control what happens when the button is clicked:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
-- create the function and define the 'button' and 'state' parameters&lt;br /&gt;
-- (these are passed automatically by onClientGUIClick)&lt;br /&gt;
function acceptRules(button,state)&lt;br /&gt;
	-- if our accept button was clicked with the left mouse button, and the state of the mouse button is up&lt;br /&gt;
	if button == &amp;quot;left&amp;quot; and state == &amp;quot;up&amp;quot; then&lt;br /&gt;
		-- hide the window and all the components&lt;br /&gt;
		guiSetVisible(rulesWindow, false)&lt;br /&gt;
		&lt;br /&gt;
		-- hide the mouse cursor&lt;br /&gt;
		showCursor(false,false)&lt;br /&gt;
		&lt;br /&gt;
		-- output a message to the player&lt;br /&gt;
		outputChatBox(&amp;quot;Thank you for accepting our rules. Have fun!&amp;quot;)&lt;br /&gt;
		&lt;br /&gt;
		&lt;br /&gt;
		-- if the warning timer exists&lt;br /&gt;
		if rulesWarningTimer then&lt;br /&gt;
			-- stop the timer and set the variable to nil&lt;br /&gt;
			-- this is the timer used to kick players who do not accept the rules. We will cover this in more detail in the next section.&lt;br /&gt;
			killTimer(rulesWarningTimer)&lt;br /&gt;
			rulesWarningTimer = nil&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Now, when the button is clicked, the window and the cursor will be hidden.&lt;br /&gt;
&lt;br /&gt;
==Checking for agreement==&lt;br /&gt;
Currently, our window will show when the player joins the server, and they must click accept to remove it.&lt;br /&gt;
However, if they do not accept it they can stay in the server indefinately with the window open.&lt;br /&gt;
&lt;br /&gt;
===Setting a timer===&lt;br /&gt;
To combat this, we will add a timer using [[setTimer]] to kick them from the server after a period of time if they have not accepted the rules.&lt;br /&gt;
First, we will need a global variable to store the timer pointer:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
local rulesWarningTimer = nil&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Put this line at the very top of your script (it does not need to be inside a function)&lt;br /&gt;
&lt;br /&gt;
Next, we will create our timer:&lt;br /&gt;
&lt;br /&gt;
'''Note that we are now writing more code for our existing 'createRulesWindow' function.'''&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
function createRulesWindow()&lt;br /&gt;
	-- create all of our gui&lt;br /&gt;
	...&lt;br /&gt;
	&lt;br /&gt;
	-- set a timer for 30 seconds and set it to call our 'inactivePlayer' function with &amp;quot;1&amp;quot; as an argument&lt;br /&gt;
	rulesWarningTimer = setTimer(inactivePlayer,30000,1,1)&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Put this [[setTimer]] line at the bottom of your 'createRulesWindow' function.&lt;br /&gt;
This will create a timer that will trigger after 30 seconds.&lt;br /&gt;
&lt;br /&gt;
===Giving a warning===&lt;br /&gt;
Now we will write our 'inactivePlayer' function, to administer warnings to the player and finally kick him if he does not accept:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
-- create our function and define the 'status' parameter&lt;br /&gt;
-- the value of status will be passed from our setTimer function call&lt;br /&gt;
function inactivePlayer(status)&lt;br /&gt;
	-- if status is 1 (this means it is the first warning)&lt;br /&gt;
	if status == 1 then&lt;br /&gt;
		-- output a warning&lt;br /&gt;
		outputChatBox(&amp;quot;Please accept our rules or be kicked.&amp;quot;)&lt;br /&gt;
		&lt;br /&gt;
		-- set another timer to call inactivePlayer in another 30 seconds, with &amp;quot;2&amp;quot; as an argument&lt;br /&gt;
		rulesWarningTimer = setTimer(inactivePlayer,30000,1,2)&lt;br /&gt;
		&lt;br /&gt;
	-- if status is 2 (the second warning)&lt;br /&gt;
	elseif status == 2 then&lt;br /&gt;
		-- output a final warning&lt;br /&gt;
		outputChatBox(&amp;quot;FINAL WARNING: Please accept our rules or be kicked.&amp;quot;)&lt;br /&gt;
		&lt;br /&gt;
		-- set a final timer to call inactivePlayer in another 30 seconds, with &amp;quot;3&amp;quot; as an argument&lt;br /&gt;
		rulesWarningTimer = setTimer(inactivePlayer,30000,1,3)	&lt;br /&gt;
	elseif status == 3 then&lt;br /&gt;
		-- trigger the server so we can kick the player&lt;br /&gt;
		triggerServerEvent(&amp;quot;clientKickInactivePlayer&amp;quot;,getLocalPlayer())&lt;br /&gt;
	end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Note the use of [[triggerServerEvent]] to call the server. You should have experience with client-server interaction from the [[Introduction to Scripting the GUI|Previous tutorial]]. &lt;br /&gt;
If not, you can go back and read the full explanation there.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
We have now completed all the clientside code for this tutorial.&lt;br /&gt;
&lt;br /&gt;
===Kicking the player===&lt;br /&gt;
We now need to catch the event on the server that we triggered from the client, so open up a serverside lua file to work with.&lt;br /&gt;
&lt;br /&gt;
To begin, we will add the event on the server:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
-- add the event, note the final argument &amp;quot;true&amp;quot; indicates it can be triggered from the client&lt;br /&gt;
addEvent(&amp;quot;clientKickInactivePlayer&amp;quot;,true)&lt;br /&gt;
-- add an event handler for this event to trigger the kickInactivePlayer function&lt;br /&gt;
addEventHandler(&amp;quot;clientKickInactivePlayer&amp;quot;,root,kickInactivePlayer)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
'''Make sure you add your event handler after you have defined your 'kickInactivePlayer' function.'''&lt;br /&gt;
&lt;br /&gt;
Note the use of [[addEvent]] and [[addEventHandler]] on the server. You should have experience with client-server interaction from the [[Introduction to Scripting the GUI|Previous tutorial]]. &lt;br /&gt;
If not, you can go back and read the full explanation there.&lt;br /&gt;
&lt;br /&gt;
Finally, we will add the 'kickInactivePlayer' function to control kicking of the player:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
-- create our function&lt;br /&gt;
function kickInactivePlayer()&lt;br /&gt;
	-- kick the player&lt;br /&gt;
	kickPlayer(client,&amp;quot;Please accept our rules.&amp;quot;)&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Note the use of the 'client' variable, this is an MTA variable that holds the value of the client (player) that triggered the event.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
'''Note that [[kickPlayer]] will require your resource to have kick access in your ACL.'''&lt;br /&gt;
&lt;br /&gt;
'''This is most easily accomplished by adding your resource into your admin group in the ACL:'''&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;xml&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;group name=&amp;quot;Admin&amp;quot;&amp;gt;&lt;br /&gt;
	...&lt;br /&gt;
    &amp;lt;object name=&amp;quot;resource.YourResourceName&amp;quot; /&amp;gt;&lt;br /&gt;
	...&lt;br /&gt;
&amp;lt;/group&amp;gt;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
For more information on the [[ACL]], see the [[ACL]] wiki page.&lt;br /&gt;
&lt;br /&gt;
That concludes this tutorial. You should now have a fully working rules window for your server.&lt;br /&gt;
&lt;br /&gt;
For further help with GUI, see the [[:Category:GUI_Tutorials|GUI tutorials]].&lt;br /&gt;
&lt;br /&gt;
[[Category:GUI_Tutorials]]&lt;/div&gt;</summary>
		<author><name>R3mp</name></author>
	</entry>
	<entry>
		<id>https://wiki.multitheftauto.com/index.php?title=Introduction_to_Scripting_the_GUI&amp;diff=22255</id>
		<title>Introduction to Scripting the GUI</title>
		<link rel="alternate" type="text/html" href="https://wiki.multitheftauto.com/index.php?title=Introduction_to_Scripting_the_GUI&amp;diff=22255"/>
		<updated>2010-01-08T01:45:10Z</updated>

		<summary type="html">&lt;p&gt;R3mp: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;!-- place holder --&amp;gt;&lt;br /&gt;
One important feature in MTA:SA is the ability to script customized GUI (Graphic User Interface). The GUI consists of windows, button, edit boxes, check boxes... Almost every standard form components in graphical environments. They can be displayed while the user is in game, and used for inputs and outputs in place of traditional commands. &lt;br /&gt;
&lt;br /&gt;
[[Image:AdminGUI.png|thumb|Admin Console GUI]]&lt;br /&gt;
&lt;br /&gt;
==A tutorial to make a login window==&lt;br /&gt;
In this tutorial we'll make a simple login window, with two input boxes and a button. The window appears when the player joins the game, and once the button is clicked, the player is spawned. The tutorial will continue the gamemode we made in [[Scripting Introduction|Introduction to Scripting]] ''(If you have used the [[Scripting Introduction|Introduction to Scripting]], you will need to remove or comment the [[spawnPlayer]] line in the &amp;quot;joinHandler&amp;quot; function in your code, as we will be replacing it with a gui alternative in this tutorial)''. We'll also take a look at client-side scripting. &lt;br /&gt;
&lt;br /&gt;
===Draw the window===&lt;br /&gt;
All the GUI must be made client side. It is also a good practice to keep all the client scripts in a separate folder. Browse to /Your MTA Server/mods/deathmatch/resources/myserver/ directory, and create a folder named &amp;quot;client&amp;quot;. Under /client/ directory, create a text file and name it &amp;quot;gui.lua&amp;quot;, and in this file we will write a funtion that draws the window:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
function createLoginWindow()&lt;br /&gt;
	-- define the X and Y positions of the window&lt;br /&gt;
	local X = 0.375&lt;br /&gt;
	local Y = 0.375&lt;br /&gt;
	-- define the width and height of the window&lt;br /&gt;
	local Width = 0.25&lt;br /&gt;
	local Height = 0.25&lt;br /&gt;
	-- create the window and save its element value into the variable 'wdwLogin'&lt;br /&gt;
	-- click on the function's name to read its documentation&lt;br /&gt;
	wdwLogin = guiCreateWindow(X, Y, Width, Height, &amp;quot;Please Log In&amp;quot;, true)&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Relative and Absolute===&lt;br /&gt;
Note that the final argument passed to guiCreateWindow in the above example is ''true''. This indicates that the coordinates and dimensions of the window are '''relative''', meaning they are a ''percentage'' of the total screen size. This means that if the far left side of the screen is 0, and the far right is 1, an X position of 0.5 would represent the centre point of the screen. Similarly, if the top of the screen is 0 and the bottom is 1, a Y position of 0.2 would be 20% of the way down the screen. The same principles apply to both Width and Height as well (with a Width value of 0.5 meaning the window will be half as wide as the screen).&lt;br /&gt;
&lt;br /&gt;
The alternative to using relative values is using '''absolute''' (by passing ''false'' instead of true to guiCreateWindow). Absolute values are calculated as the total number of pixels from the top-left corner of the parent (if no gui element parent is specified, the parent is the screen itself). If we assume a screen resolution of 1920x1200, the far left side of the screen being 0 pixels and the far right being 1920 pixels, an X position of 960 will represent the centre point of the screen. Similarly, if the top of the screen is 0 pixels and the bottom is 1200, a Y position of 20 would be 20 pixels down from the top of the screen. The same principles apple to both Width and Height as well (with a Width value of 50 meaning the window will be 50 pixels wide). ''You can use [[guiGetScreenSize]] and a little maths to calculate certain absolute positions.''&lt;br /&gt;
&lt;br /&gt;
The differences between using relative and absolute values is quite simple; gui created using absolute values will always remain exactly the same pixel size and position, while gui created using relative values will always be a percentage of its parent's size.&lt;br /&gt;
&lt;br /&gt;
Absolute is generally easier to maintain when editing code by hand, however your choice of type depends on the situation you are using it for.&lt;br /&gt;
&lt;br /&gt;
For the purposes of this introduction we will be using relative values.&lt;br /&gt;
&lt;br /&gt;
===Adding the components===&lt;br /&gt;
Next, we'll add the text labels (saying &amp;quot;username:&amp;quot; and &amp;quot;password:&amp;quot;), edit boxes (for entering your data) and a button to log in: &lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
function createLoginWindow()&lt;br /&gt;
	local X = 0.375&lt;br /&gt;
	local Y = 0.375&lt;br /&gt;
	local Width = 0.25&lt;br /&gt;
	local Height = 0.25&lt;br /&gt;
	wdwLogin = guiCreateWindow(X, Y, Width, Height, &amp;quot;Please Log In&amp;quot;, true)&lt;br /&gt;
	&lt;br /&gt;
	-- define new X and Y positions for the first label&lt;br /&gt;
	X = 0.0825&lt;br /&gt;
	Y = 0.2&lt;br /&gt;
	-- define new Width and Height values for the first label&lt;br /&gt;
	Width = 0.25&lt;br /&gt;
	Height = 0.25&lt;br /&gt;
	-- create the first label, note the final argument passed is 'wdwLogin' meaning the window&lt;br /&gt;
	-- we created above is the parent of this label (so all the position and size values are now relative to the position of that window)&lt;br /&gt;
	guiCreateLabel(X, Y, Width, Height, &amp;quot;Username&amp;quot;, true, wdwLogin)&lt;br /&gt;
	-- alter the Y value, so the second label is slightly below the first&lt;br /&gt;
	Y = 0.5&lt;br /&gt;
	guiCreateLabel(X, Y, Width, Height, &amp;quot;Password&amp;quot;, true, wdwLogin)&lt;br /&gt;
	&lt;br /&gt;
&lt;br /&gt;
	X = 0.415&lt;br /&gt;
	Y = 0.2&lt;br /&gt;
	Width = 0.5&lt;br /&gt;
	Height = 0.15&lt;br /&gt;
	edtUser = guiCreateEdit(X, Y, Width, Height, &amp;quot;&amp;quot;, true, wdwLogin)&lt;br /&gt;
	Y = 0.5&lt;br /&gt;
	edtPass = guiCreateEdit(X, Y, Width, Height, &amp;quot;&amp;quot;, true, wdwLogin)&lt;br /&gt;
	-- set the maximum character length for the username and password fields to 50&lt;br /&gt;
	guiEditSetMaxLength(edtUser, 50)&lt;br /&gt;
	guiEditSetMaxLength(edtPass, 50)&lt;br /&gt;
	&lt;br /&gt;
	X = 0.415&lt;br /&gt;
	Y = 0.7&lt;br /&gt;
	Width = 0.25&lt;br /&gt;
	Height = 0.2&lt;br /&gt;
	btnLogin = guiCreateButton(X, Y, Width, Height, &amp;quot;Log In&amp;quot;, true, wdwLogin)&lt;br /&gt;
	&lt;br /&gt;
	-- make the window invisible&lt;br /&gt;
	guiSetVisible(wdwLogin, false)&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Note that every GUI component created is a child of the window, this is done by specifying the parent element (wdwLogin, in this case) when creating the component. &lt;br /&gt;
&lt;br /&gt;
This is very useful because not only does it mean that all the components are attached to the window and will move with it, but also that any changes done to the parent window will be applied down the tree to these child components. For example, we can now hide all of the GUI we just created by simply hiding the window:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
guiSetVisible(wdwLogin, false) --hides all the GUI we made so we can show them to the player at the appropriate moment. &lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Using the function we wrote===&lt;br /&gt;
The createLoginWindow function is now complete, but it won't do anything until we call it. It is recommended to create all GUI when the client resource starts, hide them, and show them to the player later when needed. Therefore, we'll write an event handler for &amp;quot;[[onClientResourceStart]]&amp;quot; to create the window:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
-- attach the event handler to the root element of the resource&lt;br /&gt;
-- this means it will only trigger when its own resource is started&lt;br /&gt;
addEventHandler(&amp;quot;onClientResourceStart&amp;quot;, getResourceRootElement(getThisResource()), &lt;br /&gt;
	function ()&lt;br /&gt;
		createLoginWindow()&lt;br /&gt;
	end&lt;br /&gt;
)	&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
As this is a log in window, we now need to show the window when the player joins the game. &lt;br /&gt;
This can be done using the same event, &amp;quot;[[onClientResourceStart]]&amp;quot;, so we can modify the above code to include showing the window:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
addEventHandler(&amp;quot;onClientResourceStart&amp;quot;, getResourceRootElement(getThisResource()), &lt;br /&gt;
	function ()&lt;br /&gt;
		-- create the log in window and its components&lt;br /&gt;
		createLoginWindow()&lt;br /&gt;
&lt;br /&gt;
		-- output a brief welcome message to the player&lt;br /&gt;
                outputChatBox(&amp;quot;Welcome to My MTA:SA Server, please log in.&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
		-- if the GUI was successfully created, then show the GUI to the player&lt;br /&gt;
	        if (wdwLogin ~= nil) then&lt;br /&gt;
			guiSetVisible(wdwLogin, true)&lt;br /&gt;
		else&lt;br /&gt;
			-- if the GUI hasnt been properly created, tell the player&lt;br /&gt;
			outputChatBox(&amp;quot;An unexpected error has occurred and the log in GUI has not been created.&amp;quot;)&lt;br /&gt;
	        end &lt;br /&gt;
&lt;br /&gt;
		-- enable the players cursor (so they can select and click on the components)&lt;br /&gt;
	        showCursor(true)&lt;br /&gt;
		-- set the input focus onto the GUI, allowing players (for example) to press 'T' without the chatbox opening&lt;br /&gt;
	        guiSetInputEnabled(true)&lt;br /&gt;
	end&lt;br /&gt;
)	&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Note that we have a simple security check before making the window visible, so in the unlikely event that the window has not been created, meaning wdwLogin is not a valid element, we don't get an error and just inform the player what has happened. &lt;br /&gt;
In the next step, we will create the button functionality for the log in button.&lt;br /&gt;
&lt;br /&gt;
==Scripting the button==&lt;br /&gt;
Now that we have created our GUI and shown it to the player, we need to make it work. &lt;br /&gt;
&lt;br /&gt;
===Detecting the click===&lt;br /&gt;
When the player clicks on any part of the GUI, the event &amp;quot;[[onClientGUIClick]]&amp;quot; will be triggered for the GUI component you clicked on. This allows us to easily detect any clicks on the GUI elements we want to use.&lt;br /&gt;
For example, we can attach the event to the btnLogin button to catch any clicks on it:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
-- attach the event onClientGUIClick to btnLogin and set it to trigger the 'clientSubmitLogin' function&lt;br /&gt;
addEventHandler(&amp;quot;onClientGUIClick&amp;quot;, btnLogin, clientSubmitLogin, false)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
'''Note the final argument passed is &amp;quot;false&amp;quot;. This indicates that the event will only trigger directly on btnLogin, not if the event has propagated up or down the tree. Setting this to &amp;quot;true&amp;quot; while attaching to gui elements will mean that clicking on any element in the same branch will trigger this event.'''&lt;br /&gt;
&lt;br /&gt;
This line of code can now be added inside the createLoginWindow function. It is a common mistake to try and attach events to non-existant GUI elements, so make sure you always attach your events '''after''' the gui element (in this case, the button) has been created:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
function createLoginWindow()&lt;br /&gt;
	-- create all our GUI elements&lt;br /&gt;
	...&lt;br /&gt;
&lt;br /&gt;
	-- now add our onClientGUIClick event to the button we just created&lt;br /&gt;
	addEventHandler(&amp;quot;onClientGUIClick&amp;quot;, btnLogin, clientSubmitLogin, false)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Managing the click===&lt;br /&gt;
Now that we can detect when the player clicks on the button, we need to write code to manage what happens when they do.&lt;br /&gt;
In our [[onClientGUIClick]] event handle, we told it to call the function clientSubmitLogin whenever btnLogin is clicked.&lt;br /&gt;
Therefore, we can now use the function clientSubmitLogin to control what happens when the button is clicked:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
-- create the function and define the 'button' and 'state' parameters&lt;br /&gt;
-- (these are passed automatically by onClientGUIClick)&lt;br /&gt;
function clientSubmitLogin(button,state)&lt;br /&gt;
	-- if our login button was clicked with the left mouse button, and the state of the mouse button is up&lt;br /&gt;
	if button == &amp;quot;left&amp;quot; and state == &amp;quot;up&amp;quot; then&lt;br /&gt;
		-- move the input focus back onto the game (allowing players to move around, open the chatbox, etc)&lt;br /&gt;
		guiSetInputEnabled(false)&lt;br /&gt;
		-- hide the window and all the components&lt;br /&gt;
		guiSetVisible(wdwLogin, false)&lt;br /&gt;
		-- hide the mouse cursor&lt;br /&gt;
		showCursor(false)&lt;br /&gt;
	end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Now, when the button is clicked, the window will be hidden and all controls will be returned to the player. Next, we will tell the server to allow the player to spawn.&lt;br /&gt;
&lt;br /&gt;
===Triggering the server===&lt;br /&gt;
Triggering the server can be done using [[triggerServerEvent]]. This allows you to trigger a specified event on the server from the client. The same can be done in reverse using [[triggerClientEvent]].&lt;br /&gt;
Here, we use the [[triggerServerEvent]] function to call our own custom event on the server, named &amp;quot;submitLogin&amp;quot;, which will then control the spawning of the player serverside.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
function clientSubmitLogin(button,state)&lt;br /&gt;
	if button == &amp;quot;left&amp;quot; and state == &amp;quot;up&amp;quot; then&lt;br /&gt;
		-- get the text entered in the 'username' field&lt;br /&gt;
		local username = guiGetText(edtUser)&lt;br /&gt;
		-- get the text entered in the 'password' field&lt;br /&gt;
		local password = guiGetText(edtPass)&lt;br /&gt;
&lt;br /&gt;
		-- if the username and password both exist&lt;br /&gt;
		if username and password then&lt;br /&gt;
			-- trigger the server event 'submitLogin' and pass the username and password to it&lt;br /&gt;
			triggerServerEvent(&amp;quot;submitLogin&amp;quot;, getRootElement(), username, password)&lt;br /&gt;
&lt;br /&gt;
			-- hide the gui, hide the cursor and return control to the player&lt;br /&gt;
			guiSetInputEnabled(false)&lt;br /&gt;
			guiSetVisible(wdwLogin, false)&lt;br /&gt;
			showCursor(false)&lt;br /&gt;
		else&lt;br /&gt;
			-- otherwise, output a message to the player, do not trigger the server&lt;br /&gt;
			-- and do not hide the gui&lt;br /&gt;
			outputChatBox(&amp;quot;Please enter a username and password.&amp;quot;)&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Creating the serverside event===&lt;br /&gt;
At this point we now have all the code needed on the client side, so open up your serverside 'script.lua' file (from the [[Scripting Introduction|Introduction to Scripting]]) or another suitable serverside file to work with.&lt;br /&gt;
&lt;br /&gt;
On the server side, recall that we are spawning the player as soon as they login.&lt;br /&gt;
So, first of all, we will need to define the custom event that we used before on the client. This can be done using [[addEvent]] and [[addEventHandler]].&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
-- create our loginHandler function, with username and password parameters (passed from the client gui)&lt;br /&gt;
function loginHandler(username,password)&lt;br /&gt;
&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
-- define our custom event, and allow it to be triggered from the client ('true')&lt;br /&gt;
addEvent(&amp;quot;submitLogin&amp;quot;,true)&lt;br /&gt;
-- add an event handler so that when submitLogin is triggered, the function loginHandler is called&lt;br /&gt;
addEventHandler(&amp;quot;submitLogin&amp;quot;,root,loginHandler)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Logging in===&lt;br /&gt;
Now we have a function that is called through the custom event 'submitLogin', we can start to work on logging in and spawning the player, using our 'loginHandler' function:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
function loginHandler(username,password)&lt;br /&gt;
	-- check that the username and password are correct&lt;br /&gt;
	if username == &amp;quot;user&amp;quot; and password == &amp;quot;apple&amp;quot; then&lt;br /&gt;
		-- the player has successfully logged in, so spawn them&lt;br /&gt;
		if (client) then&lt;br /&gt;
			spawnPlayer(client, 1959.55, -1714.46, 10)&lt;br /&gt;
			fadeCamera(client, true)&lt;br /&gt;
			outputChatBox(&amp;quot;Welcome to My Server.&amp;quot;, client)&lt;br /&gt;
		end&lt;br /&gt;
	else&lt;br /&gt;
		-- if the username or password are not correct, output a message to the player&lt;br /&gt;
		outputChatBox(&amp;quot;Invalid username and password. Please re-connect and try again.&amp;quot;,client)&lt;br /&gt;
        end			&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
addEvent(&amp;quot;submitLogin&amp;quot;,true)&lt;br /&gt;
addEventHandler(&amp;quot;submitLogin&amp;quot;,root,loginHandler)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
'''For the purposes of this tutorial, a very basic username and password system is shown. For a more comprehensive alternative, you can use the Account System or a MySQL database.'''&lt;br /&gt;
&lt;br /&gt;
Also note the use of the variable &amp;quot;client&amp;quot;, it's an internal variable used by MTA to identify the player who triggered the event. &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Finally, do not forget to include the new gui.lua file in the meta.xml of the main resource, and label it as a client script:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;xml&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;script src=&amp;quot;client/gui.lua&amp;quot; type=&amp;quot;client&amp;quot; /&amp;gt;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
At this point, we now have a basic login window that checks the player's username and password when the login button is clicked. If they are correct, the player is automatically spawned.&lt;br /&gt;
&lt;br /&gt;
For further help with GUI, see the [[:Category:GUI_Tutorials|GUI tutorials]].&lt;br /&gt;
&lt;br /&gt;
[[Category:GUI_Tutorials]]&lt;br /&gt;
[[it:Introduzione_allo_scripting_della_GUI]]&lt;br /&gt;
[[ru:Introduction to Scripting the GUI]]&lt;/div&gt;</summary>
		<author><name>R3mp</name></author>
	</entry>
	<entry>
		<id>https://wiki.multitheftauto.com/index.php?title=Introduction_to_Scripting_the_GUI_-_Part_3&amp;diff=22254</id>
		<title>Introduction to Scripting the GUI - Part 3</title>
		<link rel="alternate" type="text/html" href="https://wiki.multitheftauto.com/index.php?title=Introduction_to_Scripting_the_GUI_-_Part_3&amp;diff=22254"/>
		<updated>2010-01-08T01:44:51Z</updated>

		<summary type="html">&lt;p&gt;R3mp: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;'''Introduction to Scripting the GUI - Part 3 (Teleport Window)'''&lt;br /&gt;
&lt;br /&gt;
In this tutorial we will make a simple city teleport window, with 3 buttons (one for each city) that when clicked will teleport you to that city.&lt;br /&gt;
&lt;br /&gt;
'''Note that this tutorial builds on content covered in the [[Introduction to Scripting the GUI|GUI Scripting Introduction]].'''&lt;br /&gt;
&lt;br /&gt;
[[Image:Gui_teleport_tutorial.PNG|thumb|GUI Teleport Window]]&lt;br /&gt;
&lt;br /&gt;
==Making the GUI==&lt;br /&gt;
&lt;br /&gt;
===Getting set up===&lt;br /&gt;
The first thing we need to do is create our GUI elements.&lt;br /&gt;
For this tutorial we will be using one [[Element/GUI/Window|window]], three [[Element/GUI/Button|buttons]] and one [[Element/GUI/Text_label|label]].&lt;br /&gt;
We will be using '''absolute''' position values.&lt;br /&gt;
&lt;br /&gt;
As noted in the [[Introduction to Scripting the GUI|Previous tutorial]], all the GUI must be made client side. &lt;br /&gt;
&lt;br /&gt;
If you are following on from that tutorial, open up your gui.lua file to work with.&lt;br /&gt;
&lt;br /&gt;
If you are not, browse to /Your MTA Server/mods/deathmatch/resources/myserver/ directory, and create a folder named &amp;quot;client&amp;quot;. &lt;br /&gt;
Under /client/ directory, create a text file and name it &amp;quot;gui.lua&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
If you have not already done so, do not forget to include the new gui.lua file in the meta.xml of the main resource, and label it as a client script:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;xml&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;script src=&amp;quot;client/gui.lua&amp;quot; type=&amp;quot;client&amp;quot; /&amp;gt;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Making the window===&lt;br /&gt;
In this file we will now write a funtion that creates the window.&lt;br /&gt;
To create a window we will use [[guiCreateWindow]]:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
-- create the function that will hold our gui creation code&lt;br /&gt;
function createTeleportWindow()&lt;br /&gt;
	-- get the screen width and height&lt;br /&gt;
	local sWidth, sHeight = guiGetScreenSize()&lt;br /&gt;
 &lt;br /&gt;
	-- create the window, using some maths to find the centre of the screen&lt;br /&gt;
	local Width,Height = 231,188&lt;br /&gt;
	local X = (sWidth/2) - (Width/2)&lt;br /&gt;
	local Y = (sHeight/2) - (Height/2)&lt;br /&gt;
 &lt;br /&gt;
	-- create the window&lt;br /&gt;
	teleportWindow = guiCreateWindow(X,Y,Width,Height,&amp;quot;City Teleporter&amp;quot;,false)&lt;br /&gt;
 &lt;br /&gt;
	-- stop players from being able to resize the window&lt;br /&gt;
	guiWindowSetSizable(teleportWindow,false)&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
This will create a basic window in the centre of the screen that cannot be resized, with the title &amp;quot;City Teleporter&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
===Making the label===&lt;br /&gt;
Next, we will add the label describing what the buttons do.&lt;br /&gt;
To create a label we will use [[guiCreateLabel]]:&lt;br /&gt;
&lt;br /&gt;
'''Note that we are now writing more code for our existing 'createTeleportWindow' function. This is not a new function and is meant to replace what you already have.'''&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
function createTeleportWindow()&lt;br /&gt;
	local sWidth, sHeight = guiGetScreenSize()&lt;br /&gt;
 &lt;br /&gt;
	local Width,Height = 231,188&lt;br /&gt;
	local X = (sWidth/2) - (Width/2)&lt;br /&gt;
	local Y = (sHeight/2) - (Height/2)&lt;br /&gt;
 &lt;br /&gt;
	teleportWindow = guiCreateWindow(X,Y,Width,Height,&amp;quot;City Teleporter&amp;quot;,false)&lt;br /&gt;
 &lt;br /&gt;
	guiWindowSetSizable(teleportWindow,false)&lt;br /&gt;
	&lt;br /&gt;
	-- create a label with our instructions on&lt;br /&gt;
	teleportLabel = guiCreateLabel(18,23,191,33,&amp;quot;Click a button to teleport to that location&amp;quot;,false,teleportWindow)&lt;br /&gt;
	&lt;br /&gt;
	-- set the horizontal alignment of the label to center (ie: in the middle of the window)&lt;br /&gt;
	-- also note the final argument &amp;quot;true&amp;quot; &lt;br /&gt;
	-- this turns on wordwrap so if your text goes over the edge of the label, it will wrap around and start a new line automatically&lt;br /&gt;
	guiLabelSetHorizontalAlign(teleportLabel,&amp;quot;center&amp;quot;,true)	&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
You will now have a simple window with some centered instructions at the top.&lt;br /&gt;
&lt;br /&gt;
===Making the buttons===&lt;br /&gt;
Now we need to add the city teleport buttons.&lt;br /&gt;
To create a button we will use [[guiCreateButton]]:&lt;br /&gt;
&lt;br /&gt;
'''Note that we are now writing more code for our existing 'createTeleportWindow' function. This is not a new function and is meant to replace what you already have.'''&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
function createTeleportWindow()&lt;br /&gt;
	local sWidth, sHeight = guiGetScreenSize()&lt;br /&gt;
 &lt;br /&gt;
	local Width,Height = 231,188&lt;br /&gt;
	local X = (sWidth/2) - (Width/2)&lt;br /&gt;
	local Y = (sHeight/2) - (Height/2)&lt;br /&gt;
 &lt;br /&gt;
	teleportWindow = guiCreateWindow(X,Y,Width,Height,&amp;quot;City Teleporter&amp;quot;,false)&lt;br /&gt;
 &lt;br /&gt;
	guiWindowSetSizable(teleportWindow,false)&lt;br /&gt;
	&lt;br /&gt;
	teleportLabel = guiCreateLabel(18,23,191,33,&amp;quot;Click a button to teleport to that location&amp;quot;,false,teleportWindow)&lt;br /&gt;
	&lt;br /&gt;
	guiLabelSetHorizontalAlign(teleportLabel,&amp;quot;center&amp;quot;,true)	&lt;br /&gt;
	&lt;br /&gt;
	-- create the button for teleporting to Los Santos&lt;br /&gt;
	teleportButtonLS = guiCreateButton(18,63,195,35,&amp;quot;Los Santos&amp;quot;,false,teleportWindow)&lt;br /&gt;
	&lt;br /&gt;
	-- slightly below that, create another button for teleporting to San Fierro&lt;br /&gt;
	teleportButtonSF = guiCreateButton(18,103,195,35,&amp;quot;San Fierro&amp;quot;,false,teleportWindow)&lt;br /&gt;
	&lt;br /&gt;
	-- slightly below that again, create another button for teleport to Las Venturas&lt;br /&gt;
	teleportButtonLV = guiCreateButton(18,143,195,35,&amp;quot;Las Venturas&amp;quot;,false,teleportWindow)	&lt;br /&gt;
	&lt;br /&gt;
	-- hide the gui&lt;br /&gt;
	guiSetVisible(teleportWindow,false)&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Using the function we wrote===&lt;br /&gt;
Now our 'createTeleportWindow' function is ready, but it wont do anything until we call it.&lt;br /&gt;
It is recommended to create all GUI when the client resource starts, hide them, and show them to the player later when needed. &lt;br /&gt;
&lt;br /&gt;
Therefore, we'll write an event handler for [[onClientResourceStart]] to create the window:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
-- add our event handler, using the root element of the resource&lt;br /&gt;
-- this means it will only trigger when its own resource is started&lt;br /&gt;
addEventHandler(&amp;quot;onClientResourceStart&amp;quot;, getResourceRootElement(getThisResource()), &lt;br /&gt;
	function ()&lt;br /&gt;
		-- call the createTeleportWindow function to create our gui&lt;br /&gt;
		createTeleportWindow()&lt;br /&gt;
	end&lt;br /&gt;
)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Now that we have our GUI created, we need a way for the players to open the window.&lt;br /&gt;
&lt;br /&gt;
===Opening the GUI===&lt;br /&gt;
There are several ways this could be done, depending on your personal preference or the particulars of the situation.&lt;br /&gt;
For this tutorial, we will use a simple [[addCommandHandler|command]].&lt;br /&gt;
&lt;br /&gt;
To open the GUI, we will use the command /teleportme :&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
-- create our function&lt;br /&gt;
function openTeleportWindow()&lt;br /&gt;
	-- show the window&lt;br /&gt;
	guiSetVisible(teleportWindow,true)&lt;br /&gt;
		&lt;br /&gt;
	-- show the mouse cursor&lt;br /&gt;
	showCursor(true,true)&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
-- define the command /teleportme to call the openTeleportWindow function&lt;br /&gt;
addCommandHandler(&amp;quot;teleportme&amp;quot;,openTeleportWindow)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Next, we need to make the buttons actually teleport the player.&lt;br /&gt;
&lt;br /&gt;
==Scripting the button==&lt;br /&gt;
&lt;br /&gt;
Now that we have created our GUI and the players are able to open it, we need to make it work. &lt;br /&gt;
&lt;br /&gt;
===Detecting the click===&lt;br /&gt;
As described in previous tutorials, when the player clicks on any part of the GUI, the event &amp;quot;onClientGUIClick&amp;quot; will be triggered for the GUI component you clicked on. &lt;br /&gt;
With that in mind, we will attach an event handler to each of our 3 teleport buttons: &lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
-- attach the event onClientGUIClick to teleportButtonLS and set it to trigger the 'teleportPlayer' function&lt;br /&gt;
addEventHandler(&amp;quot;onClientGUIClick&amp;quot;, teleportButtonLS, teleportPlayer, false)&lt;br /&gt;
&lt;br /&gt;
-- attach the event onClientGUIClick to teleportButtonSF and set it to trigger the 'teleportPlayer' function&lt;br /&gt;
addEventHandler(&amp;quot;onClientGUIClick&amp;quot;, teleportButtonSF, teleportPlayer, false)&lt;br /&gt;
&lt;br /&gt;
-- attach the event onClientGUIClick to teleportButtonLV and set it to trigger the 'teleportPlayer' function&lt;br /&gt;
addEventHandler(&amp;quot;onClientGUIClick&amp;quot;, teleportButtonLV, teleportPlayer, false)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Put this code into your 'createTeleportWindow' function, '''after''' the buttons have been created.&lt;br /&gt;
&lt;br /&gt;
Note how we have set all 3 buttons to trigger the 'teleportPlayer' function.&lt;br /&gt;
&lt;br /&gt;
This allows us to easily expand our code later on (for example, to add more teleport locations) with a simple if statement in the function.&lt;br /&gt;
&lt;br /&gt;
===Managing the clicks===&lt;br /&gt;
Now that we can detect clicks on all our buttons, we need to manage what happens when we do.&lt;br /&gt;
&lt;br /&gt;
As we just noted, we will do this using the 'teleportPlayer' function.&lt;br /&gt;
We will use if statements to check which button has been clicked, then trigger a custom server event with the specified teleport coordinates to move the player:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
-- create our function, and add button and state parameters (these are passed automatically with onClickGUIClick)&lt;br /&gt;
function teleportPlayer(button,state)&lt;br /&gt;
	-- if our button was clicked with the left mouse button, and the state of the mouse button is up&lt;br /&gt;
	if button == &amp;quot;left&amp;quot; and state == &amp;quot;up&amp;quot; then&lt;br /&gt;
		-- if the player clicked on the LS teleport button&lt;br /&gt;
		if source == teleportButtonLS then&lt;br /&gt;
		&lt;br /&gt;
			-- trigger the server with our Los Santos coordinates&lt;br /&gt;
			triggerServerEvent(&amp;quot;movePlayerToPosition&amp;quot;,getLocalPlayer(),1479.6,-1612.8,14.0,0)&lt;br /&gt;
			&lt;br /&gt;
			-- output a message to the player&lt;br /&gt;
			outputChatBox(&amp;quot;Welcome to Los Santos!&amp;quot;)&lt;br /&gt;
			&lt;br /&gt;
		-- otherwise, if the player clicked on the SF teleport button&lt;br /&gt;
		elseif source == teleportButtonSF then&lt;br /&gt;
		&lt;br /&gt;
			-- trigger the server with our San Fierro coordinates&lt;br /&gt;
			triggerServerEvent(&amp;quot;movePlayerToPosition&amp;quot;,getLocalPlayer(),-2265.5,534.0,35.0,270)&lt;br /&gt;
&lt;br /&gt;
			-- output a message to the player&lt;br /&gt;
			outputChatBox(&amp;quot;Welcome to San Fierro!&amp;quot;)&lt;br /&gt;
			&lt;br /&gt;
		-- otherwise, if the player clicked on the LV teleport button&lt;br /&gt;
		elseif source == teleportButtonLV then&lt;br /&gt;
		&lt;br /&gt;
			-- trigger the server with our Las Venturas coordinates&lt;br /&gt;
			triggerServerEvent(&amp;quot;movePlayerToPosition&amp;quot;,getLocalPlayer(),2036.9,1545.2,10.8,270)&lt;br /&gt;
&lt;br /&gt;
			-- output a message to the player&lt;br /&gt;
			outputChatBox(&amp;quot;Welcome to Las Venturas!&amp;quot;)&lt;br /&gt;
			&lt;br /&gt;
		end&lt;br /&gt;
		&lt;br /&gt;
		-- hide the window and all the components&lt;br /&gt;
		guiSetVisible(teleportWindow, false)&lt;br /&gt;
		&lt;br /&gt;
		-- hide the mouse cursor&lt;br /&gt;
		showCursor(false)		&lt;br /&gt;
	end	&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
If you wanted to add more locations, you could simply add a new button to your GUI and check for it in this function using another if statement.&lt;br /&gt;
For example:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
function teleportPlayer(button,state)&lt;br /&gt;
	if button == &amp;quot;left&amp;quot; and state == &amp;quot;up&amp;quot; then&lt;br /&gt;
		...&lt;br /&gt;
		&lt;br /&gt;
		elseif source == yourNewButton then&lt;br /&gt;
			triggerServerEvent(&amp;quot;movePlayerToPosition&amp;quot;,getLocalPlayer(),xCoord,yCoord,zCoord,rotation)&lt;br /&gt;
		end&lt;br /&gt;
		...&lt;br /&gt;
	end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Creating the serverside event===&lt;br /&gt;
At this point we now have all the code needed on the client side, &lt;br /&gt;
so open up your serverside 'script.lua' file (from the [[Scripting Introduction|Introduction to Scripting]]) or another suitable serverside file to work with.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
On the clientside, we are triggering the server event &amp;quot;movePlayerToPosition&amp;quot;. So, we will first define that event.&lt;br /&gt;
To do that we will use [[addEvent]], then [[addEventHandler]]:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
-- create our function, with the x,y and z values we passed from the client&lt;br /&gt;
function moveThePlayer(x,y,z)&lt;br /&gt;
&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
-- define our custom event, and allow it to be triggered from the client ('true')&lt;br /&gt;
addEvent(&amp;quot;movePlayerToPosition&amp;quot;,true)&lt;br /&gt;
-- add an event handler so that when movePlayerToPosition is triggered, the function moveThePlayer is called&lt;br /&gt;
addEventHandler(&amp;quot;movePlayerToPosition&amp;quot;,root,moveThePlayer)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Moving the player===&lt;br /&gt;
Now all that is left is to move the player to their new position.&lt;br /&gt;
&lt;br /&gt;
'''Note that we are now writing more code for our existing 'moveThePlayer' function. This is not a new function and is meant to replace what you already have.'''&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
-- create our function, with the x,y and z values we passed from the client&lt;br /&gt;
function moveThePlayer(x,y,z,rotation)&lt;br /&gt;
	-- check we have a position and rotation&lt;br /&gt;
	if x and y and z and rotation then&lt;br /&gt;
		-- get the players current skin, so we can spawn them again without losing it&lt;br /&gt;
		local skin = getElementModel(client)&lt;br /&gt;
		&lt;br /&gt;
		-- spawn the player&lt;br /&gt;
		spawnPlayer(client,x,y,z,rotation,skin)&lt;br /&gt;
		&lt;br /&gt;
		-- make sure the players camera is on his character&lt;br /&gt;
		setCameraTarget(client,client)&lt;br /&gt;
	end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Note the use of [[spawnPlayer]] rather than, for example, [[setElementPosition]].&lt;br /&gt;
Using [[spawnPlayer]] has several advantages, such as being able to set the position when 'de-spawned' or dead, and automatically refilling health.&lt;br /&gt;
Of course, [[setElementPosition]] would work just as well to simply move them, so the choice is yours.&lt;br /&gt;
&lt;br /&gt;
Also note the use of the variable &amp;quot;client&amp;quot;, it's an internal variable used by MTA to identify the player who triggered the event.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
At this point, you should have a basic teleport window, allowing the player to teleport to any of the 3 major cities in San Andreas.&lt;br /&gt;
&lt;br /&gt;
For further help with GUI, see the [[:Category:GUI_Tutorials|GUI tutorials]].&lt;br /&gt;
&lt;br /&gt;
[[Category:GUI_Tutorials]]&lt;/div&gt;</summary>
		<author><name>R3mp</name></author>
	</entry>
	<entry>
		<id>https://wiki.multitheftauto.com/index.php?title=Introduction_to_Scripting_the_GUI_-_Part_3&amp;diff=22253</id>
		<title>Introduction to Scripting the GUI - Part 3</title>
		<link rel="alternate" type="text/html" href="https://wiki.multitheftauto.com/index.php?title=Introduction_to_Scripting_the_GUI_-_Part_3&amp;diff=22253"/>
		<updated>2010-01-08T01:41:35Z</updated>

		<summary type="html">&lt;p&gt;R3mp: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;'''Introduction to Scripting the GUI - Part 3 (Teleport Window)'''&lt;br /&gt;
&lt;br /&gt;
In this tutorial we will make a simple city teleport window, with 3 buttons (one for each city) that when clicked will teleport you to that city.&lt;br /&gt;
&lt;br /&gt;
'''Note that this tutorial builds on content covered in the [[Introduction to Scripting the GUI|GUI Scripting Introduction]].'''&lt;br /&gt;
&lt;br /&gt;
[[Image:Gui_teleport_tutorial.PNG|thumb|GUI Teleport Window]]&lt;br /&gt;
&lt;br /&gt;
==Making the GUI==&lt;br /&gt;
&lt;br /&gt;
===Getting set up===&lt;br /&gt;
The first thing we need to do is create our GUI elements.&lt;br /&gt;
For this tutorial we will be using one [[Element/GUI/Window|window]], three [[Element/GUI/Button|buttons]] and one [[Element/GUI/Text_label|label]].&lt;br /&gt;
We will be using '''absolute''' position values.&lt;br /&gt;
&lt;br /&gt;
As noted in the [[Introduction to Scripting the GUI|Previous tutorial]], all the GUI must be made client side. &lt;br /&gt;
&lt;br /&gt;
If you are following on from that tutorial, open up your gui.lua file to work with.&lt;br /&gt;
&lt;br /&gt;
If you are not, browse to /Your MTA Server/mods/deathmatch/resources/myserver/ directory, and create a folder named &amp;quot;client&amp;quot;. &lt;br /&gt;
Under /client/ directory, create a text file and name it &amp;quot;gui.lua&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
If you have not already done so, do not forget to include the new gui.lua file in the meta.xml of the main resource, and label it as a client script:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;xml&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;script src=&amp;quot;client/gui.lua&amp;quot; type=&amp;quot;client&amp;quot; /&amp;gt;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Making the window===&lt;br /&gt;
In this file we will now write a funtion that creates the window.&lt;br /&gt;
To create a window we will use [[guiCreateWindow]]:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
-- create the function that will hold our gui creation code&lt;br /&gt;
function createTeleportWindow()&lt;br /&gt;
	-- get the screen width and height&lt;br /&gt;
	local sWidth, sHeight = guiGetScreenSize()&lt;br /&gt;
 &lt;br /&gt;
	-- create the window, using some maths to find the centre of the screen&lt;br /&gt;
	local Width,Height = 231,188&lt;br /&gt;
	local X = (sWidth/2) - (Width/2)&lt;br /&gt;
	local Y = (sHeight/2) - (Height/2)&lt;br /&gt;
 &lt;br /&gt;
	-- create the window&lt;br /&gt;
	teleportWindow = guiCreateWindow(X,Y,Width,Height,&amp;quot;City Teleporter&amp;quot;,false)&lt;br /&gt;
 &lt;br /&gt;
	-- stop players from being able to resize the window&lt;br /&gt;
	guiWindowSetSizable(teleportWindow,false)&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
This will create a basic window in the centre of the screen that cannot be resized, with the title &amp;quot;City Teleporter&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
===Making the label===&lt;br /&gt;
Next, we will add the label describing what the buttons do.&lt;br /&gt;
To create a label we will use [[guiCreateLabel]]:&lt;br /&gt;
&lt;br /&gt;
'''Note that we are now writing more code for our existing 'createTeleportWindow' function. This is not a new function and is meant to replace what you already have.'''&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
function createTeleportWindow()&lt;br /&gt;
	local sWidth, sHeight = guiGetScreenSize()&lt;br /&gt;
 &lt;br /&gt;
	local Width,Height = 231,188&lt;br /&gt;
	local X = (sWidth/2) - (Width/2)&lt;br /&gt;
	local Y = (sHeight/2) - (Height/2)&lt;br /&gt;
 &lt;br /&gt;
	teleportWindow = guiCreateWindow(X,Y,Width,Height,&amp;quot;City Teleporter&amp;quot;,false)&lt;br /&gt;
 &lt;br /&gt;
	guiWindowSetSizable(teleportWindow,false)&lt;br /&gt;
	&lt;br /&gt;
	-- create a label with our instructions on&lt;br /&gt;
	teleportLabel = guiCreateLabel(18,23,191,33,&amp;quot;Click a button to teleport to that location&amp;quot;,false,teleportWindow)&lt;br /&gt;
	&lt;br /&gt;
	-- set the horizontal alignment of the label to center (ie: in the middle of the window)&lt;br /&gt;
	-- also note the final argument &amp;quot;true&amp;quot; &lt;br /&gt;
	-- this turns on wordwrap so if your text goes over the edge of the label, it will wrap around and start a new line automatically&lt;br /&gt;
	guiLabelSetHorizontalAlign(teleportLabel,&amp;quot;center&amp;quot;,true)	&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
You will now have a simple window with some centered instructions at the top.&lt;br /&gt;
&lt;br /&gt;
===Making the buttons===&lt;br /&gt;
Now we need to add the city teleport buttons.&lt;br /&gt;
To create a button we will use [[guiCreateButton]]:&lt;br /&gt;
&lt;br /&gt;
'''Note that we are now writing more code for our existing 'createTeleportWindow' function. This is not a new function and is meant to replace what you already have.'''&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
function createTeleportWindow()&lt;br /&gt;
	local sWidth, sHeight = guiGetScreenSize()&lt;br /&gt;
 &lt;br /&gt;
	local Width,Height = 231,188&lt;br /&gt;
	local X = (sWidth/2) - (Width/2)&lt;br /&gt;
	local Y = (sHeight/2) - (Height/2)&lt;br /&gt;
 &lt;br /&gt;
	teleportWindow = guiCreateWindow(X,Y,Width,Height,&amp;quot;City Teleporter&amp;quot;,false)&lt;br /&gt;
 &lt;br /&gt;
	guiWindowSetSizable(teleportWindow,false)&lt;br /&gt;
	&lt;br /&gt;
	teleportLabel = guiCreateLabel(18,23,191,33,&amp;quot;Click a button to teleport to that location&amp;quot;,false,teleportWindow)&lt;br /&gt;
	&lt;br /&gt;
	guiLabelSetHorizontalAlign(teleportLabel,&amp;quot;center&amp;quot;,true)	&lt;br /&gt;
	&lt;br /&gt;
	-- create the button for teleporting to Los Santos&lt;br /&gt;
	teleportButtonLS = guiCreateButton(18,63,195,35,&amp;quot;Los Santos&amp;quot;,false,teleportWindow)&lt;br /&gt;
	&lt;br /&gt;
	-- slightly below that, create another button for teleporting to San Fierro&lt;br /&gt;
	teleportButtonSF = guiCreateButton(18,103,195,35,&amp;quot;San Fierro&amp;quot;,false,teleportWindow)&lt;br /&gt;
	&lt;br /&gt;
	-- slightly below that again, create another button for teleport to Las Venturas&lt;br /&gt;
	teleportButtonLV = guiCreateButton(18,143,195,35,&amp;quot;Las Venturas&amp;quot;,false,teleportWindow)	&lt;br /&gt;
	&lt;br /&gt;
	-- hide the gui&lt;br /&gt;
	guiSetVisible(teleportWindow,false)&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Using the function we wrote===&lt;br /&gt;
Now our 'createTeleportWindow' function is ready, but it wont do anything until we call it.&lt;br /&gt;
It is recommended to create all GUI when the client resource starts, hide them, and show them to the player later when needed. &lt;br /&gt;
&lt;br /&gt;
Therefore, we'll write an event handler for [[onClientResourceStart]] to create the window:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
-- add our event handler, using the root element of the resource&lt;br /&gt;
-- this means it will only trigger when its own resource is started&lt;br /&gt;
addEventHandler(&amp;quot;onClientResourceStart&amp;quot;, getResourceRootElement(getThisResource()), &lt;br /&gt;
	function ()&lt;br /&gt;
		-- call the createTeleportWindow function to create our gui&lt;br /&gt;
		createTeleportWindow()&lt;br /&gt;
	end&lt;br /&gt;
)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Now that we have our GUI created, we need a way for the players to open the window.&lt;br /&gt;
&lt;br /&gt;
===Opening the GUI===&lt;br /&gt;
There are several ways this could be done, depending on your personal preference or the particulars of the situation.&lt;br /&gt;
For this tutorial, we will use a simple [[addCommandHandler|command]].&lt;br /&gt;
&lt;br /&gt;
To open the GUI, we will use the command /teleportme :&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
-- create our function&lt;br /&gt;
function openTeleportWindow()&lt;br /&gt;
	-- show the window&lt;br /&gt;
	guiSetVisible(teleportWindow,true)&lt;br /&gt;
		&lt;br /&gt;
	-- show the mouse cursor&lt;br /&gt;
	showCursor(true,true)&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
-- define the command /teleportme to call the openTeleportWindow function&lt;br /&gt;
addCommandHandler(&amp;quot;teleportme&amp;quot;,openTeleportWindow)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Next, we need to make the buttons actually teleport the player.&lt;br /&gt;
&lt;br /&gt;
==Scripting the button==&lt;br /&gt;
&lt;br /&gt;
Now that we have created our GUI and the players are able to open it, we need to make it work. &lt;br /&gt;
&lt;br /&gt;
===Detecting the click===&lt;br /&gt;
As described in previous tutorials, when the player clicks on any part of the GUI, the event &amp;quot;onClientGUIClick&amp;quot; will be triggered for the GUI component you clicked on. &lt;br /&gt;
With that in mind, we will attach an event handler to each of our 3 teleport buttons: &lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
-- attach the event onClientGUIClick to teleportButtonLS and set it to trigger the 'teleportPlayer' function&lt;br /&gt;
addEventHandler(&amp;quot;onClientGUIClick&amp;quot;, teleportButtonLS, teleportPlayer, false)&lt;br /&gt;
&lt;br /&gt;
-- attach the event onClientGUIClick to teleportButtonSF and set it to trigger the 'teleportPlayer' function&lt;br /&gt;
addEventHandler(&amp;quot;onClientGUIClick&amp;quot;, teleportButtonSF, teleportPlayer, false)&lt;br /&gt;
&lt;br /&gt;
-- attach the event onClientGUIClick to teleportButtonLV and set it to trigger the 'teleportPlayer' function&lt;br /&gt;
addEventHandler(&amp;quot;onClientGUIClick&amp;quot;, teleportButtonLV, teleportPlayer, false)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Put this code into your 'createTeleportWindow' function, '''after''' the buttons have been created.&lt;br /&gt;
&lt;br /&gt;
Note how we have set all 3 buttons to trigger the 'teleportPlayer' function.&lt;br /&gt;
&lt;br /&gt;
This allows us to easily expand our code later on (for example, to add more teleport locations) with a simple if statement in the function.&lt;br /&gt;
&lt;br /&gt;
===Managing the clicks===&lt;br /&gt;
Now that we can detect clicks on all our buttons, we need to manage what happens when we do.&lt;br /&gt;
&lt;br /&gt;
As we just noted, we will do this using the 'teleportPlayer' function.&lt;br /&gt;
We will use if statements to check which button has been clicked, then trigger a custom server event with the specified teleport coordinates to move the player:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
-- create our function, and add button and state parameters (these are passed automatically with onClickGUIClick)&lt;br /&gt;
function teleportPlayer(button,state)&lt;br /&gt;
	-- if our button was clicked with the left mouse button, and the state of the mouse button is up&lt;br /&gt;
	if button == &amp;quot;left&amp;quot; and state == &amp;quot;up&amp;quot; then&lt;br /&gt;
		-- if the player clicked on the LS teleport button&lt;br /&gt;
		if source == teleportButtonLS then&lt;br /&gt;
		&lt;br /&gt;
			-- trigger the server with our Los Santos coordinates&lt;br /&gt;
			triggerServerEvent(&amp;quot;movePlayerToPosition&amp;quot;,getLocalPlayer(),1479.6,-1612.8,14.0,0)&lt;br /&gt;
			&lt;br /&gt;
			-- output a message to the player&lt;br /&gt;
			outputChatBox(&amp;quot;Welcome to Los Santos!&amp;quot;)&lt;br /&gt;
			&lt;br /&gt;
		-- otherwise, if the player clicked on the SF teleport button&lt;br /&gt;
		elseif source == teleportButtonSF then&lt;br /&gt;
		&lt;br /&gt;
			-- trigger the server with our San Fierro coordinates&lt;br /&gt;
			triggerServerEvent(&amp;quot;movePlayerToPosition&amp;quot;,getLocalPlayer(),-2265.5,534.0,35.0,270)&lt;br /&gt;
&lt;br /&gt;
			-- output a message to the player&lt;br /&gt;
			outputChatBox(&amp;quot;Welcome to San Fierro!&amp;quot;)&lt;br /&gt;
			&lt;br /&gt;
		-- otherwise, if the player clicked on the LV teleport button&lt;br /&gt;
		elseif source == teleportButtonLV then&lt;br /&gt;
		&lt;br /&gt;
			-- trigger the server with our Las Venturas coordinates&lt;br /&gt;
			triggerServerEvent(&amp;quot;movePlayerToPosition&amp;quot;,getLocalPlayer(),2036.9,1545.2,10.8,270)&lt;br /&gt;
&lt;br /&gt;
			-- output a message to the player&lt;br /&gt;
			outputChatBox(&amp;quot;Welcome to Las Venturas!&amp;quot;)&lt;br /&gt;
			&lt;br /&gt;
		end&lt;br /&gt;
		&lt;br /&gt;
		-- hide the window and all the components&lt;br /&gt;
		guiSetVisible(teleportWindow, false)&lt;br /&gt;
		&lt;br /&gt;
		-- hide the mouse cursor&lt;br /&gt;
		showCursor(false)		&lt;br /&gt;
	end	&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
If you wanted to add more locations, you could simply add a new button to your GUI and check for it in this function using another if statement.&lt;br /&gt;
For example:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
function teleportPlayer(button,state)&lt;br /&gt;
	if button == &amp;quot;left&amp;quot; and state == &amp;quot;up&amp;quot; then&lt;br /&gt;
		...&lt;br /&gt;
		&lt;br /&gt;
		elseif source == yourNewButton then&lt;br /&gt;
			triggerServerEvent(&amp;quot;movePlayerToPosition&amp;quot;,getLocalPlayer(),xCoord,yCoord,zCoord,rotation)&lt;br /&gt;
		end&lt;br /&gt;
		...&lt;br /&gt;
	end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Creating the serverside event===&lt;br /&gt;
At this point we now have all the code needed on the client side, &lt;br /&gt;
so open up your serverside 'script.lua' file (from the [[Scripting Introduction|Introduction to Scripting]]) or another suitable serverside file to work with.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
On the clientside, we are triggering the server event &amp;quot;movePlayerToPosition&amp;quot;. So, we will first define that event.&lt;br /&gt;
To do that we will use [[addEvent]], then [[addEventHandler]]:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
-- create our function, with the x,y and z values we passed from the client&lt;br /&gt;
function moveThePlayer(x,y,z)&lt;br /&gt;
&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
-- define our custom event, and allow it to be triggered from the client ('true')&lt;br /&gt;
addEvent(&amp;quot;movePlayerToPosition&amp;quot;,true)&lt;br /&gt;
-- add an event handler so that when movePlayerToPosition is triggered, the function moveThePlayer is called&lt;br /&gt;
addEventHandler(&amp;quot;movePlayerToPosition&amp;quot;,root,moveThePlayer)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Moving the player===&lt;br /&gt;
Now all that is left is to move the player to their new position.&lt;br /&gt;
&lt;br /&gt;
'''Note that we are now writing more code for our existing 'moveThePlayer' function. This is not a new function and is meant to replace what you already have.'''&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
-- create our function, with the x,y and z values we passed from the client&lt;br /&gt;
function moveThePlayer(x,y,z,rotation)&lt;br /&gt;
	-- check we have a position and rotation&lt;br /&gt;
	if x and y and z and rotation then&lt;br /&gt;
		-- get the players current skin, so we can spawn them again without losing it&lt;br /&gt;
		local skin = getElementModel(client)&lt;br /&gt;
		&lt;br /&gt;
		-- spawn the player&lt;br /&gt;
		spawnPlayer(client,x,y,z,rotation,skin)&lt;br /&gt;
		&lt;br /&gt;
		-- make sure the players camera is on his character&lt;br /&gt;
		setCameraTarget(client,client)&lt;br /&gt;
	end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Note the use of [[spawnPlayer]] rather than, for example, [[setElementPosition]].&lt;br /&gt;
Using [[spawnPlayer]] has several advantages, such as being able to set the position when 'de-spawned' or dead, and automatically refilling health.&lt;br /&gt;
Of course, [[setElementPosition]] would work just as well to simply move them, so the choice is yours.&lt;br /&gt;
&lt;br /&gt;
Also note the use of the variable &amp;quot;client&amp;quot;, it's an internal variable used by MTA to identify the player who triggered the event.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
At this point, you should have a basic teleport window, allowing the player to teleport to any of the 3 major cities in San Andreas.&lt;br /&gt;
&lt;br /&gt;
[[Category:GUI_Tutorials]]&lt;/div&gt;</summary>
		<author><name>R3mp</name></author>
	</entry>
	<entry>
		<id>https://wiki.multitheftauto.com/index.php?title=File:Gui_teleport_tutorial.PNG&amp;diff=22252</id>
		<title>File:Gui teleport tutorial.PNG</title>
		<link rel="alternate" type="text/html" href="https://wiki.multitheftauto.com/index.php?title=File:Gui_teleport_tutorial.PNG&amp;diff=22252"/>
		<updated>2010-01-08T01:39:01Z</updated>

		<summary type="html">&lt;p&gt;R3mp: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;/div&gt;</summary>
		<author><name>R3mp</name></author>
	</entry>
	<entry>
		<id>https://wiki.multitheftauto.com/index.php?title=Category:GUI_Tutorials&amp;diff=22251</id>
		<title>Category:GUI Tutorials</title>
		<link rel="alternate" type="text/html" href="https://wiki.multitheftauto.com/index.php?title=Category:GUI_Tutorials&amp;diff=22251"/>
		<updated>2010-01-08T01:38:38Z</updated>

		<summary type="html">&lt;p&gt;R3mp: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;These are a set of tutorials with information on how to include and manipulate [[GUI widgets|GUI elements]] in your resources.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
'''Beginner Tutorials:'''&lt;br /&gt;
** [[Introduction to Scripting the GUI|Introduction to Scripting the GUI (Login Window)]]&lt;br /&gt;
** [[Introduction to Scripting the GUI - Part 2|Introduction to Scripting the GUI - Part 2 (Rules Window)]]&lt;br /&gt;
** [[Introduction to Scripting the GUI - Part 3|Introduction to Scripting the GUI - Part 3 (Teleport Window)]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
'''Novice Tutorials:'''&lt;br /&gt;
** [[Scripting the GUI - Tutorial 1|Scripting the GUI - Tutorial 1 (Gridlists)]]&lt;br /&gt;
** [[Scripting the GUI - Tutorial 2|Scripting the GUI - Tutorial 2 (Gates + Keypads)]]&lt;br /&gt;
** [[Scripting the GUI - Tutorial 3|Scripting the GUI - Tutorial 3 (Scrolling News Feed)]]&lt;/div&gt;</summary>
		<author><name>R3mp</name></author>
	</entry>
	<entry>
		<id>https://wiki.multitheftauto.com/index.php?title=Introduction_to_Scripting_the_GUI_-_Part_3&amp;diff=22250</id>
		<title>Introduction to Scripting the GUI - Part 3</title>
		<link rel="alternate" type="text/html" href="https://wiki.multitheftauto.com/index.php?title=Introduction_to_Scripting_the_GUI_-_Part_3&amp;diff=22250"/>
		<updated>2010-01-08T01:38:09Z</updated>

		<summary type="html">&lt;p&gt;R3mp: Created page with ''''Introduction to Scripting the GUI - Part 3 (Teleport Window)'''  In this tutorial we will make a simple city teleport window, with 3 buttons (one for each city) that when clic…'&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;'''Introduction to Scripting the GUI - Part 3 (Teleport Window)'''&lt;br /&gt;
&lt;br /&gt;
In this tutorial we will make a simple city teleport window, with 3 buttons (one for each city) that when clicked will teleport you to that city.&lt;br /&gt;
&lt;br /&gt;
'''Note that this tutorial builds on content covered in the [[Introduction to Scripting the GUI|GUI Scripting Introduction]].'''&lt;br /&gt;
&lt;br /&gt;
==Making the GUI==&lt;br /&gt;
&lt;br /&gt;
===Getting set up===&lt;br /&gt;
The first thing we need to do is create our GUI elements.&lt;br /&gt;
For this tutorial we will be using one [[Element/GUI/Window|window]], three [[Element/GUI/Button|buttons]] and one [[Element/GUI/Text_label|label]].&lt;br /&gt;
We will be using '''absolute''' position values.&lt;br /&gt;
&lt;br /&gt;
As noted in the [[Introduction to Scripting the GUI|Previous tutorial]], all the GUI must be made client side. &lt;br /&gt;
&lt;br /&gt;
If you are following on from that tutorial, open up your gui.lua file to work with.&lt;br /&gt;
&lt;br /&gt;
If you are not, browse to /Your MTA Server/mods/deathmatch/resources/myserver/ directory, and create a folder named &amp;quot;client&amp;quot;. &lt;br /&gt;
Under /client/ directory, create a text file and name it &amp;quot;gui.lua&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
If you have not already done so, do not forget to include the new gui.lua file in the meta.xml of the main resource, and label it as a client script:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;xml&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;script src=&amp;quot;client/gui.lua&amp;quot; type=&amp;quot;client&amp;quot; /&amp;gt;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Making the window===&lt;br /&gt;
In this file we will now write a funtion that creates the window.&lt;br /&gt;
To create a window we will use [[guiCreateWindow]]:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
-- create the function that will hold our gui creation code&lt;br /&gt;
function createTeleportWindow()&lt;br /&gt;
	-- get the screen width and height&lt;br /&gt;
	local sWidth, sHeight = guiGetScreenSize()&lt;br /&gt;
 &lt;br /&gt;
	-- create the window, using some maths to find the centre of the screen&lt;br /&gt;
	local Width,Height = 231,188&lt;br /&gt;
	local X = (sWidth/2) - (Width/2)&lt;br /&gt;
	local Y = (sHeight/2) - (Height/2)&lt;br /&gt;
 &lt;br /&gt;
	-- create the window&lt;br /&gt;
	teleportWindow = guiCreateWindow(X,Y,Width,Height,&amp;quot;City Teleporter&amp;quot;,false)&lt;br /&gt;
 &lt;br /&gt;
	-- stop players from being able to resize the window&lt;br /&gt;
	guiWindowSetSizable(teleportWindow,false)&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
This will create a basic window in the centre of the screen that cannot be resized, with the title &amp;quot;City Teleporter&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
===Making the label===&lt;br /&gt;
Next, we will add the label describing what the buttons do.&lt;br /&gt;
To create a label we will use [[guiCreateLabel]]:&lt;br /&gt;
&lt;br /&gt;
'''Note that we are now writing more code for our existing 'createTeleportWindow' function. This is not a new function and is meant to replace what you already have.'''&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
function createTeleportWindow()&lt;br /&gt;
	local sWidth, sHeight = guiGetScreenSize()&lt;br /&gt;
 &lt;br /&gt;
	local Width,Height = 231,188&lt;br /&gt;
	local X = (sWidth/2) - (Width/2)&lt;br /&gt;
	local Y = (sHeight/2) - (Height/2)&lt;br /&gt;
 &lt;br /&gt;
	teleportWindow = guiCreateWindow(X,Y,Width,Height,&amp;quot;City Teleporter&amp;quot;,false)&lt;br /&gt;
 &lt;br /&gt;
	guiWindowSetSizable(teleportWindow,false)&lt;br /&gt;
	&lt;br /&gt;
	-- create a label with our instructions on&lt;br /&gt;
	teleportLabel = guiCreateLabel(18,23,191,33,&amp;quot;Click a button to teleport to that location&amp;quot;,false,teleportWindow)&lt;br /&gt;
	&lt;br /&gt;
	-- set the horizontal alignment of the label to center (ie: in the middle of the window)&lt;br /&gt;
	-- also note the final argument &amp;quot;true&amp;quot; &lt;br /&gt;
	-- this turns on wordwrap so if your text goes over the edge of the label, it will wrap around and start a new line automatically&lt;br /&gt;
	guiLabelSetHorizontalAlign(teleportLabel,&amp;quot;center&amp;quot;,true)	&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
You will now have a simple window with some centered instructions at the top.&lt;br /&gt;
&lt;br /&gt;
===Making the buttons===&lt;br /&gt;
Now we need to add the city teleport buttons.&lt;br /&gt;
To create a button we will use [[guiCreateButton]]:&lt;br /&gt;
&lt;br /&gt;
'''Note that we are now writing more code for our existing 'createTeleportWindow' function. This is not a new function and is meant to replace what you already have.'''&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
function createTeleportWindow()&lt;br /&gt;
	local sWidth, sHeight = guiGetScreenSize()&lt;br /&gt;
 &lt;br /&gt;
	local Width,Height = 231,188&lt;br /&gt;
	local X = (sWidth/2) - (Width/2)&lt;br /&gt;
	local Y = (sHeight/2) - (Height/2)&lt;br /&gt;
 &lt;br /&gt;
	teleportWindow = guiCreateWindow(X,Y,Width,Height,&amp;quot;City Teleporter&amp;quot;,false)&lt;br /&gt;
 &lt;br /&gt;
	guiWindowSetSizable(teleportWindow,false)&lt;br /&gt;
	&lt;br /&gt;
	teleportLabel = guiCreateLabel(18,23,191,33,&amp;quot;Click a button to teleport to that location&amp;quot;,false,teleportWindow)&lt;br /&gt;
	&lt;br /&gt;
	guiLabelSetHorizontalAlign(teleportLabel,&amp;quot;center&amp;quot;,true)	&lt;br /&gt;
	&lt;br /&gt;
	-- create the button for teleporting to Los Santos&lt;br /&gt;
	teleportButtonLS = guiCreateButton(18,63,195,35,&amp;quot;Los Santos&amp;quot;,false,teleportWindow)&lt;br /&gt;
	&lt;br /&gt;
	-- slightly below that, create another button for teleporting to San Fierro&lt;br /&gt;
	teleportButtonSF = guiCreateButton(18,103,195,35,&amp;quot;San Fierro&amp;quot;,false,teleportWindow)&lt;br /&gt;
	&lt;br /&gt;
	-- slightly below that again, create another button for teleport to Las Venturas&lt;br /&gt;
	teleportButtonLV = guiCreateButton(18,143,195,35,&amp;quot;Las Venturas&amp;quot;,false,teleportWindow)	&lt;br /&gt;
	&lt;br /&gt;
	-- hide the gui&lt;br /&gt;
	guiSetVisible(teleportWindow,false)&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Using the function we wrote===&lt;br /&gt;
Now our 'createTeleportWindow' function is ready, but it wont do anything until we call it.&lt;br /&gt;
It is recommended to create all GUI when the client resource starts, hide them, and show them to the player later when needed. &lt;br /&gt;
&lt;br /&gt;
Therefore, we'll write an event handler for [[onClientResourceStart]] to create the window:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
-- add our event handler, using the root element of the resource&lt;br /&gt;
-- this means it will only trigger when its own resource is started&lt;br /&gt;
addEventHandler(&amp;quot;onClientResourceStart&amp;quot;, getResourceRootElement(getThisResource()), &lt;br /&gt;
	function ()&lt;br /&gt;
		-- call the createTeleportWindow function to create our gui&lt;br /&gt;
		createTeleportWindow()&lt;br /&gt;
	end&lt;br /&gt;
)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Now that we have our GUI created, we need a way for the players to open the window.&lt;br /&gt;
&lt;br /&gt;
===Opening the GUI===&lt;br /&gt;
There are several ways this could be done, depending on your personal preference or the particulars of the situation.&lt;br /&gt;
For this tutorial, we will use a simple [[addCommandHandler|command]].&lt;br /&gt;
&lt;br /&gt;
To open the GUI, we will use the command /teleportme :&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
-- create our function&lt;br /&gt;
function openTeleportWindow()&lt;br /&gt;
	-- show the window&lt;br /&gt;
	guiSetVisible(teleportWindow,true)&lt;br /&gt;
		&lt;br /&gt;
	-- show the mouse cursor&lt;br /&gt;
	showCursor(true,true)&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
-- define the command /teleportme to call the openTeleportWindow function&lt;br /&gt;
addCommandHandler(&amp;quot;teleportme&amp;quot;,openTeleportWindow)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Next, we need to make the buttons actually teleport the player.&lt;br /&gt;
&lt;br /&gt;
==Scripting the button==&lt;br /&gt;
&lt;br /&gt;
Now that we have created our GUI and the players are able to open it, we need to make it work. &lt;br /&gt;
&lt;br /&gt;
===Detecting the click===&lt;br /&gt;
As described in previous tutorials, when the player clicks on any part of the GUI, the event &amp;quot;onClientGUIClick&amp;quot; will be triggered for the GUI component you clicked on. &lt;br /&gt;
With that in mind, we will attach an event handler to each of our 3 teleport buttons: &lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
-- attach the event onClientGUIClick to teleportButtonLS and set it to trigger the 'teleportPlayer' function&lt;br /&gt;
addEventHandler(&amp;quot;onClientGUIClick&amp;quot;, teleportButtonLS, teleportPlayer, false)&lt;br /&gt;
&lt;br /&gt;
-- attach the event onClientGUIClick to teleportButtonSF and set it to trigger the 'teleportPlayer' function&lt;br /&gt;
addEventHandler(&amp;quot;onClientGUIClick&amp;quot;, teleportButtonSF, teleportPlayer, false)&lt;br /&gt;
&lt;br /&gt;
-- attach the event onClientGUIClick to teleportButtonLV and set it to trigger the 'teleportPlayer' function&lt;br /&gt;
addEventHandler(&amp;quot;onClientGUIClick&amp;quot;, teleportButtonLV, teleportPlayer, false)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Put this code into your 'createTeleportWindow' function, '''after''' the buttons have been created.&lt;br /&gt;
&lt;br /&gt;
Note how we have set all 3 buttons to trigger the 'teleportPlayer' function.&lt;br /&gt;
&lt;br /&gt;
This allows us to easily expand our code later on (for example, to add more teleport locations) with a simple if statement in the function.&lt;br /&gt;
&lt;br /&gt;
===Managing the clicks===&lt;br /&gt;
Now that we can detect clicks on all our buttons, we need to manage what happens when we do.&lt;br /&gt;
&lt;br /&gt;
As we just noted, we will do this using the 'teleportPlayer' function.&lt;br /&gt;
We will use if statements to check which button has been clicked, then trigger a custom server event with the specified teleport coordinates to move the player:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
-- create our function, and add button and state parameters (these are passed automatically with onClickGUIClick)&lt;br /&gt;
function teleportPlayer(button,state)&lt;br /&gt;
	-- if our button was clicked with the left mouse button, and the state of the mouse button is up&lt;br /&gt;
	if button == &amp;quot;left&amp;quot; and state == &amp;quot;up&amp;quot; then&lt;br /&gt;
		-- if the player clicked on the LS teleport button&lt;br /&gt;
		if source == teleportButtonLS then&lt;br /&gt;
		&lt;br /&gt;
			-- trigger the server with our Los Santos coordinates&lt;br /&gt;
			triggerServerEvent(&amp;quot;movePlayerToPosition&amp;quot;,getLocalPlayer(),1479.6,-1612.8,14.0,0)&lt;br /&gt;
			&lt;br /&gt;
			-- output a message to the player&lt;br /&gt;
			outputChatBox(&amp;quot;Welcome to Los Santos!&amp;quot;)&lt;br /&gt;
			&lt;br /&gt;
		-- otherwise, if the player clicked on the SF teleport button&lt;br /&gt;
		elseif source == teleportButtonSF then&lt;br /&gt;
		&lt;br /&gt;
			-- trigger the server with our San Fierro coordinates&lt;br /&gt;
			triggerServerEvent(&amp;quot;movePlayerToPosition&amp;quot;,getLocalPlayer(),-2265.5,534.0,35.0,270)&lt;br /&gt;
&lt;br /&gt;
			-- output a message to the player&lt;br /&gt;
			outputChatBox(&amp;quot;Welcome to San Fierro!&amp;quot;)&lt;br /&gt;
			&lt;br /&gt;
		-- otherwise, if the player clicked on the LV teleport button&lt;br /&gt;
		elseif source == teleportButtonLV then&lt;br /&gt;
		&lt;br /&gt;
			-- trigger the server with our Las Venturas coordinates&lt;br /&gt;
			triggerServerEvent(&amp;quot;movePlayerToPosition&amp;quot;,getLocalPlayer(),2036.9,1545.2,10.8,270)&lt;br /&gt;
&lt;br /&gt;
			-- output a message to the player&lt;br /&gt;
			outputChatBox(&amp;quot;Welcome to Las Venturas!&amp;quot;)&lt;br /&gt;
			&lt;br /&gt;
		end&lt;br /&gt;
		&lt;br /&gt;
		-- hide the window and all the components&lt;br /&gt;
		guiSetVisible(teleportWindow, false)&lt;br /&gt;
		&lt;br /&gt;
		-- hide the mouse cursor&lt;br /&gt;
		showCursor(false)		&lt;br /&gt;
	end	&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
If you wanted to add more locations, you could simply add a new button to your GUI and check for it in this function using another if statement.&lt;br /&gt;
For example:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
function teleportPlayer(button,state)&lt;br /&gt;
	if button == &amp;quot;left&amp;quot; and state == &amp;quot;up&amp;quot; then&lt;br /&gt;
		...&lt;br /&gt;
		&lt;br /&gt;
		elseif source == yourNewButton then&lt;br /&gt;
			triggerServerEvent(&amp;quot;movePlayerToPosition&amp;quot;,getLocalPlayer(),xCoord,yCoord,zCoord,rotation)&lt;br /&gt;
		end&lt;br /&gt;
		...&lt;br /&gt;
	end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Creating the serverside event===&lt;br /&gt;
At this point we now have all the code needed on the client side, &lt;br /&gt;
so open up your serverside 'script.lua' file (from the [[Scripting Introduction|Introduction to Scripting]]) or another suitable serverside file to work with.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
On the clientside, we are triggering the server event &amp;quot;movePlayerToPosition&amp;quot;. So, we will first define that event.&lt;br /&gt;
To do that we will use [[addEvent]], then [[addEventHandler]]:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
-- create our function, with the x,y and z values we passed from the client&lt;br /&gt;
function moveThePlayer(x,y,z)&lt;br /&gt;
&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
-- define our custom event, and allow it to be triggered from the client ('true')&lt;br /&gt;
addEvent(&amp;quot;movePlayerToPosition&amp;quot;,true)&lt;br /&gt;
-- add an event handler so that when movePlayerToPosition is triggered, the function moveThePlayer is called&lt;br /&gt;
addEventHandler(&amp;quot;movePlayerToPosition&amp;quot;,root,moveThePlayer)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Moving the player===&lt;br /&gt;
Now all that is left is to move the player to their new position.&lt;br /&gt;
&lt;br /&gt;
'''Note that we are now writing more code for our existing 'moveThePlayer' function. This is not a new function and is meant to replace what you already have.'''&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
-- create our function, with the x,y and z values we passed from the client&lt;br /&gt;
function moveThePlayer(x,y,z,rotation)&lt;br /&gt;
	-- check we have a position and rotation&lt;br /&gt;
	if x and y and z and rotation then&lt;br /&gt;
		-- get the players current skin, so we can spawn them again without losing it&lt;br /&gt;
		local skin = getElementModel(client)&lt;br /&gt;
		&lt;br /&gt;
		-- spawn the player&lt;br /&gt;
		spawnPlayer(client,x,y,z,rotation,skin)&lt;br /&gt;
		&lt;br /&gt;
		-- make sure the players camera is on his character&lt;br /&gt;
		setCameraTarget(client,client)&lt;br /&gt;
	end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Note the use of [[spawnPlayer]] rather than, for example, [[setElementPosition]].&lt;br /&gt;
Using [[spawnPlayer]] has several advantages, such as being able to set the position when 'de-spawned' or dead, and automatically refilling health.&lt;br /&gt;
Of course, [[setElementPosition]] would work just as well to simply move them, so the choice is yours.&lt;br /&gt;
&lt;br /&gt;
Also note the use of the variable &amp;quot;client&amp;quot;, it's an internal variable used by MTA to identify the player who triggered the event.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
At this point, you should have a basic teleport window, allowing the player to teleport to any of the 3 major cities in San Andreas.&lt;br /&gt;
&lt;br /&gt;
[[Category:GUI_Tutorials]]&lt;/div&gt;</summary>
		<author><name>R3mp</name></author>
	</entry>
	<entry>
		<id>https://wiki.multitheftauto.com/index.php?title=Category:GUI_Tutorials&amp;diff=22244</id>
		<title>Category:GUI Tutorials</title>
		<link rel="alternate" type="text/html" href="https://wiki.multitheftauto.com/index.php?title=Category:GUI_Tutorials&amp;diff=22244"/>
		<updated>2010-01-06T11:57:11Z</updated>

		<summary type="html">&lt;p&gt;R3mp: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;These are a set of tutorials with information on how to include and manipulate [[GUI widgets|GUI elements]] in your resources.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
'''Beginner Tutorials:'''&lt;br /&gt;
** [[Introduction to Scripting the GUI|Introduction to Scripting the GUI (Login Window)]]&lt;br /&gt;
** [[Introduction to Scripting the GUI - Part 2|Introduction to Scripting the GUI - Part 2 (Rules Window)]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
'''Novice Tutorials:'''&lt;br /&gt;
** [[Scripting the GUI - Tutorial 1|Scripting the GUI - Tutorial 1 (Gridlists)]]&lt;br /&gt;
** [[Scripting the GUI - Tutorial 2|Scripting the GUI - Tutorial 2 (Gates + Keypads)]]&lt;br /&gt;
** [[Scripting the GUI - Tutorial 3|Scripting the GUI - Tutorial 3 (Scrolling News Feed)]]&lt;/div&gt;</summary>
		<author><name>R3mp</name></author>
	</entry>
	<entry>
		<id>https://wiki.multitheftauto.com/index.php?title=Category:GUI_Tutorials&amp;diff=22199</id>
		<title>Category:GUI Tutorials</title>
		<link rel="alternate" type="text/html" href="https://wiki.multitheftauto.com/index.php?title=Category:GUI_Tutorials&amp;diff=22199"/>
		<updated>2010-01-06T01:23:55Z</updated>

		<summary type="html">&lt;p&gt;R3mp: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;These are a set of tutorials with information on how to include and manipulate [[GUI widgets|GUI elements]] in your resources.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
'''Beginner Tutorials:'''&lt;br /&gt;
** [[Introduction to Scripting the GUI]]&lt;br /&gt;
** [[Introduction to Scripting the GUI - Part 2]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
'''Novice Tutorials:'''&lt;br /&gt;
** [[Scripting the GUI - Tutorial 1|Scripting the GUI - Tutorial 1 (Gridlists)]]&lt;br /&gt;
** [[Scripting the GUI - Tutorial 2|Scripting the GUI - Tutorial 2 (Gates + Keypads)]]&lt;br /&gt;
** [[Scripting the GUI - Tutorial 3|Scripting the GUI - Tutorial 3 (Scrolling News Feed)]]&lt;/div&gt;</summary>
		<author><name>R3mp</name></author>
	</entry>
	<entry>
		<id>https://wiki.multitheftauto.com/index.php?title=Introduction_to_Scripting_the_GUI_-_Part_2&amp;diff=22198</id>
		<title>Introduction to Scripting the GUI - Part 2</title>
		<link rel="alternate" type="text/html" href="https://wiki.multitheftauto.com/index.php?title=Introduction_to_Scripting_the_GUI_-_Part_2&amp;diff=22198"/>
		<updated>2010-01-06T01:06:14Z</updated>

		<summary type="html">&lt;p&gt;R3mp: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;In this tutorial we will make a simple rules window, with an accept button and a list of all the server rules &amp;amp; information.&lt;br /&gt;
&lt;br /&gt;
'''Note that this tutorial builds on content covered in the [[Introduction to Scripting the GUI|GUI Scripting Introduction]].'''&lt;br /&gt;
&lt;br /&gt;
==Making the GUI==&lt;br /&gt;
&lt;br /&gt;
===Getting set up===&lt;br /&gt;
The first thing we need to do is create our GUI elements.&lt;br /&gt;
For this tutorial we will be using one [[Element/GUI/Window|window]], one [[Element/GUI/Button|button]] and one [[Element/GUI/Text_label|label]].&lt;br /&gt;
We will be using '''absolute''' position values.&lt;br /&gt;
&lt;br /&gt;
As noted in the [[Introduction to Scripting the GUI|Previous tutorial]], all the GUI must be made client side. &lt;br /&gt;
&lt;br /&gt;
If you are following on from that tutorial, open up your gui.lua file to work with.&lt;br /&gt;
&lt;br /&gt;
If you are not, browse to /Your MTA Server/mods/deathmatch/resources/myserver/ directory, and create a folder named &amp;quot;client&amp;quot;. &lt;br /&gt;
Under /client/ directory, create a text file and name it &amp;quot;gui.lua&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
If you have not already done so, do not forget to include the new gui.lua file in the meta.xml of the main resource, and label it as a client script:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;xml&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;script src=&amp;quot;client/gui.lua&amp;quot; type=&amp;quot;client&amp;quot; /&amp;gt;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Making the window===&lt;br /&gt;
In this file we will write a funtion that draws the window:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
-- create the function that will hold our gui creation code&lt;br /&gt;
function createRulesWindow()&lt;br /&gt;
	-- get the screen width and height&lt;br /&gt;
	local sWidth, sHeight = guiGetScreenSize()&lt;br /&gt;
 &lt;br /&gt;
	-- create the window, using some maths to find the centre of the screen&lt;br /&gt;
	local Width,Height = 445,445&lt;br /&gt;
	local X = (sWidth/2) - (Width/2)&lt;br /&gt;
	local Y = (sHeight/2) - (Height/2)&lt;br /&gt;
&lt;br /&gt;
	-- create the window&lt;br /&gt;
	rulesWindow = guiCreateWindow(X,Y,Width,Height,&amp;quot;Rules&amp;quot;,false)&lt;br /&gt;
	&lt;br /&gt;
	-- stop players from being able to simply move the window out of the way&lt;br /&gt;
	guiWindowSetMovable(rulesWindow,false)&lt;br /&gt;
	&lt;br /&gt;
	-- stop players from being able to resize the window&lt;br /&gt;
	guiWindowSetSizable(rulesWindow,false)&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
This will create a basic window in the centre of the screen that cannot be moved and cannot be resized.&lt;br /&gt;
&lt;br /&gt;
===Making the button===&lt;br /&gt;
Next, we will add the button to the bottom of our window that players can click on to accept the rules:&lt;br /&gt;
&lt;br /&gt;
'''Note that we are now writing more code for our existing 'createRulesWindow' function. This is not a new function and is meant to replace what you already have.'''&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
function createRulesWindow()&lt;br /&gt;
	-- get the screen width and height&lt;br /&gt;
	local sWidth, sHeight = guiGetScreenSize()&lt;br /&gt;
 &lt;br /&gt;
	-- create the window, using some maths to find the centre of the screen&lt;br /&gt;
	local Width,Height = 445,445&lt;br /&gt;
	local X = (sWidth/2) - (Width/2)&lt;br /&gt;
	local Y = (sHeight/2) - (Height/2)&lt;br /&gt;
&lt;br /&gt;
	-- create the window and save the window gui element in a variable called 'rulesWindow'&lt;br /&gt;
	rulesWindow = guiCreateWindow(X,Y,Width,Height,&amp;quot;Rules&amp;quot;,false)&lt;br /&gt;
	&lt;br /&gt;
	-- stop players from being able to simply move the window out of the way&lt;br /&gt;
	-- note that we use our 'rulesWindow' variable to make changes to the window&lt;br /&gt;
	guiWindowSetMovable(rulesWindow,false)&lt;br /&gt;
	&lt;br /&gt;
	-- stop players from being able to resize the window&lt;br /&gt;
	guiWindowSetSizable(rulesWindow,false)&lt;br /&gt;
	&lt;br /&gt;
	-- create the button and save the button gui element in a variable called 'rulesButton'&lt;br /&gt;
	rulesButton = guiCreateButton(137,394,158,37,&amp;quot;Accept&amp;quot;,false,rulesWindow)&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Making the label===&lt;br /&gt;
Next, we will add the label to the centre of our window that our rules will be displayed on:&lt;br /&gt;
&lt;br /&gt;
'''Note that we are now writing more code for our existing 'createRulesWindow' function. This is not a new function and is meant to replace what you already have.'''&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
function createRulesWindow()&lt;br /&gt;
	-- get the screen width and height&lt;br /&gt;
	local sWidth, sHeight = guiGetScreenSize()&lt;br /&gt;
 &lt;br /&gt;
	-- create the window, using some maths to find the centre of the screen&lt;br /&gt;
	local Width,Height = 445,445&lt;br /&gt;
	local X = (sWidth/2) - (Width/2)&lt;br /&gt;
	local Y = (sHeight/2) - (Height/2)&lt;br /&gt;
&lt;br /&gt;
	-- create the window and save the window gui element in a variable called 'rulesWindow'&lt;br /&gt;
	rulesWindow = guiCreateWindow(X,Y,Width,Height,&amp;quot;Rules&amp;quot;,false)&lt;br /&gt;
	&lt;br /&gt;
	-- stop players from being able to simply move the window out of the way&lt;br /&gt;
	-- note that we use our 'rulesWindow' variable to make changes to the window&lt;br /&gt;
	guiWindowSetMovable(rulesWindow,false)&lt;br /&gt;
	&lt;br /&gt;
	-- stop players from being able to resize the window&lt;br /&gt;
	guiWindowSetSizable(rulesWindow,false)&lt;br /&gt;
	&lt;br /&gt;
	-- create the button and save the button gui element in a variable called 'rulesButton'&lt;br /&gt;
	rulesButton = guiCreateButton(137,394,158,37,&amp;quot;Accept&amp;quot;,false,rulesWindow)&lt;br /&gt;
	&lt;br /&gt;
	-- create the label and save the label gui element in a variable called 'rulesLabel'&lt;br /&gt;
	-- we set the text of the label to our rules&lt;br /&gt;
	rulesLabel = guiCreateLabel(10,25,425,359,[[&lt;br /&gt;
	Welcome to my MTA Server!&lt;br /&gt;
&lt;br /&gt;
	Please carefully read the rules before accepting.&lt;br /&gt;
&lt;br /&gt;
	By accepting the rules, you are agreeing to play by them.&lt;br /&gt;
	Anyone caught breaking these rules will be kicked and/or banned from this server.&lt;br /&gt;
&lt;br /&gt;
	If you do not accept the rules within 90 seconds, you will be kicked.&lt;br /&gt;
&lt;br /&gt;
	1: No cheating.&lt;br /&gt;
&lt;br /&gt;
	2: No bug abuse.&lt;br /&gt;
&lt;br /&gt;
	3: No mods to your game.&lt;br /&gt;
&lt;br /&gt;
	4: No flaming.&lt;br /&gt;
&lt;br /&gt;
	5: Respect other players.&lt;br /&gt;
&lt;br /&gt;
	6: Be nice!]],false,rulesWindow)&lt;br /&gt;
	&lt;br /&gt;
	-- set the horizontal alignment of the label to center (ie: in the middle of the window)&lt;br /&gt;
	-- also note the final argument &amp;quot;true&amp;quot; &lt;br /&gt;
	-- this turns on wordwrap so if your text goes over the edge of the label, it will wrap around and start a new line automatically&lt;br /&gt;
	guiLabelSetHorizontalAlign(rulesLabel,&amp;quot;center&amp;quot;,true)	&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
''Note that the text is added in a different way to usual (we are not using quotation marks, &amp;quot;&amp;quot;).''&lt;br /&gt;
&lt;br /&gt;
===Text===&lt;br /&gt;
There are ''two'' ways to define text for a label.&lt;br /&gt;
For most situations, the recommended method is to enter all your text between quotation marks:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
guiSetText(guiElement,&amp;quot;My text here&amp;quot;)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
However, when we want to have more than 1 line in our text, it becomes just as easy to use the second method. &lt;br /&gt;
It is purely dependant on situation and personal choice which method you chose.&lt;br /&gt;
For clarity's sake, i will briefly outline both here.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
When using quotation marks, we can make use of the newline character: &amp;quot;\n&amp;quot;&lt;br /&gt;
This allows us to break onto a new line in our text by entering &amp;quot;\n&amp;quot;. For example:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
guiSetText(guiElement,&amp;quot;This is line 1. \n This is line 2. \n This is line 3.&amp;quot;)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
However, if we use brackets to enclose the text instead of quotation marks, we do not need to worry about entering any extra characters.&lt;br /&gt;
We can simply type the text out as we want it to appear in the label. For example:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
guiSetText(guiElement,[[This is line 1.&lt;br /&gt;
This is line 2.&lt;br /&gt;
This is line 3.]])&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Both of these examples will create exactly the same text on the label.&lt;br /&gt;
It is entirely up to you which method you chose to use.&lt;br /&gt;
&lt;br /&gt;
===Using the function we wrote===&lt;br /&gt;
The createRulesWindow function is now complete, but it won't do anything until we call it. &lt;br /&gt;
It is recommended to create all GUI when the client resource starts, hide them, and show them to the player later when needed. &lt;br /&gt;
&lt;br /&gt;
Therefore, we'll write an event handler for [[onClientResourceStart]] to create the window:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
-- attach the event handler to the root element of the resource&lt;br /&gt;
-- this means it will only trigger when its own resource is started&lt;br /&gt;
addEventHandler(&amp;quot;onClientResourceStart&amp;quot;, getResourceRootElement(getThisResource()), &lt;br /&gt;
	function ()&lt;br /&gt;
		-- call the createRulesWindow function to create our gui&lt;br /&gt;
		createRulesWindow()&lt;br /&gt;
	end&lt;br /&gt;
)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
As this is a rules window, we need to show the window when the player joins the game. &lt;br /&gt;
Fortunately, GUI elements are visible by default so we do not need to write any more code to achieve this.&lt;br /&gt;
&lt;br /&gt;
However, we will also need to show the cursor for the player. &lt;br /&gt;
This can be done using the same event, [[onClientResourceStart]], so we can modify the above code to include showing the cursor:&lt;br /&gt;
&lt;br /&gt;
'''Note that we are now writing more code for our 'onClientResourceStart' event. This is not a new function and is meant to replace what you already have.'''&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
-- attach the event handler to the root element of the resource&lt;br /&gt;
-- this means it will only trigger when its own resource is started&lt;br /&gt;
addEventHandler(&amp;quot;onClientResourceStart&amp;quot;, getResourceRootElement(getThisResource()), &lt;br /&gt;
	function ()&lt;br /&gt;
		-- call the createRulesWindow function to create our gui&lt;br /&gt;
		createRulesWindow()&lt;br /&gt;
		&lt;br /&gt;
		-- show the cursor to the player&lt;br /&gt;
		showCursor(true,true)&lt;br /&gt;
	end&lt;br /&gt;
)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
We now have a completed GUI rules window. Next, we need to write the button functionality for the accept button.&lt;br /&gt;
&lt;br /&gt;
==Scripting the Button==&lt;br /&gt;
Now that we have created our GUI, we need to make it work.&lt;br /&gt;
&lt;br /&gt;
===Detecting the click===&lt;br /&gt;
When the player clicks on any part of the GUI, the event &amp;quot;[[onClientGUIClick]]&amp;quot; will be triggered for the GUI component you clicked on. This allows us to easily detect any clicks on the GUI elements we want to use.&lt;br /&gt;
For example, we can attach the event to the 'rulesButton' button to catch any clicks on it:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
-- attach the event onClientGUIClick to rulesButton and set it to trigger the 'acceptRules' function&lt;br /&gt;
addEventHandler(&amp;quot;onClientGUIClick&amp;quot;, rulesButton, acceptRules, false)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
'''Note the final argument passed is &amp;quot;false&amp;quot;. This indicates that the event will only trigger directly on rulesButton, not if the event has propagated up or down the tree. Setting this to &amp;quot;true&amp;quot; while attaching to gui elements will mean that clicking on any element in the same branch will trigger this event.'''&lt;br /&gt;
&lt;br /&gt;
This line of code can now be added inside the 'createRulesWindow' function. It is a common mistake to try and attach events to non-existant GUI elements, so make sure you always attach your events '''after''' the GUI element (in this case, the button) has been created:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
function createRulesWindow()&lt;br /&gt;
	-- create all our GUI elements&lt;br /&gt;
	...&lt;br /&gt;
&lt;br /&gt;
	-- now add our onClientGUIClick event to the button we just created&lt;br /&gt;
	addEventHandler(&amp;quot;onClientGUIClick&amp;quot;, rulesButton, acceptRules, false)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Managing the click===&lt;br /&gt;
Now that we can detect when the player clicks on the button, we need to write code to manage what happens when they do.&lt;br /&gt;
In our [[onClientGUIClick]] event handle, we told it to call the function 'acceptRules' whenever 'rulesButton' is clicked.&lt;br /&gt;
Therefore, we can now use the function 'acceptRules' to control what happens when the button is clicked:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
-- create the function and define the 'button' and 'state' parameters&lt;br /&gt;
-- (these are passed automatically by onClientGUIClick)&lt;br /&gt;
function acceptRules(button,state)&lt;br /&gt;
	-- if our accept button was clicked with the left mouse button, and the state of the mouse button is up&lt;br /&gt;
	if button == &amp;quot;left&amp;quot; and state == &amp;quot;up&amp;quot; then&lt;br /&gt;
		-- hide the window and all the components&lt;br /&gt;
		guiSetVisible(rulesWindow, false)&lt;br /&gt;
		&lt;br /&gt;
		-- hide the mouse cursor&lt;br /&gt;
		showCursor(false,false)&lt;br /&gt;
		&lt;br /&gt;
		-- output a message to the player&lt;br /&gt;
		outputChatBox(&amp;quot;Thank you for accepting our rules. Have fun!&amp;quot;)&lt;br /&gt;
		&lt;br /&gt;
		&lt;br /&gt;
		-- if the warning timer exists&lt;br /&gt;
		if rulesWarningTimer then&lt;br /&gt;
			-- stop the timer and set the variable to nil&lt;br /&gt;
			-- this is the timer used to kick players who do not accept the rules. We will cover this in more detail in the next section.&lt;br /&gt;
			killTimer(rulesWarningTimer)&lt;br /&gt;
			rulesWarningTimer = nil&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Now, when the button is clicked, the window and the cursor will be hidden.&lt;br /&gt;
&lt;br /&gt;
==Checking for agreement==&lt;br /&gt;
Currently, our window will show when the player joins the server, and they must click accept to remove it.&lt;br /&gt;
However, if they do not accept it they can stay in the server indefinately with the window open.&lt;br /&gt;
&lt;br /&gt;
===Setting a timer===&lt;br /&gt;
To combat this, we will add a timer using [[setTimer]] to kick them from the server after a period of time if they have not accepted the rules.&lt;br /&gt;
First, we will need a global variable to store the timer pointer:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
local rulesWarningTimer = nil&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Put this line at the very top of your script (it does not need to be inside a function)&lt;br /&gt;
&lt;br /&gt;
Next, we will create our timer:&lt;br /&gt;
&lt;br /&gt;
'''Note that we are now writing more code for our existing 'createRulesWindow' function.'''&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
function createRulesWindow()&lt;br /&gt;
	-- create all of our gui&lt;br /&gt;
	...&lt;br /&gt;
	&lt;br /&gt;
	-- set a timer for 30 seconds and set it to call our 'inactivePlayer' function with &amp;quot;1&amp;quot; as an argument&lt;br /&gt;
	rulesWarningTimer = setTimer(inactivePlayer,30000,1,1)&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Put this [[setTimer]] line at the bottom of your 'createRulesWindow' function.&lt;br /&gt;
This will create a timer that will trigger after 30 seconds.&lt;br /&gt;
&lt;br /&gt;
===Giving a warning===&lt;br /&gt;
Now we will write our 'inactivePlayer' function, to administer warnings to the player and finally kick him if he does not accept:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
-- create our function and define the 'status' parameter&lt;br /&gt;
-- the value of status will be passed from our setTimer function call&lt;br /&gt;
function inactivePlayer(status)&lt;br /&gt;
	-- if status is 1 (this means it is the first warning)&lt;br /&gt;
	if status == 1 then&lt;br /&gt;
		-- output a warning&lt;br /&gt;
		outputChatBox(&amp;quot;Please accept our rules or be kicked.&amp;quot;)&lt;br /&gt;
		&lt;br /&gt;
		-- set another timer to call inactivePlayer in another 30 seconds, with &amp;quot;2&amp;quot; as an argument&lt;br /&gt;
		rulesWarningTimer = setTimer(inactivePlayer,30000,1,2)&lt;br /&gt;
		&lt;br /&gt;
	-- if status is 2 (the second warning)&lt;br /&gt;
	elseif status == 2 then&lt;br /&gt;
		-- output a final warning&lt;br /&gt;
		outputChatBox(&amp;quot;FINAL WARNING: Please accept our rules or be kicked.&amp;quot;)&lt;br /&gt;
		&lt;br /&gt;
		-- set a final timer to call inactivePlayer in another 30 seconds, with &amp;quot;3&amp;quot; as an argument&lt;br /&gt;
		rulesWarningTimer = setTimer(inactivePlayer,30000,1,3)	&lt;br /&gt;
	elseif status == 3 then&lt;br /&gt;
		-- trigger the server so we can kick the player&lt;br /&gt;
		triggerServerEvent(&amp;quot;clientKickInactivePlayer&amp;quot;,getLocalPlayer())&lt;br /&gt;
	end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Note the use of [[triggerServerEvent]] to call the server. You should have experience with client-server interaction from the [[Introduction to Scripting the GUI|Previous tutorial]]. &lt;br /&gt;
If not, you can go back and read the full explanation there.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
We have now completed all the clientside code for this tutorial.&lt;br /&gt;
&lt;br /&gt;
===Kicking the player===&lt;br /&gt;
We now need to catch the event on the server that we triggered from the client, so open up a serverside lua file to work with.&lt;br /&gt;
&lt;br /&gt;
To begin, we will add the event on the server:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
-- add the event, note the final argument &amp;quot;true&amp;quot; indicates it can be triggered from the client&lt;br /&gt;
addEvent(&amp;quot;clientKickInactivePlayer&amp;quot;,true)&lt;br /&gt;
-- add an event handler for this event to trigger the kickInactivePlayer function&lt;br /&gt;
addEventHandler(&amp;quot;clientKickInactivePlayer&amp;quot;,root,kickInactivePlayer)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
'''Make sure you add your event handler after you have defined your 'kickInactivePlayer' function.'''&lt;br /&gt;
&lt;br /&gt;
Note the use of [[addEvent]] and [[addEventHandler]] on the server. You should have experience with client-server interaction from the [[Introduction to Scripting the GUI|Previous tutorial]]. &lt;br /&gt;
If not, you can go back and read the full explanation there.&lt;br /&gt;
&lt;br /&gt;
Finally, we will add the 'kickInactivePlayer' function to control kicking of the player:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
-- create our function&lt;br /&gt;
function kickInactivePlayer()&lt;br /&gt;
	-- kick the player&lt;br /&gt;
	kickPlayer(client,&amp;quot;Please accept our rules.&amp;quot;)&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Note the use of the 'client' variable, this is an MTA variable that holds the value of the client (player) that triggered the event.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
'''Note that [[kickPlayer]] will require your resource to have kick access in your ACL.'''&lt;br /&gt;
&lt;br /&gt;
'''This is most easily accomplished by adding your resource into your admin group in the ACL:'''&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;xml&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;group name=&amp;quot;Admin&amp;quot;&amp;gt;&lt;br /&gt;
	...&lt;br /&gt;
    &amp;lt;object name=&amp;quot;resource.YourResourceName&amp;quot; /&amp;gt;&lt;br /&gt;
	...&lt;br /&gt;
&amp;lt;/group&amp;gt;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
For more information on the [[ACL]], see the [[ACL]] wiki page.&lt;br /&gt;
&lt;br /&gt;
That concludes this tutorial. You should now have a fully working rules window for your server.&lt;br /&gt;
&lt;br /&gt;
[[Category:GUI_Tutorials]]&lt;/div&gt;</summary>
		<author><name>R3mp</name></author>
	</entry>
	<entry>
		<id>https://wiki.multitheftauto.com/index.php?title=Scripting_the_GUI_-_Tutorial_3&amp;diff=22197</id>
		<title>Scripting the GUI - Tutorial 3</title>
		<link rel="alternate" type="text/html" href="https://wiki.multitheftauto.com/index.php?title=Scripting_the_GUI_-_Tutorial_3&amp;diff=22197"/>
		<updated>2010-01-06T01:04:29Z</updated>

		<summary type="html">&lt;p&gt;R3mp: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;'''Scripting the GUI - Tutorial 3 (Scrolling News Feed)'''&lt;br /&gt;
&lt;br /&gt;
In this tutorial we will explore how to create a simple scrolling news feed GUI, &lt;br /&gt;
allowing you to quickly and easily show server updates and other server information to your players.&lt;br /&gt;
We will store all news items in a clientside xml file and use some simple xml reading to load them into the game.&lt;br /&gt;
&lt;br /&gt;
We will then animate the news item to scroll along the bottom of the screen, updating the news text once it has scrolled beyond the edge of the screen.&lt;br /&gt;
&lt;br /&gt;
'''Note that this tutorial assumes you are familiar with all the content covered in the [[Introduction to Scripting GUI|GUI Scripting Introduction]].'''&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Setting up the News Feed==&lt;br /&gt;
To begin, open up a clientside lua file (if you have been following the [[Introduction to Scripting GUI|GUI Scripting Introduction]], this is gui.lua) to work with.&lt;br /&gt;
&lt;br /&gt;
===Creating the GUI===&lt;br /&gt;
As with the previous tutorial, you should be suitably familiar with GUI creation already so we will not go into too much detail here. &lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
function createNewsFeed()&lt;br /&gt;
	-- get the screen width and height&lt;br /&gt;
	local sWidth, sHeight = guiGetScreenSize()&lt;br /&gt;
 &lt;br /&gt;
	-- create the gridlist, using some maths to find the bottom-centre of the screen&lt;br /&gt;
	local Width,Height = 800,45&lt;br /&gt;
	local X = (sWidth/2) - (Width/2)&lt;br /&gt;
	local Y = sHeight - (Height/2)&lt;br /&gt;
	&lt;br /&gt;
	-- the gridlist will act as the background to our news reel&lt;br /&gt;
	newsGridlist = guiCreateGridList(X,Y,Width,Height,false)&lt;br /&gt;
	&lt;br /&gt;
	-- create the label in the same place, but as a child of the gridlist&lt;br /&gt;
	-- also make it half the height of the gridlist, as half of the gridlist is off the bottom of the screen&lt;br /&gt;
	newsLabel = guiCreateLabel(X,Y,Width,Height/2,&amp;quot;Test text&amp;quot;,false,newsGridlist)&lt;br /&gt;
	&lt;br /&gt;
	-- call our function to read the news out of the xml file&lt;br /&gt;
	loadNews()&lt;br /&gt;
	&lt;br /&gt;
	-- load the first news item in the table&lt;br /&gt;
	updateNewsItem(1)&lt;br /&gt;
	&lt;br /&gt;
	-- define a global variable called 'currentItem' with the value 1&lt;br /&gt;
	currentItem = 1&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
addEventHandler(&amp;quot;onClientResourceStart&amp;quot;,resourceRoot,createNewsFeed)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Note that the label is created as a child of the gridlist. &lt;br /&gt;
Not only is this good practice in general, but it means that we can freely move parts of the label beyond the edge of the gridlist without them showing, which is critical to the visual effect of this tutorial.&lt;br /&gt;
&lt;br /&gt;
Also notice the use of the 'resourceRoot' variable. This is an MTA variable that holds the root element value of the resource you are using it in.&lt;br /&gt;
&lt;br /&gt;
The 'currentItem' variable is what we will use to keep track of which news item we are currently showing&lt;br /&gt;
&lt;br /&gt;
===Writing the News===&lt;br /&gt;
Now that we have our GUI created, we need some news to fill it with.&lt;br /&gt;
To do this, we will read our news items out of a clientside xml file.&lt;br /&gt;
&lt;br /&gt;
So, navigate to your resource directory and create a new xml file called newsfeed.xml (don't forget to add it to your meta.xml with the appropriate client tag).&lt;br /&gt;
&lt;br /&gt;
Inside this file enter the following information:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;root&amp;gt;&lt;br /&gt;
	&amp;lt;news&amp;gt;This is an example news item.&amp;lt;/news&amp;gt;&lt;br /&gt;
	&amp;lt;news&amp;gt;From the 'Scripting the GUI' tutorial.&amp;lt;/news&amp;gt;&lt;br /&gt;
	&amp;lt;news&amp;gt;Showing scrolling news text.&amp;lt;/news&amp;gt;&lt;br /&gt;
	&amp;lt;news&amp;gt;Written on a GUI news feed.&amp;lt;/news&amp;gt;&lt;br /&gt;
&amp;lt;/root&amp;gt;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
As you can see, each news item is defined as a &amp;lt;news&amp;gt; node with the value being the news text you want to display.&lt;br /&gt;
There is no limit on how many news items you can add.&lt;br /&gt;
&lt;br /&gt;
===Collecting the News===&lt;br /&gt;
Once we have written all our news items, we will need to collect them all and store them in a table on the client.&lt;br /&gt;
We will do this when the resource starts, saving us from having to repeatedly access the xml for new news items.&lt;br /&gt;
&lt;br /&gt;
First, we need to define a table to store the items in:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
local newsItems = {}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Add this line to the top of your script.&lt;br /&gt;
Make sure it is not inside a function otherwise it will not exist outside of that function (as denoted by the prefix &amp;quot;local&amp;quot;).&lt;br /&gt;
When defined in the main body of the script it will exist in all functions.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Next, we will need to load the xml file:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
function loadNews()&lt;br /&gt;
	-- load our &amp;quot;newsfeed.xml&amp;quot; file&lt;br /&gt;
	local newsfile = xmlLoadFile(&amp;quot;newsfeed.xml&amp;quot;)&lt;br /&gt;
	&lt;br /&gt;
	-- if it was successfully loaded&lt;br /&gt;
	if newsfile then&lt;br /&gt;
	&lt;br /&gt;
		-- always remember to unload files once you are finished&lt;br /&gt;
		xmlUnloadFile(newsfile)&lt;br /&gt;
	end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
'''Always remember to unload files once you are finished using them.'''&lt;br /&gt;
&lt;br /&gt;
Finally, we can add some more code to our loadNews function to read the news items into our newsItems table:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
function loadNews()&lt;br /&gt;
	local newsfile = xmlLoadFile(&amp;quot;newsfeed.xml&amp;quot;)&lt;br /&gt;
	&lt;br /&gt;
	if newsfile then&lt;br /&gt;
		-- loop through all the children of the root node (the &amp;quot;news&amp;quot; nodes)&lt;br /&gt;
		for index,itemNode in ipairs(xmlNodeGetChildren(newsfile)) do&lt;br /&gt;
			-- get the text (the news item) from the node&lt;br /&gt;
			local item = xmlNodeGetValue(itemNode)&lt;br /&gt;
			&lt;br /&gt;
			-- insert it into our newsItems table&lt;br /&gt;
			table.insert(newsItems,item)&lt;br /&gt;
		end&lt;br /&gt;
	&lt;br /&gt;
		xmlUnloadFile(newsfile)&lt;br /&gt;
	end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
We now have a table called 'newsItems' holding all of our news text from the xml file.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Updating the News==&lt;br /&gt;
Now that we have our GUI created and our news items ready, we need to write some code to update the news item being shown to players.&lt;br /&gt;
As stated earlier, our news items will be shown on our 'newsLabel' GUI label.&lt;br /&gt;
&lt;br /&gt;
To do this, we will write a simple function to get the next news item from our 'newsItems' table and display it in our label.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
-- define our function with a newIndex parameter, so that we can pass which news item we want to show&lt;br /&gt;
function updateNewsItem(newIndex)&lt;br /&gt;
	-- get the new news item from the table&lt;br /&gt;
	local item = newsItems[newIndex]&lt;br /&gt;
	&lt;br /&gt;
	-- update the label text&lt;br /&gt;
	guiSetText(newsLabel,item)&lt;br /&gt;
	&lt;br /&gt;
	-- update the 'currentItem' global variable&lt;br /&gt;
	currentItem = newIndex&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Sizing the Label===&lt;br /&gt;
To make our news scrolling as accurate as possible, we need to be able to make the GUI label the same size as the news item text it is showing.&lt;br /&gt;
&lt;br /&gt;
While this may seem like a tricky thing to do, it is made very easy with the function [[guiLabelGetTextExtent]].&lt;br /&gt;
This will tell us the extent, or width, of the text currently shown in our label.&lt;br /&gt;
So with a few modifications to our 'updateNewsItems' function, we get:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
function updateNewsItem(newIndex)&lt;br /&gt;
	local item = newsItems[newIndex]&lt;br /&gt;
	&lt;br /&gt;
	guiSetText(newsLabel,item)&lt;br /&gt;
	&lt;br /&gt;
	currentItem = newIndex&lt;br /&gt;
	&lt;br /&gt;
	-- get the current dimensions of the gui label&lt;br /&gt;
	local width,height = guiGetSize(newsLabel,false)&lt;br /&gt;
	&lt;br /&gt;
	-- get the text width of the label&lt;br /&gt;
	local extent = guiLabelGetTextExtent(newsLabel)&lt;br /&gt;
	&lt;br /&gt;
	-- update the size of the label with the new width (we do not change the height)&lt;br /&gt;
	guiSetSize(newsLabel,extent,height,false)&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Positioning the Label===&lt;br /&gt;
Now that our GUI label is the correct width, we need to move it to a position where it is ready to scroll onto the screen.&lt;br /&gt;
&lt;br /&gt;
Again, we can do this with a small modification to our 'updateNewsItems' function:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
function updateNewsItem(newIndex)&lt;br /&gt;
	local item = newsItems[newIndex]&lt;br /&gt;
	&lt;br /&gt;
	guiSetText(newsLabel,item)&lt;br /&gt;
	&lt;br /&gt;
	currentItem = newIndex&lt;br /&gt;
	&lt;br /&gt;
	local width,height = guiGetSize(newsLabel,false)&lt;br /&gt;
	&lt;br /&gt;
	local extent = guiLabelGetTextExtent(newsLabel)&lt;br /&gt;
	&lt;br /&gt;
	guiSetSize(newsLabel,extent,height,false)&lt;br /&gt;
	&lt;br /&gt;
	-- set the positon to the far right side of the gridlist, ready to scroll on to the left&lt;br /&gt;
	guiSetPosition(newsLabel,1,0,true)&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Note the use of '''relative''' position values in the final line of the function. &lt;br /&gt;
&lt;br /&gt;
In this case, it is far easier than calculating pixel values.&lt;br /&gt;
&lt;br /&gt;
You can use both relative and absolute in the same script if you want to, the only limitation is that you cannot mix them in the same function call. The type of values you are using is defined by the final argument (true or false).&lt;br /&gt;
 &lt;br /&gt;
This means you cannot do the following and have it set to 400 pixels in, but 0.5% down&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
guiSetPosition(yourElement,400,0.5,false)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
The final argument &amp;quot;false&amp;quot; means both 400 and 0.5 will be read as pixel values.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Scrolling the News==&lt;br /&gt;
The next step is to animate our news feed.&lt;br /&gt;
&lt;br /&gt;
===Looking at Frames===&lt;br /&gt;
To do this, we will introduce a new event: [[onClientRender]].&lt;br /&gt;
As stated on the [[onClientRender]] wiki page, this event is called every time GTA renders a new frame (ie: very often).&lt;br /&gt;
&lt;br /&gt;
As usual, to use this event we will need to create an event handler for it:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
addEventHandler(&amp;quot;onClientRender&amp;quot;,root,scrollNews)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
This will call our scrollNews function every frame, which we will then use to update the position of our news item.&lt;br /&gt;
&lt;br /&gt;
'''Make sure you add this handler after you have defined your scrollNews function.'''&lt;br /&gt;
&lt;br /&gt;
For our purposes, [[onClientRender]] has one main advantage over, for example, [[setTimer]].&lt;br /&gt;
As it is called every frame (and therefore is dependant on the players FPS), the movement of the news item will always appear to be completely smooth,&lt;br /&gt;
unlike using a timer which would often appear to lag.&lt;br /&gt;
&lt;br /&gt;
===Moving the News===&lt;br /&gt;
In our 'updateNewsItem' function, we position the 'newsLabel' to the far right, so we will scroll in from the right to the left.&lt;br /&gt;
&lt;br /&gt;
For this we will simply move the X position by -1 every frame:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
function scrollNews()&lt;br /&gt;
	-- if the newsLabel exists&lt;br /&gt;
	if newsLabel then&lt;br /&gt;
		-- get the current position of the label&lt;br /&gt;
		local x,y = guiGetPosition(newsLabel,false)&lt;br /&gt;
		&lt;br /&gt;
		-- set the new x position of the label as the old position -1&lt;br /&gt;
		guiSetPosition(newsLabel,x-1,y,false)&lt;br /&gt;
	end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Looping around===&lt;br /&gt;
Now that our news scrolls across the screen, we need to be able to check when it has scrolled too far to the left&lt;br /&gt;
so we can start scrolling from the far-right side again.&lt;br /&gt;
&lt;br /&gt;
We will also need to update the news item, so we should check the next item exists, and if it doesn't, go back to the first.&lt;br /&gt;
&lt;br /&gt;
For this we will use some simple maths in a modification to our 'scrollNews' function:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
function scrollNews()&lt;br /&gt;
	local x,y = guiGetPosition(newsLabel,false)&lt;br /&gt;
	&lt;br /&gt;
	local labelWidth, labelHeight = guiGetSize(newsLabel,false)&lt;br /&gt;
	&lt;br /&gt;
	-- if the far right position of the label (x + labelWidth) is greater than or equal to 0 (ie: still showing on the gridlist)&lt;br /&gt;
	if ((x-1) + labelWidth) &amp;gt;= 0 then&lt;br /&gt;
		-- compensate for a small off-by-one bug in MTA&lt;br /&gt;
		if x &amp;lt;= 0 then x = x - 1 end&lt;br /&gt;
		&lt;br /&gt;
		-- update the position as normal&lt;br /&gt;
		guiSetPosition(newsLabel,x-1,y,false)&lt;br /&gt;
		&lt;br /&gt;
	-- otherwise, we move on to the next item and reset the position&lt;br /&gt;
	else&lt;br /&gt;
		-- get the total number of items in the 'newsItems' table&lt;br /&gt;
		local totalItems = #newsItems&lt;br /&gt;
		&lt;br /&gt;
		-- if the next item on our list does not exist in our table&lt;br /&gt;
		if (currentItem + 1) &amp;gt; totalItems then&lt;br /&gt;
			-- loop back to the first item in the list&lt;br /&gt;
			updateNewsItem(1)&lt;br /&gt;
		else&lt;br /&gt;
			-- otherwise move onto the next item in the list&lt;br /&gt;
			updateNewsItem(currentItem + 1)&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Notice the use of the '#' symbol to get the size of the 'newsItems' table. &lt;br /&gt;
This is the Lua length operator, but it only works on tables that have numerical indexes (like an array or a list).&lt;br /&gt;
It also works on strings, eg: #&amp;quot;hello&amp;quot; would return 5.&lt;br /&gt;
&lt;br /&gt;
That completes this section of the tutorial.&lt;br /&gt;
For ideas on how to further improve and advance this code, continue reading the next section.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Improving the code==&lt;br /&gt;
This section will detail several ways to improve upon the code you now have.&lt;br /&gt;
&lt;br /&gt;
===GUI Customisation===&lt;br /&gt;
To give your GUI a more unique feel, you have the ability to customise some aspects of your GUI elements.&lt;br /&gt;
&lt;br /&gt;
For ideas on what is possible, browse the [[Client_Scripting_Functions#GUI_functions|MTA GUI functions]].&lt;br /&gt;
&lt;br /&gt;
For the purposes of this tutorial, we will be using Font, Colour and Alpha.&lt;br /&gt;
&lt;br /&gt;
To start, we will change the alpha of the background gridlist GUI element we are using.&lt;br /&gt;
To set the alpha, use [[guiSetAlpha]] and pass a value between 1 and 0; 1 being fully opaque and 0 being fully transparent.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
guiSetAlpha(newsGridlist,0.8)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Place this line of code in your 'createNewsFeed' function, after your gridlist has been created.&lt;br /&gt;
&lt;br /&gt;
I find an alpha level of 0.8 looks best, however this is personal preference and you can experiment to suit your needs.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Next, we will look at the font of the label text.&lt;br /&gt;
To set the font, use [[guiSetFont]] and pass the string name of the font you want to use (available to see on the [[GUI Fonts]] page).&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
guiSetFont(newsLabel,&amp;quot;default-bold-small&amp;quot;)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Place this line of code in your 'createNewsFeed' function, after your label has been created.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Finally, we will look at setting the colour of the label text.&lt;br /&gt;
To set the colour, use [[guiLabelSetColor]] and pass the individual red,green and blue values.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
guiLabelSetColor(newsLabel,255,70,0)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Place this line of code in your 'createNewsFeed' function, after your label has been created.&lt;br /&gt;
&lt;br /&gt;
This will give your news items an orange-red colour.&lt;br /&gt;
&lt;br /&gt;
===Multiple News Items===&lt;br /&gt;
In its current form, this code is only capable of showing one news item at a time.&lt;br /&gt;
However, with a few modifications we can show multiple news items at once, one after another.&lt;br /&gt;
&lt;br /&gt;
To begin with, we need to make sure we have a 'newItems' table defined at the very start of our script,&lt;br /&gt;
as well as a 'distance' variable that will control the pixel distance between each news item:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
local newsItems = {}&lt;br /&gt;
local distance = 30&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
So put these lines at the top of the file.&lt;br /&gt;
&lt;br /&gt;
Next, we will not know how many items we have (and consequently, how many labels we need) until we have loaded the file.&lt;br /&gt;
With that in mind, we will move around some of the code in our 'createNewsFeed' function to support this:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
function createNewsFeed()&lt;br /&gt;
	-- get the screen width and height&lt;br /&gt;
	local sWidth, sHeight = guiGetScreenSize()&lt;br /&gt;
 &lt;br /&gt;
	-- create the gridlist, using some maths to find the bottom-centre of the screen&lt;br /&gt;
	local Width,Height = 800,45&lt;br /&gt;
	local X = (sWidth/2) - (Width/2)&lt;br /&gt;
	local Y = sHeight - (Height/2)&lt;br /&gt;
	&lt;br /&gt;
	-- the gridlist will act as the background to our news reel&lt;br /&gt;
	newsGridlist = guiCreateGridList(X,Y,Width,Height,false)&lt;br /&gt;
	&lt;br /&gt;
	guiSetAlpha(newsGridlist,0.8)&lt;br /&gt;
	&lt;br /&gt;
	-- call our function to read the news out of the xml file, before we create the labels&lt;br /&gt;
	loadNews()&lt;br /&gt;
		&lt;br /&gt;
	-- define a table to hold our labels&lt;br /&gt;
	newsLabel = {}&lt;br /&gt;
	&lt;br /&gt;
	-- now we can loop all our news items, and create a label for each one&lt;br /&gt;
	for index,item in ipairs(newsItems) do&lt;br /&gt;
	&lt;br /&gt;
		-- because we now have one label for every item, we can just set the text here and it wont need to be changed again.&lt;br /&gt;
		newsLabel[index] = guiCreateLabel(0,0,Width,Height/2,item,false,newsGridlist)&lt;br /&gt;
		&lt;br /&gt;
		guiSetFont(newsLabel[index],&amp;quot;default-bold-small&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
		guiLabelSetColor(newsLabel[index],255,70,0)		&lt;br /&gt;
&lt;br /&gt;
		-- modify the width of the label to fit the text&lt;br /&gt;
		local extent = guiLabelGetTextExtent(newsLabel[index])		&lt;br /&gt;
		guiSetSize(newsLabel[index],extent,Height/2,false)&lt;br /&gt;
		&lt;br /&gt;
		&lt;br /&gt;
		-- get the size of the gridlist&lt;br /&gt;
		local x,y = guiGetSize(newsGridlist,false)&lt;br /&gt;
		&lt;br /&gt;
		-- loop from 1 until index-1 in steps of 1&lt;br /&gt;
		-- this allows us to loop every label before the label we are currently on&lt;br /&gt;
		for i=1, index-1, 1 do&lt;br /&gt;
			-- tally up the sizes of all labels before our current one and store them in x&lt;br /&gt;
			local width = guiGetSize(newsLabel[i],false)&lt;br /&gt;
			x = x + width&lt;br /&gt;
		end&lt;br /&gt;
		&lt;br /&gt;
		-- put a 'distance' pixel gap between each news item&lt;br /&gt;
		x = x + (distance*(index-1))&lt;br /&gt;
		&lt;br /&gt;
		-- set the positon to the far right side of the gridlist, ready to scroll on to the left&lt;br /&gt;
		guiSetPosition(newsLabel[index],x,0,false)	&lt;br /&gt;
	end	&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Now we need to update our 'updateNewsItem' function to account for having multiple labels:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
function updateNewsItem(newIndex)&lt;br /&gt;
	-- find the index of the news item directly infront (in the looping order) of the newIndex item&lt;br /&gt;
	local index = newIndex - 1&lt;br /&gt;
	if index == 0 then index = #newsItems end&lt;br /&gt;
	&lt;br /&gt;
	-- find the position of the right-edge of the label directly infront of the newIndex label&lt;br /&gt;
	local x = guiGetPosition(newsLabel[index],false) &lt;br /&gt;
	local width = guiGetSize(newsLabel[index],false)&lt;br /&gt;
	x = x + width&lt;br /&gt;
&lt;br /&gt;
	-- add a 'distance' pixel gap in&lt;br /&gt;
	x = x + distance&lt;br /&gt;
&lt;br /&gt;
	-- check the new position isnt actually on the gridlist (ie: so it wont suddenly appear in the centre of the list)&lt;br /&gt;
	local gridlistWidth = guiGetSize(newsGridlist,false)&lt;br /&gt;
	&lt;br /&gt;
	if x &amp;lt; gridlistWidth then&lt;br /&gt;
		-- if it is, simple move it back to the edge&lt;br /&gt;
		x = gridlistWidth&lt;br /&gt;
	end&lt;br /&gt;
	&lt;br /&gt;
	-- set the new position&lt;br /&gt;
	guiSetPosition(newsLabel[newIndex],x,0,false)&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Finally, we need to make some small adjustments to our 'scrollNews' function:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
function scrollNews()&lt;br /&gt;
	if newsItems then&lt;br /&gt;
		-- loop every news item&lt;br /&gt;
		for index,item in ipairs(newsItems) do&lt;br /&gt;
			local x,y = guiGetPosition(newsLabel[index],false)&lt;br /&gt;
			&lt;br /&gt;
			local labelWidth, labelHeight = guiGetSize(newsLabel[index],false)&lt;br /&gt;
			&lt;br /&gt;
			-- if the far right position of the label (x + labelWidth) is greater than or equal to 0 (ie: still showing on the gridlist)&lt;br /&gt;
			if ((x-1) + labelWidth) &amp;gt;= 0 then&lt;br /&gt;
				-- compensate for a small off-by-one bug in MTA&lt;br /&gt;
				if x &amp;lt;= 0 then x = x - 1 end&lt;br /&gt;
			&lt;br /&gt;
				-- update the position as normal&lt;br /&gt;
				guiSetPosition(newsLabel[index],x-1,y,false)&lt;br /&gt;
				&lt;br /&gt;
			-- otherwise, we move on to the next item and reset the position&lt;br /&gt;
			else&lt;br /&gt;
				updateNewsItem(index)&lt;br /&gt;
			end&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
You should now have multiple news items scrolling along your news feed simultaneously.&lt;br /&gt;
&lt;br /&gt;
===Globally controlled scroll speed===&lt;br /&gt;
As with the 'distance' variable above, we can set a global variable for controlling the scroll speed of the news items as well.&lt;br /&gt;
Note that the speed will still be dependant on the players FPS (ie: lower FPS means slightly slower scrolling).&lt;br /&gt;
&lt;br /&gt;
To do this, we simply need to create the variable at the start of our code:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
local scrollSpeed = 1&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Put this line at the top of your file.&lt;br /&gt;
&lt;br /&gt;
Then, we just replace the instance of &amp;quot;x-1&amp;quot; in our 'scrollNews' function with &amp;quot;x-scrollSpeed&amp;quot;:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
function scrollNews()&lt;br /&gt;
		...&lt;br /&gt;
				-- update the position as normal&lt;br /&gt;
				guiSetPosition(newsLabel[index],x-scrollSpeed,y,false)&lt;br /&gt;
		...&lt;br /&gt;
	end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
That concludes this section of the tutorial.&lt;br /&gt;
&lt;br /&gt;
[[Category:GUI_Tutorials]]&lt;/div&gt;</summary>
		<author><name>R3mp</name></author>
	</entry>
	<entry>
		<id>https://wiki.multitheftauto.com/index.php?title=Scripting_the_GUI_-_Tutorial_2&amp;diff=22196</id>
		<title>Scripting the GUI - Tutorial 2</title>
		<link rel="alternate" type="text/html" href="https://wiki.multitheftauto.com/index.php?title=Scripting_the_GUI_-_Tutorial_2&amp;diff=22196"/>
		<updated>2010-01-06T01:04:13Z</updated>

		<summary type="html">&lt;p&gt;R3mp: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;'''Scripting the GUI - Tutorial 2 (Gates + Keypads)'''&lt;br /&gt;
&lt;br /&gt;
In this tutorial we will look at creating GUI keypads with combination codes for map-defined object gates.&lt;br /&gt;
We will be using serverside keycodes, with some client - server interaction to verify the codes and report the outcome.&lt;br /&gt;
&lt;br /&gt;
'''Note that this tutorial assumes you are familiar with all the content covered in the [[Introduction to Scripting GUI|GUI Scripting Introduction]].'''&lt;br /&gt;
&lt;br /&gt;
[[Image:Gui_keypad_tutorial.png|thumb|GUI Keypad]]&lt;br /&gt;
&lt;br /&gt;
==Setting up the Keypad==&lt;br /&gt;
To begin, open up a clientside lua file (if you have been following the [[Introduction to Scripting GUI|GUI Scripting Introduction]], this is gui.lua) to work with.&lt;br /&gt;
&lt;br /&gt;
===Creating the GUI===&lt;br /&gt;
By now, GUI creation should seem relatively straight forward, so we will not go over this in too much detail.&lt;br /&gt;
As in [[Scripting the GUI - Tutorial 1|Tutorial 1]] we will be using '''absolute''' values in this tutorial.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
function createKeypad()&lt;br /&gt;
	-- get the screen width and height&lt;br /&gt;
	local sWidth, sHeight = guiGetScreenSize()&lt;br /&gt;
&lt;br /&gt;
	-- create the window, using some maths to find the centre of the screen&lt;br /&gt;
	local Width,Height = 142,276&lt;br /&gt;
	local X = (sWidth/2) - (Width/2)&lt;br /&gt;
	local Y = (sHeight/2) - (Height/2)&lt;br /&gt;
	keypadWindow = guiCreateWindow(X,Y,Width,Height,&amp;quot;Keypad&amp;quot;,false)&lt;br /&gt;
	&lt;br /&gt;
	-- don't allow people to resize the keypad&lt;br /&gt;
	guiWindowSetSizable(keypadWindow,false)&lt;br /&gt;
&lt;br /&gt;
	-- create buttons labeled 0-9, &amp;quot;*&amp;quot;, &amp;quot;#&amp;quot;, &amp;quot;Enter&amp;quot; and &amp;quot;C&amp;quot; (clear)&lt;br /&gt;
	keypadButton1 = guiCreateButton(13,68,37,36,&amp;quot;1&amp;quot;,false,keypadWindow)&lt;br /&gt;
	keypadButton2 = guiCreateButton(53,68,37,36,&amp;quot;2&amp;quot;,false,keypadWindow)&lt;br /&gt;
	keypadButton3 = guiCreateButton(93,68,37,36,&amp;quot;3&amp;quot;,false,keypadWindow)&lt;br /&gt;
	keypadButton4 = guiCreateButton(13,108,37,36,&amp;quot;4&amp;quot;,false,keypadWindow)&lt;br /&gt;
	keypadButton5 = guiCreateButton(53,108,37,36,&amp;quot;5&amp;quot;,false,keypadWindow)&lt;br /&gt;
	keypadButton6 = guiCreateButton(93,108,37,36,&amp;quot;6&amp;quot;,false,keypadWindow)&lt;br /&gt;
	keypadButton7 = guiCreateButton(13,148,37,36,&amp;quot;7&amp;quot;,false,keypadWindow)&lt;br /&gt;
	keypadButton8 = guiCreateButton(53,148,37,36,&amp;quot;8&amp;quot;,false,keypadWindow)&lt;br /&gt;
	keypadButton9 = guiCreateButton(93,148,37,36,&amp;quot;9&amp;quot;,false,keypadWindow)&lt;br /&gt;
	keypadButtonAsterix = guiCreateButton(13,188,37,36,&amp;quot;*&amp;quot;,false,keypadWindow)&lt;br /&gt;
	keypadButton0 = guiCreateButton(53,188,37,36,&amp;quot;0&amp;quot;,false,keypadWindow)&lt;br /&gt;
	keypadButtonHash = guiCreateButton(93,188,37,36,&amp;quot;#&amp;quot;,false,keypadWindow)&lt;br /&gt;
	keypadButtonExit = guiCreateButton(13,228,37,36,&amp;quot;Exit&amp;quot;,false,keypadWindow)&lt;br /&gt;
	keypadButtonEnter = guiCreateButton(53,228,37,36,&amp;quot;Enter&amp;quot;,false,keypadWindow)&lt;br /&gt;
	keypadButtonClear = guiCreateButton(93,228,37,36,&amp;quot;Clear&amp;quot;,false,keypadWindow)&lt;br /&gt;
&lt;br /&gt;
	-- create a gridlist to act as a backdrop on the kaypad display&lt;br /&gt;
	keypadGridlistDisplay = guiCreateGridList(13,25,117,33,false,keypadWindow)&lt;br /&gt;
	guiGridListSetSelectionMode(keypadGridlistDisplay,2)&lt;br /&gt;
	guiSetAlpha(keypadGridlistDisplay,0.6)&lt;br /&gt;
	-- create a label so we can write text on the keypad display&lt;br /&gt;
	keypadLabelDisplay = guiCreateLabel(14,26,115,30,&amp;quot;Enter Keycode.&amp;quot;,false,keypadWindow)&lt;br /&gt;
	guiLabelSetColor(keypadLabelDisplay,255,000,000)&lt;br /&gt;
	guiLabelSetVerticalAlign(keypadLabelDisplay,&amp;quot;center&amp;quot;)&lt;br /&gt;
	guiLabelSetHorizontalAlign(keypadLabelDisplay,&amp;quot;center&amp;quot;,false)&lt;br /&gt;
	&lt;br /&gt;
	guiSetVisible(keypadWindow,false)&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
-- create the GUI when the resource starts&lt;br /&gt;
addEventHandler(&amp;quot;onClientResourceStart&amp;quot;,getResourceRootElement(getThisResource()),createKeypad)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
As you can see, the keypad consists of 10 numerical keys (0-9), two character keys (* and #), a clear key, an exit key and an enter key.&lt;br /&gt;
This means the codes used on the keypad can contain any of these characters (0123456789*#).&lt;br /&gt;
&lt;br /&gt;
===Managing the display===&lt;br /&gt;
We will begin by writing a small function to control the display on the keypad.&lt;br /&gt;
This is done by encapsulating several methods of changing the text into a single function,&lt;br /&gt;
which will enable us to easily add/remove text from the display later on.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
function updateDisplay(text)&lt;br /&gt;
	-- if we are passing some text&lt;br /&gt;
	if text then&lt;br /&gt;
		-- if its a digit or * or #, then append it to the end of the display&lt;br /&gt;
		if tonumber(text) or text == &amp;quot;*&amp;quot; or text == &amp;quot;#&amp;quot; then&lt;br /&gt;
			guiSetText(keypadLabelDisplay,guiGetText(keypadLabelDisplay) .. text)&lt;br /&gt;
		-- otherwise replace the display with the new text&lt;br /&gt;
		else&lt;br /&gt;
			guiSetText(keypadLabelDisplay,text)&lt;br /&gt;
		end	&lt;br /&gt;
	-- if we pass nil, clear the display entirely&lt;br /&gt;
	else&lt;br /&gt;
		guiSetText(keypadLabelDisplay,&amp;quot;&amp;quot;)&lt;br /&gt;
	end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
We can now simply call updateDisplay(our text) to change the text on the display, or updateDisplay(nil) to clear it.&lt;br /&gt;
&lt;br /&gt;
===Detecting the clicks===&lt;br /&gt;
With so many buttons that do very similar tasks on our keypad, there are two methods available to us for detecting when a player clicks on them.&lt;br /&gt;
&lt;br /&gt;
We could add [[onClientGUIClick]] events for every button individually, as we have done in previous tutorials; Or, alternatively, &lt;br /&gt;
we could add a single [[onClientGUIClick]] handle for the window (which is the parent of all our other keypad GUI elements), filter our results to include only the buttons we want and trigger our own custom event.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
For the purposes of this tutorial and in the interest of outlining multiple approaches, we will explore the second method, though either one is an acceptable solution.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
addEventHandler(&amp;quot;onClientGUIClick&amp;quot;,keypadWindow,processKeypadClicks,true)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
'''Notice the final argument is set to 'true'. This means that clicks on any other elements in the same branch of the tree will also trigger this event handle (eg. clicks on our buttons).'''&lt;br /&gt;
&lt;br /&gt;
Add this line of code into your createKeypad function, after your GUI has been created.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Now that we are detecting all clicks on our GUI, we need to filter out the ones we do not want (ie: clicks on the window or display) and trigger our custom event:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
function processKeypadClicks(button,state)&lt;br /&gt;
	if button == &amp;quot;left&amp;quot; and state == &amp;quot;up&amp;quot; then&lt;br /&gt;
		-- if the source of this event is a gui button&lt;br /&gt;
		if getElementType(source) == &amp;quot;gui-button&amp;quot; then&lt;br /&gt;
			-- trigger our custom event and send the keypad id of this keypad as an argument&lt;br /&gt;
			triggerEvent(&amp;quot;onKeypadButtonClicked&amp;quot;,source,getElementData(keypadWindow,&amp;quot;keypadID&amp;quot;))&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
As you can see, we are now triggering our custom event &amp;quot;onKeypadButtonClicked&amp;quot; whenever a button is clicked on the keypad.&lt;br /&gt;
Also note we use element data &amp;quot;keypadID&amp;quot; to differentiate between keypads. This data will need to be set whenever the player is shown a new keypad.&lt;br /&gt;
We will cover this in more detail later.&lt;br /&gt;
&lt;br /&gt;
===Handling the clicks===&lt;br /&gt;
Much like when using [[triggerServerEvent]] in previous tutorials, we now need to define the event, only this time it is purely clientside:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
addEvent(&amp;quot;onKeypadButtonClicked&amp;quot;,false)&lt;br /&gt;
addEventHandler(&amp;quot;onKeypadButtonClicked&amp;quot;,root,&lt;br /&gt;
	function(keypadID)&lt;br /&gt;
&lt;br /&gt;
	end&lt;br /&gt;
)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Note the second argument in [[addEvent]] is set to false, indicating that this event cannot be triggered from the server.&lt;br /&gt;
Also note, the function we are using in the [[addEventHandler]] does not have a name. If you contract it down and remove the spacing, you get:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
addEventHandler(&amp;quot;onKeypadButtonClicked&amp;quot;,root,function() ... end)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
This simply means instead of storing the pointer to the function in a variable, we are passing it directly as an argument.&lt;br /&gt;
Doing it this way cleans up the code and will often make it easier to follow.&lt;br /&gt;
&lt;br /&gt;
Now that the event has been created, we can fill in the code logic that will control our button presses.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
addEvent(&amp;quot;onKeypadButtonClicked&amp;quot;,false)&lt;br /&gt;
addEventHandler(&amp;quot;onKeypadButtonClicked&amp;quot;,root,&lt;br /&gt;
	function(keypadID)&lt;br /&gt;
		-- clear the display if this is the first time its being used&lt;br /&gt;
		if guiGetText(keypadLabelDisplay) == &amp;quot;Enter Keycode.&amp;quot; or guiGetText(keypadLabelDisplay) == &amp;quot;Invalid Keycode.&amp;quot; then&lt;br /&gt;
			updateDisplay()&lt;br /&gt;
		end&lt;br /&gt;
	&lt;br /&gt;
	&lt;br /&gt;
		-- if its the clear button&lt;br /&gt;
		if guiGetText(source) == &amp;quot;Clear&amp;quot; then&lt;br /&gt;
			-- clear the display&lt;br /&gt;
			updateDisplay()&lt;br /&gt;
		&lt;br /&gt;
		-- if its the enter button&lt;br /&gt;
		elseif guiGetText(source) == &amp;quot;Enter&amp;quot; then&lt;br /&gt;
			-- get the currently entered code from the display&lt;br /&gt;
			local code = guiGetText(keypadLabelDisplay)&lt;br /&gt;
			&lt;br /&gt;
			-- if they have entered a code&lt;br /&gt;
			if code then&lt;br /&gt;
				-- trigger the server so we can verify their code&lt;br /&gt;
				triggerServerEvent(&amp;quot;verifyKeypadCode&amp;quot;,getLocalPlayer(),code,keypadID)&lt;br /&gt;
			end&lt;br /&gt;
		&lt;br /&gt;
		-- if its the exit button&lt;br /&gt;
		elseif guiGetText(source) == &amp;quot;Exit&amp;quot; then&lt;br /&gt;
			-- hide the keypad and reset the display text ready for next time&lt;br /&gt;
			guiSetVisible(keypadWindow,false)&lt;br /&gt;
			updateDisplay(&amp;quot;Enter Keycode.&amp;quot;)&lt;br /&gt;
			showCursor(false,false)&lt;br /&gt;
			&lt;br /&gt;
		-- otherwise, it must be a character button&lt;br /&gt;
		else&lt;br /&gt;
			updateDisplay(guiGetText(source))	&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Serverside Verification==&lt;br /&gt;
For this part of the tutorial, you will need to open up a serverside lua file from your resource to work with.&lt;br /&gt;
&lt;br /&gt;
===Defining the keycode===&lt;br /&gt;
Now that we have completed the keypad clicking logic, we need to move on to verifying the code entered into the keypad.&lt;br /&gt;
To do this, we need to have the correct code stored somewhere on the server, which we can check the players code against.&lt;br /&gt;
&lt;br /&gt;
For the purposes of this tutorial we will simply store the code in a serverside table, however it can be done any number of ways (such as serverside xml files or MySQL databases).&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
local keypadCodes = {&lt;br /&gt;
	[&amp;quot;a51MainGateKeypadCode&amp;quot;] = &amp;quot;4455*#&amp;quot;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
This table stores an entry called &amp;quot;a51MainGateKeypadCode&amp;quot; with the code 4455*#&lt;br /&gt;
&lt;br /&gt;
'''This is the keycode that you will use to open the gate later on in this tutorial.'''&lt;br /&gt;
&lt;br /&gt;
===Verifying the code===&lt;br /&gt;
Now that we have a keycode to verify against, we can write our serverside event:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
addEvent(&amp;quot;verifyKeypadCode&amp;quot;,true)&lt;br /&gt;
addEventHandler(&amp;quot;verifyKeypadCode&amp;quot;,root,function(code,keypadID)&lt;br /&gt;
	if code then&lt;br /&gt;
		-- using the table we created earlier, check if the code supplied is the same as the code for this gate&lt;br /&gt;
		if code == keypadCodes[keypadID] then&lt;br /&gt;
			-- if it is, tell the client that it was successful&lt;br /&gt;
			triggerClientEvent(client,&amp;quot;onKeypadVerificationSuccessful&amp;quot;,client,keypadID)&lt;br /&gt;
		else&lt;br /&gt;
			-- if it is not, tell the client that it was not successful&lt;br /&gt;
			triggerClientEvent(client,&amp;quot;onKeypadVerificationFailed&amp;quot;,client,keypadID)&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
end)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Here we use our table and the keypadID supplied by the player to check if the codes match.&lt;br /&gt;
&lt;br /&gt;
If you are not using a table to store the codes, then you will need to replace 'keypadCodes[keypadID]' with your own storage method.&lt;br /&gt;
Once it is verified (or not), we can trigger the client so the appropriate information can be shown on the keypad display.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Receiving the result==&lt;br /&gt;
We have now finished the serverside section of the tutorial, so you will need to open up the clientside lua file from your resource &lt;br /&gt;
that you were previously working on.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Once our code has been verified, the server will send back the response to the client.&lt;br /&gt;
In just the same way as client -&amp;gt; server interaction, we now need to add the event that the server is going to trigger on the client.&lt;br /&gt;
&lt;br /&gt;
===Catching and processing the result===&lt;br /&gt;
First we will add the event for when the verification is successful:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
addEvent(&amp;quot;onKeypadVerificationSuccessful&amp;quot;,true)&lt;br /&gt;
addEventHandler(&amp;quot;onKeypadVerificationSuccessful&amp;quot;,root,&lt;br /&gt;
	function()&lt;br /&gt;
		-- hide the keypad and reset the display text ready for next time&lt;br /&gt;
		guiSetVisible(keypadWindow,false)&lt;br /&gt;
		updateDisplay(&amp;quot;Enter Keycode.&amp;quot;)&lt;br /&gt;
		showCursor(false,false)&lt;br /&gt;
	end&lt;br /&gt;
)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Finally we can add the event for when the verification is unsuccessful:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
addEvent(&amp;quot;onKeypadVerificationFailed&amp;quot;,true)&lt;br /&gt;
addEventHandler(&amp;quot;onKeypadVerificationFailed&amp;quot;,root,&lt;br /&gt;
	function()&lt;br /&gt;
		-- update the display text to show the code was invalid&lt;br /&gt;
		updateDisplay(&amp;quot;Invalid Keycode.&amp;quot;)&lt;br /&gt;
	end&lt;br /&gt;
)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This completes the keypad section of the tutorial.&lt;br /&gt;
&lt;br /&gt;
For an example of how to implement this into a working gate system, carry on reading the next section.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Applying the Keypad==&lt;br /&gt;
For the keypad to have any use, we need something to use it on.&lt;br /&gt;
For this tutorial we will be using gates, and as mentioned earlier we will create a main gate into A51.&lt;br /&gt;
&lt;br /&gt;
===Creating the gate===&lt;br /&gt;
First of all, we need to create the gate object.&lt;br /&gt;
For the purposes of this example, we will be using a map file to store the object. &lt;br /&gt;
While this is the recommended method for defining objects, it is not the only way to approach it.&lt;br /&gt;
&lt;br /&gt;
Navigate to your resource folder and make a new file called gate.map, then add your new map file to your meta.xml using:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;map src=&amp;quot;gate.map&amp;quot;/&amp;gt;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
''If you are unsure of map file syntax, please see the [[Writing_Gamemodes| Writing Gamemodes Tutorial]] or check the [[Object]] page for help.''&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;map&amp;gt;&lt;br /&gt;
    &amp;lt;object id=&amp;quot;a51MainGateKeypadCode&amp;quot; model=&amp;quot;971&amp;quot; posX=&amp;quot;96.736&amp;quot; posY=&amp;quot;1918.352&amp;quot; posZ=&amp;quot;20.694&amp;quot; rotX=&amp;quot;0&amp;quot; rotY=&amp;quot;0&amp;quot; rotZ=&amp;quot;270.40&amp;quot; newPosX=&amp;quot;96.751&amp;quot; newPosY=&amp;quot;1914.474&amp;quot; newPosZ=&amp;quot;20.694&amp;quot; /&amp;gt;&lt;br /&gt;
&amp;lt;/map&amp;gt;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
This will create a gate object across the A51 entrance. The object will have position and rotation data, as well as its newPosX,newPosY and newPosZ information that we need to be able to move it.&lt;br /&gt;
&lt;br /&gt;
'''Note that the object id is the same as the table entry we created earlier to hold the access code.'''&lt;br /&gt;
This is one possible method that could be accessed to link this gate with that particular keycode.&lt;br /&gt;
&lt;br /&gt;
===Opening the keypad===&lt;br /&gt;
Back in the clientside lua file again, we can now work on linking the gate and the keypad.&lt;br /&gt;
&lt;br /&gt;
Now that we have our gate, we need a way of accessing the keypad to open it.&lt;br /&gt;
For the purposes of this tutorial we will use a simple command, however you could just as easily use a colshape or button press.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
addCommandHandler(&amp;quot;a51gate&amp;quot;,function()&lt;br /&gt;
	guiSetVisible(keypadWindow,true)&lt;br /&gt;
	showCursor(true,true)&lt;br /&gt;
	setElementData(keypadWindow,&amp;quot;keypadID&amp;quot;,&amp;quot;a51MainGateKeypadCode&amp;quot;)&lt;br /&gt;
end)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Note that we set the element data &amp;quot;keypadID&amp;quot;.&lt;br /&gt;
This is very important because it allows us to keep track of which gate we are trying to open (in this case, the &amp;quot;a51MainGateKeypadCode&amp;quot; gate).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Opening the gate===&lt;br /&gt;
With our gate created and our keypad ready, all thats left now is to open the gate.&lt;br /&gt;
Having created custom events earlier for successfully and unsuccessfully verifying the code, this now becomes very easy to do.&lt;br /&gt;
All we do is add an event handler for our custom &amp;quot;success&amp;quot; event, and using the keypadID we defined earlier we can move the gate inside it:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
addEventHandler(&amp;quot;onKeypadVerificationSuccessful&amp;quot;,root,&lt;br /&gt;
	-- keypadID is sent back from the server&lt;br /&gt;
	function(keypadID)&lt;br /&gt;
		-- get the gate object (this is where the id=&amp;quot;a51MainGateKeypadCode&amp;quot; tag in the map file becomes useful)&lt;br /&gt;
		local gate = getElementByID(keypadID)&lt;br /&gt;
&lt;br /&gt;
		-- if we found the object&lt;br /&gt;
		if gate then&lt;br /&gt;
			-- get the new position (as we defined in the map file)&lt;br /&gt;
			local x = tonumber(getElementData(gate,&amp;quot;newPosX&amp;quot;))&lt;br /&gt;
			local y = tonumber(getElementData(gate,&amp;quot;newPosY&amp;quot;))&lt;br /&gt;
			local z = tonumber(getElementData(gate,&amp;quot;newPosZ&amp;quot;))&lt;br /&gt;
&lt;br /&gt;
			-- move the gate&lt;br /&gt;
			moveObject(gate,1500,x,y,z)&lt;br /&gt;
			&lt;br /&gt;
			-- get the original position&lt;br /&gt;
			x = tonumber(getElementData(gate,&amp;quot;posX&amp;quot;))&lt;br /&gt;
			y = tonumber(getElementData(gate,&amp;quot;posY&amp;quot;))&lt;br /&gt;
			z = tonumber(getElementData(gate,&amp;quot;posZ&amp;quot;))	&lt;br /&gt;
			&lt;br /&gt;
			-- set a timer to close the gate in 5 seconds&lt;br /&gt;
			setTimer(moveObject,5000,1,gate,1500,x,y,z)&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Note how by using the keypadID sent back from the server, we can use if statements and checks against the id to control any number of gates from the same function.&lt;br /&gt;
&lt;br /&gt;
You should now have a working example of a GUI Keypad controlling an A51 Gate.&lt;br /&gt;
&lt;br /&gt;
For further GUI tutorials, see [[Scripting the GUI - Tutorial 3|Tutorial 3 (Scrolling News Feed)]]&lt;br /&gt;
&lt;br /&gt;
[[Category:GUI_Tutorials]]&lt;/div&gt;</summary>
		<author><name>R3mp</name></author>
	</entry>
	<entry>
		<id>https://wiki.multitheftauto.com/index.php?title=Scripting_the_GUI_-_Tutorial_1&amp;diff=22195</id>
		<title>Scripting the GUI - Tutorial 1</title>
		<link rel="alternate" type="text/html" href="https://wiki.multitheftauto.com/index.php?title=Scripting_the_GUI_-_Tutorial_1&amp;diff=22195"/>
		<updated>2010-01-06T01:03:55Z</updated>

		<summary type="html">&lt;p&gt;R3mp: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;'''Scripting the Gui - Tutorial 1 (Gridlists)'''&lt;br /&gt;
&lt;br /&gt;
In this tutorial we will explore the use of gridlists in creating a vehicle selection screen, with optional clientside vehicle xml data reading.&lt;br /&gt;
&lt;br /&gt;
'''Note that this tutorial assumes you are familiar with all the content covered in the [[Introduction to Scripting GUI|Previous tutorial]].'''&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Setting up the Vehicle Selection==&lt;br /&gt;
&lt;br /&gt;
===Creating the GUI===&lt;br /&gt;
To begin, open up a clientside lua file (if you have been following the [[Scripting Introduction]], this is gui.lua) to work with.&lt;br /&gt;
&lt;br /&gt;
In this file, we will start writing our function for creating the GUI.&lt;br /&gt;
As covered in the [[Introduction to Scripting GUI|Previous tutorial]], there are 2 value type options available when creating gui: '''relative''' and '''absolute'''.&lt;br /&gt;
&lt;br /&gt;
For the purposes of this tutorial, we will be using '''absolute''' values.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
This will create a simple GUI with a window, gridlist and button:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
function createVehicleSelection()&lt;br /&gt;
	-- get the screen width and height&lt;br /&gt;
	local sWidth, sHeight = guiGetScreenSize()&lt;br /&gt;
	&lt;br /&gt;
	-- use some simple maths to position the window in the centre of the screen&lt;br /&gt;
	local Width,Height = 376,259&lt;br /&gt;
	local X = (sWidth/2) - (Width/2)&lt;br /&gt;
	local Y = (sHeight/2) - (Height/2)&lt;br /&gt;
	windowVehicleSelection = guiCreateWindow(X,Y,Width,Height,&amp;quot;Vehicle Selection Window&amp;quot;,false)&lt;br /&gt;
	&lt;br /&gt;
	gridlistVehicleSelection = guiCreateGridList(10,26,357,192,false,windowVehicleSelection)&lt;br /&gt;
	-- add a &amp;quot;Vehicle&amp;quot; and a &amp;quot;Type&amp;quot; collumn to the gridlist&lt;br /&gt;
	guiGridListAddColumn(gridlistVehicleSelection,&amp;quot;Vehicle&amp;quot;,0.2)&lt;br /&gt;
	guiGridListAddColumn(gridlistVehicleSelection,&amp;quot;Type&amp;quot;,0.2)&lt;br /&gt;
	&lt;br /&gt;
	-- set the default width of the columns to roughly half the size of the gridlist (each)&lt;br /&gt;
	guiGridListSetColumnWidth(gridlistVehicleSelection,1,0.4,true)&lt;br /&gt;
	guiGridListSetColumnWidth(gridlistVehicleSelection,2,0.5,true)&lt;br /&gt;
	&lt;br /&gt;
	buttonCreate = guiCreateButton(121,227,120,20,&amp;quot;Create&amp;quot;,false,windowVehicleSelection)&lt;br /&gt;
	&lt;br /&gt;
	-- add the event handler for when the button is clicked&lt;br /&gt;
	addEventHandler(&amp;quot;onClientGUIClick&amp;quot;,buttonCreate,createVehicleHandler,false)&lt;br /&gt;
	&lt;br /&gt;
	-- hide the GUI&lt;br /&gt;
	guiSetVisible(windowVehicleSelection,false)&lt;br /&gt;
	&lt;br /&gt;
	-- this will add all the vehicle options onto the gridlist, it is explained later in this tutorial&lt;br /&gt;
	populateGridlist()&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
We now also need to call this function somewhere, otherwise the GUI will never be created.&lt;br /&gt;
As in previous tutorials, to do this we can use [[onClientResourceStart]].&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
-- when the resource is started, create the GUI and hide it&lt;br /&gt;
addEventHandler(&amp;quot;onClientResourceStart&amp;quot;,getResourceRootElement(getThisResource()),&lt;br /&gt;
	function()&lt;br /&gt;
		createVehicleSelection()&lt;br /&gt;
	end&lt;br /&gt;
)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Showing the GUI===&lt;br /&gt;
Unlike in previous tutorials, we want players to be able to open this window whenever they chose, not when the resource starts. &lt;br /&gt;
So, we can add a [[addCommandHandler|Command]] to do this.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
-- create the function that will show the window&lt;br /&gt;
function showVehicleSelection()&lt;br /&gt;
	-- if the window isnt visible, show it&lt;br /&gt;
	if not guiGetVisible(windowVehicleSelection) then&lt;br /&gt;
		guiSetVisible(windowVehicleSelection,true)&lt;br /&gt;
		&lt;br /&gt;
		showCursor(true,true)&lt;br /&gt;
	end&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
-- add the command /vehicleselection and set it to call the showVehicleSelection function&lt;br /&gt;
addCommandHandler(&amp;quot;vehicleselection&amp;quot;,showVehicleSelection)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Populating the Gridlist from a table===&lt;br /&gt;
Now that we have our basic GUI created, we need to fill the gridlist with all of our vehicles.&lt;br /&gt;
&lt;br /&gt;
To begin with, we will do this using a simple clientside table. &lt;br /&gt;
Later in the tutorial, we will explore expanding this method to use .xml files for storing information.&lt;br /&gt;
To begin, we must create a small table containing a selection of vehicles that we can spawn.&lt;br /&gt;
&lt;br /&gt;
The table contains vehicles in the format [&amp;quot;description&amp;quot;] = vehicle_id :&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
-- create the table and fill it with a selection of vehicle ids and names&lt;br /&gt;
local vehicleSelectionTable = {&lt;br /&gt;
	[&amp;quot;Sparrow&amp;quot;] = 469,&lt;br /&gt;
	[&amp;quot;Stuntplane&amp;quot;] = 513,&lt;br /&gt;
	[&amp;quot;BF-400&amp;quot;] = 581,&lt;br /&gt;
	[&amp;quot;Freeway&amp;quot;] = 463,&lt;br /&gt;
	[&amp;quot;Speeder&amp;quot;] = 452,&lt;br /&gt;
	[&amp;quot;Jester&amp;quot;] = 559,&lt;br /&gt;
	[&amp;quot;Sabre&amp;quot;] = 475,&lt;br /&gt;
	[&amp;quot;Police Ranger&amp;quot;] = 599,&lt;br /&gt;
	[&amp;quot;Utility Van&amp;quot;] = 552,&lt;br /&gt;
	[&amp;quot;Tug&amp;quot;] = 583&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Place this code at the very top of your file (it does not need to be inside a function).&lt;br /&gt;
&lt;br /&gt;
Next, we can write our &amp;quot;populateGridlist&amp;quot; function which will fill the Gridlist with all the vehicles in the table.&lt;br /&gt;
To do this we simply need to loop through all the values in the table, adding each one to the gridlist as we go.&lt;br /&gt;
We will also set hidden data using [[guiGridListSetItemData]] to store the vehicle id:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
function populateGridlist()&lt;br /&gt;
	-- loop through the table&lt;br /&gt;
	for name,vehicle in pairs(vehicleSelectionTable) do&lt;br /&gt;
		-- add a new row to the gridlist&lt;br /&gt;
		local row = guiGridListAddRow(gridlistVehicleSelection)&lt;br /&gt;
&lt;br /&gt;
		-- set the text in the first column to the vehicle name&lt;br /&gt;
		guiGridListSetItemText(gridlistVehicleSelection,row,1,name,false,false)&lt;br /&gt;
		-- set the text in the second column to the vehicle type&lt;br /&gt;
		guiGridListSetItemText(gridlistVehicleSelection,row,2,getVehicleType(vehicle),false,false)&lt;br /&gt;
		&lt;br /&gt;
		-- set the data for gridlist slot as the vehicle id&lt;br /&gt;
		guiGridListSetItemData(gridlistVehicleSelection,row,1,tostring(vehicle))&lt;br /&gt;
	end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt; &lt;br /&gt;
&lt;br /&gt;
===Managing the click===&lt;br /&gt;
Now that we have our GUI completed, we need to be able to catch any clicks made on the &amp;quot;create&amp;quot; button.&lt;br /&gt;
We have attached the [[onClientGUIClick]] event to buttonCreate already, so now we need to write the function that it calls.&lt;br /&gt;
In this function we do some basic error checking, such as making sure a vehicle has been selected in the list. &lt;br /&gt;
We can then use some maths to find a position infront of the player and send the server this information to spawn the vehicle (using [[triggerServerEvent]]) &lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
function createVehicleHandler(button,state)&lt;br /&gt;
	if button == &amp;quot;left&amp;quot; and state == &amp;quot;up&amp;quot; then&lt;br /&gt;
		-- get the selected item in the gridlist&lt;br /&gt;
		local row,col = guiGridListGetSelectedItem(gridlistVehicleSelection)&lt;br /&gt;
		&lt;br /&gt;
		-- if something is selected&lt;br /&gt;
		if row and col and row ~= -1 and col ~= -1 then&lt;br /&gt;
			-- get the vehicle id data from the gridlist that is selected&lt;br /&gt;
			local selected = guiGridListGetItemData(gridlistVehicleSelection,row,col)&lt;br /&gt;
			&lt;br /&gt;
			-- make sure the vehicle id is a number not a string&lt;br /&gt;
			selected = tonumber(selected)&lt;br /&gt;
						&lt;br /&gt;
			-- get the players position and rotation&lt;br /&gt;
			local rotz = getPedRotation(getLocalPlayer())&lt;br /&gt;
			local x,y,z = getElementPosition(getLocalPlayer())&lt;br /&gt;
			-- find the position directly infront of the player&lt;br /&gt;
			x = x + ( math.cos ( math.rad ( rotz+90 ) ) * 3)&lt;br /&gt;
			y = y + ( math.sin ( math.rad ( rotz+90 ) ) * 3)&lt;br /&gt;
			&lt;br /&gt;
			if selected and x and y and z then&lt;br /&gt;
				-- trigger the server&lt;br /&gt;
				triggerServerEvent(&amp;quot;createVehicleFromGUI&amp;quot;,getRootElement(),selected,x,y,z)&lt;br /&gt;
				&lt;br /&gt;
				-- hide the gui and the cursor&lt;br /&gt;
				guiSetVisible(windowVehicleSelection,false)&lt;br /&gt;
				showCursor(false,false)&lt;br /&gt;
			else&lt;br /&gt;
				outputChatBox(&amp;quot;Invalid arguments.&amp;quot;)&lt;br /&gt;
			end&lt;br /&gt;
		else&lt;br /&gt;
			-- otherwise, output a message to the player&lt;br /&gt;
			outputChatBox(&amp;quot;Please select a vehicle.&amp;quot;)&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Creating the Vehicle===&lt;br /&gt;
At this point we now have all the code needed on the client side, so open up a serverside .lua file to work with. &lt;br /&gt;
&lt;br /&gt;
On the server side, we will first of all need to define the custom event that we triggered before from the client. This can be done using [[addEvent]] and [[addEventHandler]].&lt;br /&gt;
Finally we will need a small function for creating the vehicle:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
function createMyVehicle(vehicleid,x,y,z)&lt;br /&gt;
	-- check all the arguments exist&lt;br /&gt;
	if vehicleid and x and y and z then&lt;br /&gt;
		createVehicle(vehicleid,x,y,z)&lt;br /&gt;
	end&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
addEvent(&amp;quot;createVehicleFromGUI&amp;quot;,true)&lt;br /&gt;
addEventHandler(&amp;quot;createVehicleFromGUI&amp;quot;,root,createMyVehicle)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Note the use of the &amp;quot;root&amp;quot; variable. This is an MTA variable containing the root element; every resource has one.&lt;br /&gt;
&lt;br /&gt;
This completes the first section of the tutorial. You should now have a basic, working vehicle spawn script.&lt;br /&gt;
&lt;br /&gt;
In the second section, we will cover collapsible gridlist data and clientside xml file reading.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Expanding the code==&lt;br /&gt;
This section will detail several ways to improve upon the code you now have.&lt;br /&gt;
&lt;br /&gt;
===Importing Data===&lt;br /&gt;
One big improvement over the previously mentioned method is to use external files to store the vehicle information, allowing us to much more quickly and easily manage large amounts of data.&lt;br /&gt;
For this tutorial, we will use a clientside xml file to hold the information.&lt;br /&gt;
&lt;br /&gt;
First of all you will need to create your xml file, so navigate to your resources directory and create a new file named vehicles.xml:&lt;br /&gt;
&lt;br /&gt;
''For the purpose of this example, we will include only a small fraction of the total vehicles, however the file can easily be expanded to include them all.''&lt;br /&gt;
&lt;br /&gt;
If you are unsure of xml data structures, you can browse the [http://wiki.multitheftauto.com/wiki/Server_Scripting_Functions#XML_functions| MTA xml functions] for help.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;root&amp;gt;&lt;br /&gt;
	&amp;lt;group type=&amp;quot;Bikes&amp;quot;&amp;gt;&lt;br /&gt;
		&amp;lt;vehicle id=&amp;quot;581&amp;quot; name=&amp;quot;BF-400&amp;quot;/&amp;gt;&lt;br /&gt;
		&amp;lt;vehicle id=&amp;quot;463&amp;quot; name=&amp;quot;Freeway&amp;quot;/&amp;gt;&lt;br /&gt;
		&amp;lt;vehicle id=&amp;quot;481&amp;quot; name=&amp;quot;BMX&amp;quot;/&amp;gt;&lt;br /&gt;
	&amp;lt;/group&amp;gt;&lt;br /&gt;
	&amp;lt;group type=&amp;quot;Boats&amp;quot;&amp;gt;&lt;br /&gt;
		&amp;lt;vehicle id=&amp;quot;472&amp;quot; name=&amp;quot;Coastguard&amp;quot;/&amp;gt;&lt;br /&gt;
		&amp;lt;vehicle id=&amp;quot;452&amp;quot; name=&amp;quot;Speeder&amp;quot;/&amp;gt;&lt;br /&gt;
	&amp;lt;/group&amp;gt;&lt;br /&gt;
	&amp;lt;group type=&amp;quot;Helicopters&amp;quot;&amp;gt;&lt;br /&gt;
		&amp;lt;vehicle id=&amp;quot;487&amp;quot; name=&amp;quot;Maverick&amp;quot;/&amp;gt;&lt;br /&gt;
		&amp;lt;vehicle id=&amp;quot;469&amp;quot; name=&amp;quot;Sparrow&amp;quot;/&amp;gt;	&lt;br /&gt;
	&amp;lt;/group&amp;gt;&lt;br /&gt;
	&amp;lt;group type=&amp;quot;Planes&amp;quot;&amp;gt;&lt;br /&gt;
		&amp;lt;vehicle id=&amp;quot;593&amp;quot; name=&amp;quot;Dodo&amp;quot;/&amp;gt;&lt;br /&gt;
		&amp;lt;vehicle id=&amp;quot;513&amp;quot; name=&amp;quot;Stuntplane&amp;quot;/&amp;gt;	&lt;br /&gt;
	&amp;lt;/group&amp;gt;&lt;br /&gt;
	&amp;lt;group type=&amp;quot;Sports Cars&amp;quot;&amp;gt;&lt;br /&gt;
		&amp;lt;vehicle id=&amp;quot;565&amp;quot; name=&amp;quot;Flash&amp;quot;/&amp;gt;&lt;br /&gt;
		&amp;lt;vehicle id=&amp;quot;559&amp;quot; name=&amp;quot;Jester&amp;quot;/&amp;gt;&lt;br /&gt;
		&amp;lt;vehicle id=&amp;quot;477&amp;quot; name=&amp;quot;ZR-350&amp;quot;/&amp;gt;	&lt;br /&gt;
	&amp;lt;/group&amp;gt;&lt;br /&gt;
	&amp;lt;group type=&amp;quot;2-Door&amp;quot;&amp;gt;&lt;br /&gt;
		&amp;lt;vehicle id=&amp;quot;474&amp;quot; name=&amp;quot;Hermes&amp;quot;/&amp;gt;&lt;br /&gt;
		&amp;lt;vehicle id=&amp;quot;475&amp;quot; name=&amp;quot;Sabre&amp;quot;/&amp;gt;&lt;br /&gt;
	&amp;lt;/group&amp;gt;&lt;br /&gt;
	&amp;lt;group type=&amp;quot;Emergency&amp;quot;&amp;gt;&lt;br /&gt;
		&amp;lt;vehicle id=&amp;quot;416&amp;quot; name=&amp;quot;Ambulance&amp;quot;/&amp;gt;&lt;br /&gt;
		&amp;lt;vehicle id=&amp;quot;599&amp;quot; name=&amp;quot;Police ranger&amp;quot;/&amp;gt;&lt;br /&gt;
	&amp;lt;/group&amp;gt;&lt;br /&gt;
	&amp;lt;group type=&amp;quot;Industrial&amp;quot;&amp;gt;&lt;br /&gt;
		&amp;lt;vehicle id=&amp;quot;573&amp;quot; name=&amp;quot;Dune&amp;quot;/&amp;gt;&lt;br /&gt;
		&amp;lt;vehicle id=&amp;quot;552&amp;quot; name=&amp;quot;Utility van&amp;quot;/&amp;gt;	&lt;br /&gt;
	&amp;lt;/group&amp;gt;&lt;br /&gt;
	&amp;lt;group type=&amp;quot;Misc&amp;quot;&amp;gt;&lt;br /&gt;
		&amp;lt;vehicle id=&amp;quot;457&amp;quot; name=&amp;quot;Caddy&amp;quot;/&amp;gt;&lt;br /&gt;
		&amp;lt;vehicle id=&amp;quot;583&amp;quot; name=&amp;quot;Tug&amp;quot;/&amp;gt;&lt;br /&gt;
	&amp;lt;/group&amp;gt;&lt;br /&gt;
&amp;lt;/root&amp;gt;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Once you have created your file, do not forget to add it to the meta.xml of your resource with the appropriate client tag.&lt;br /&gt;
&lt;br /&gt;
Note the group &amp;quot;type&amp;quot; tag. This is an arbitrary description of the vehicles contained within the group and can be renamed or added as any text.&lt;br /&gt;
Similarly, the vehicle &amp;quot;name&amp;quot; tag is also just a textual description of the vehicle and does not need to be the exact vehicle name.&lt;br /&gt;
&lt;br /&gt;
Now that we have the data, we can import it into the game and display it in the GUI.&lt;br /&gt;
'''If you are following on from the first section of this tutorial, this new code will replace what is inside your existing 'populateGridlist' function.'''&lt;br /&gt;
First, we need to load the file:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
function populateGridlist()&lt;br /&gt;
	-- load the file and save the root node value it returns&lt;br /&gt;
	local rootnode = xmlLoadFile(&amp;quot;vehicles.xml&amp;quot;)&lt;br /&gt;
	&lt;br /&gt;
	-- check that the file exists and has been correctly loaded&lt;br /&gt;
	if rootnode then		&lt;br /&gt;
		-- unload the xml file&lt;br /&gt;
		xmlUnloadFile(rootnode)&lt;br /&gt;
	end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Always make sure you unload any files once you are finished using them.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
We can now start collecting the data from the file and entering it into our gridlist.&lt;br /&gt;
We can do this by looping through the xml data (in a similar manner to looping through the vehicle table earlier in this tutorial) and adding each entry into the list.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
function populateGridlist()&lt;br /&gt;
	local rootnode = xmlLoadFile(&amp;quot;vehicles.xml&amp;quot;)&lt;br /&gt;
	&lt;br /&gt;
	if rootnode then		&lt;br /&gt;
		-- first, we find every &amp;quot;group&amp;quot; node (they are direct children of the root)&lt;br /&gt;
		for _,group in ipairs(xmlNodeGetChildren(rootnode)) do&lt;br /&gt;
			-- add a new row to the gridlist&lt;br /&gt;
			local row = guiGridListAddRow(gridlistVehicleSelection)&lt;br /&gt;
&lt;br /&gt;
			-- get the group name&lt;br /&gt;
			local name = xmlNodeGetAttribute(group,&amp;quot;type&amp;quot;)&lt;br /&gt;
			&lt;br /&gt;
			-- set the text in the first column to the group type and indicate it is a section ('true')&lt;br /&gt;
			-- (sections on gridlists show up in bold and cannot be clicked)&lt;br /&gt;
			guiGridListSetItemText(gridlistVehicleSelection,row,1,name,true,false)			&lt;br /&gt;
		&lt;br /&gt;
			-- then, for every group that we find, loop all of its children (the vehicle nodes)&lt;br /&gt;
			-- and add them into the gridlist&lt;br /&gt;
			for _,vehicle in ipairs(xmlNodeGetChildren(group)) do&lt;br /&gt;
				-- add a new row to the gridlist&lt;br /&gt;
				row = guiGridListAddRow(gridlistVehicleSelection)&lt;br /&gt;
&lt;br /&gt;
				-- get the vehicle name and id&lt;br /&gt;
				name = xmlNodeGetAttribute(vehicle,&amp;quot;name&amp;quot;)&lt;br /&gt;
				local id = xmlNodeGetAttribute(vehicle,&amp;quot;id&amp;quot;)&lt;br /&gt;
				&lt;br /&gt;
				-- set the text in the first column to the vehicle name&lt;br /&gt;
				guiGridListSetItemText(gridlistVehicleSelection,row,1,name,false,false)&lt;br /&gt;
				-- set the text in the second column to the vehicle type&lt;br /&gt;
				guiGridListSetItemText(gridlistVehicleSelection,row,2,getVehicleType(tonumber(id)),false,false)		&lt;br /&gt;
				&lt;br /&gt;
				-- finally, set the vehicle id as data so we can access it later&lt;br /&gt;
				guiGridListSetItemData(gridlistVehicleSelection,row,1,tostring(id))&lt;br /&gt;
			end&lt;br /&gt;
		end	&lt;br /&gt;
	&lt;br /&gt;
		-- unload the xml file now that we are finished&lt;br /&gt;
		xmlUnloadFile(rootnode)&lt;br /&gt;
	end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Note the use of for loops in the code with [[xmlNodeGetChildren]]. This saves us a lot of time and effort as we do not have to manually code each group and vehicle into the list.&lt;br /&gt;
&lt;br /&gt;
You should now have a fully working vehicle selection menu, reading all of its data from a clientside xml file.&lt;br /&gt;
Next, we will examine how to generate the appearance of collapsing and expanding sections in a gridlist.&lt;br /&gt;
&lt;br /&gt;
===Collapsing/Expanding the Gridlist===&lt;br /&gt;
Allowing sections of the gridlist to be collapsed or expanded gives much more control over the visible content to the user.&lt;br /&gt;
This frees up space on the screen and makes the whole menu much more comfortable to use.&lt;br /&gt;
&lt;br /&gt;
===Loading the data===&lt;br /&gt;
To be able to achieve this effect (as it is not a natural feature of gridlists) we will need to load the vehicle information into a table (from the xml file), rather than directly including it all in the gridlist.&lt;br /&gt;
'''If you are following on from a previous section of this tutorial, this new code will replace what is inside your existing 'populateGridlist' function.'''&lt;br /&gt;
&lt;br /&gt;
This works in much the same way the previous xml loading example does, only this time instead of saving the data into the gridlist, we save it into a table entry instead.&lt;br /&gt;
We also set the custom data &amp;quot;header&amp;quot; on the gridlist slots to denote which gridlist entries are our &amp;quot;group&amp;quot; entries and which are vehicles.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
function populateGridlist()&lt;br /&gt;
	local rootnode = xmlLoadFile(&amp;quot;vehicles.xml&amp;quot;)&lt;br /&gt;
	&lt;br /&gt;
	-- create a blank global table to store our imported data&lt;br /&gt;
	vehicleTable = {}&lt;br /&gt;
	&lt;br /&gt;
	if rootnode then		&lt;br /&gt;
		for _,group in ipairs(xmlNodeGetChildren(rootnode)) do&lt;br /&gt;
			-- create an entry in the gridlist for every vehicle &amp;quot;group&amp;quot;&lt;br /&gt;
			local row = guiGridListAddRow(gridlistVehicleSelection)&lt;br /&gt;
&lt;br /&gt;
			local name = xmlNodeGetAttribute(group,&amp;quot;type&amp;quot;)&lt;br /&gt;
			&lt;br /&gt;
			guiGridListSetItemText(gridlistVehicleSelection,row,1,name,false,false)	&lt;br /&gt;
&lt;br /&gt;
			-- add an entry containing the group name into the table&lt;br /&gt;
			vehicleTable[name] = {}&lt;br /&gt;
			&lt;br /&gt;
			-- we will use the custom data &amp;quot;header&amp;quot; to indicate that this entry can be expanded/collapsed&lt;br /&gt;
			guiGridListSetItemData(gridlistVehicleSelection,row,1,&amp;quot;header&amp;quot;)	&lt;br /&gt;
		&lt;br /&gt;
			-- then, for every group that we find, loop all of its children (the vehicle nodes) and store them in a table&lt;br /&gt;
			for _,vehicle in ipairs(xmlNodeGetChildren(group)) do&lt;br /&gt;
				local vname = xmlNodeGetAttribute(vehicle,&amp;quot;name&amp;quot;)&lt;br /&gt;
				local id = xmlNodeGetAttribute(vehicle,&amp;quot;id&amp;quot;)			&lt;br /&gt;
			&lt;br /&gt;
				-- insert both the vehicle id and the vehicle description into the table&lt;br /&gt;
				table.insert(vehicleTable[name],{id,vname})&lt;br /&gt;
			end&lt;br /&gt;
		end	&lt;br /&gt;
	&lt;br /&gt;
		-- set element data on the gridlist so we know which group is currently showing&lt;br /&gt;
		setElementData(gridlistVehicleSelection,&amp;quot;expanded&amp;quot;,&amp;quot;none&amp;quot;)&lt;br /&gt;
	&lt;br /&gt;
		-- unload the xml file now that we are finished&lt;br /&gt;
		xmlUnloadFile(rootnode)&lt;br /&gt;
	end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Now that we have all the data stored, we can quickly manipulate it when neccessary.&lt;br /&gt;
&lt;br /&gt;
===Managing the double click===&lt;br /&gt;
To enable the player to simply double click on a group name to expand/collapse it we need to use the [[onClientGUIDoubleClick]] event.&lt;br /&gt;
If we attach it to the gridlist, we can then catch any double clicks on the group names in it:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
-- attach the onClientGUIDoubleClick event to the gridlist and set it to call processDoubleClick&lt;br /&gt;
addEventHandler(&amp;quot;onClientGUIDoubleClick&amp;quot;,gridlistVehicleSelection,processDoubleClick,false)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Add this line of code in your createVehicleSelection, after the gridlist has been created.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
As the gridlist items are not separate GUI elements, we must capture all clicks from anywhere on the gridlist then process them to filter out the ones we do not want.&lt;br /&gt;
This can be done by checking if an item is selected, then checking if the item is one of our &amp;quot;group&amp;quot; values (using our previously mentioned &amp;quot;header&amp;quot; data):&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
function processDoubleClick(button,state)&lt;br /&gt;
	if button == &amp;quot;left&amp;quot; and state == &amp;quot;up&amp;quot; then&lt;br /&gt;
		local row,col = guiGridListGetSelectedItem(gridlistVehicleSelection)&lt;br /&gt;
		&lt;br /&gt;
		-- if something in the gridlist has been selected&lt;br /&gt;
		if row and col and row ~= -1 and col ~= -1 then		&lt;br /&gt;
			-- if it is a header&lt;br /&gt;
			if guiGridListGetItemData(gridlistVehicleSelection,row,col) == &amp;quot;header&amp;quot; then&lt;br /&gt;
				local selected = guiGridListGetItemText(gridlistVehicleSelection,row,col)&lt;br /&gt;
				&lt;br /&gt;
				-- call the function to collapse or expand the menu and pass which section it is as an argument&lt;br /&gt;
				changeGridlistState(selected)&lt;br /&gt;
			end&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Once we have narrowed down the double clicks to only those done on our group headers, we can expand/collapse them appropriately.&lt;br /&gt;
This can be done by simply setting new text values in the gridlist according to the newly expanded/collapsed group, which creates the convincing illusion of collapsable menus.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Note that much of the following code is reused from previous areas of this tutorial. While it is generally bad practice to clone sections of code in this way, for the purposes of this example it is far easier to understand.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
function changeGridlistState(group)&lt;br /&gt;
	if group then&lt;br /&gt;
		-- if the group is already expanded, we want to collapse it&lt;br /&gt;
		if getElementData(gridlistVehicleSelection,&amp;quot;expanded&amp;quot;) == group then&lt;br /&gt;
			-- first, we clear all previous data from the gridlist&lt;br /&gt;
			guiGridListClear(gridlistVehicleSelection)&lt;br /&gt;
			&lt;br /&gt;
			-- now, loop all the group entries in the vehicle table that we created earlier&lt;br /&gt;
			for group,_ in pairs(vehicleTable) do&lt;br /&gt;
				-- add each group to the list and mark them with &amp;quot;header&amp;quot;			&lt;br /&gt;
				local row = guiGridListAddRow(gridlistVehicleSelection)&lt;br /&gt;
				&lt;br /&gt;
				guiGridListSetItemText(gridlistVehicleSelection,row,1,group,false,false)	&lt;br /&gt;
				guiGridListSetItemData(gridlistVehicleSelection,row,1,&amp;quot;header&amp;quot;)	&lt;br /&gt;
			end&lt;br /&gt;
			&lt;br /&gt;
			-- update the data to indicate that no groups are currently expanded&lt;br /&gt;
			setElementData(gridlistVehicleSelection,&amp;quot;expanded&amp;quot;,&amp;quot;none&amp;quot;)&lt;br /&gt;
			&lt;br /&gt;
		-- otherwise, we want to expand it&lt;br /&gt;
		else&lt;br /&gt;
			guiGridListClear(gridlistVehicleSelection)&lt;br /&gt;
			&lt;br /&gt;
			local row = guiGridListAddRow(gridlistVehicleSelection)&lt;br /&gt;
			&lt;br /&gt;
			guiGridListSetItemText(gridlistVehicleSelection,row,1,group,false,false)	&lt;br /&gt;
			guiGridListSetItemData(gridlistVehicleSelection,row,1,&amp;quot;header&amp;quot;)				&lt;br /&gt;
			&lt;br /&gt;
			-- loop every vehicle in the specified groups table&lt;br /&gt;
			for _,vehicle in ipairs(vehicleTable[group]) do&lt;br /&gt;
				-- add them to the gridlist and set the vehicle id as data&lt;br /&gt;
				row = guiGridListAddRow(gridlistVehicleSelection)&lt;br /&gt;
			&lt;br /&gt;
				-- format a &amp;quot;-&amp;quot; into the string to make it visually easier to distinguish between groups and vehicles&lt;br /&gt;
				guiGridListSetItemText(gridlistVehicleSelection,row,1,&amp;quot;- &amp;quot;..vehicle[2],false,false)	&lt;br /&gt;
				guiGridListSetItemText(gridlistVehicleSelection,row,2,getVehicleType(tonumber(vehicle[1])),false,false)	&lt;br /&gt;
											&lt;br /&gt;
				guiGridListSetItemData(gridlistVehicleSelection,row,1,tostring(vehicle[1]))&lt;br /&gt;
			end	&lt;br /&gt;
&lt;br /&gt;
			-- update the data to indicate which group is currently expanded&lt;br /&gt;
			setElementData(gridlistVehicleSelection,&amp;quot;expanded&amp;quot;,group)			&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This comletes the second section of the tutorial.&lt;br /&gt;
&lt;br /&gt;
For further GUI tutorials, see [[Scripting the GUI - Tutorial 2|Tutorial 2 (Gates and Keypads)]]&lt;br /&gt;
&lt;br /&gt;
[[Category:GUI_Tutorials]]&lt;/div&gt;</summary>
		<author><name>R3mp</name></author>
	</entry>
	<entry>
		<id>https://wiki.multitheftauto.com/index.php?title=Introduction_to_Scripting_the_GUI_-_Part_2&amp;diff=22194</id>
		<title>Introduction to Scripting the GUI - Part 2</title>
		<link rel="alternate" type="text/html" href="https://wiki.multitheftauto.com/index.php?title=Introduction_to_Scripting_the_GUI_-_Part_2&amp;diff=22194"/>
		<updated>2010-01-06T01:03:38Z</updated>

		<summary type="html">&lt;p&gt;R3mp: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;In this tutorial we will make a simple rules window, with an accept button and a list of all the server rules &amp;amp; information.&lt;br /&gt;
&lt;br /&gt;
==Making the GUI==&lt;br /&gt;
&lt;br /&gt;
===Getting set up===&lt;br /&gt;
The first thing we need to do is create our GUI elements.&lt;br /&gt;
For this tutorial we will be using one [[Element/GUI/Window|window]], one [[Element/GUI/Button|button]] and one [[Element/GUI/Text_label|label]].&lt;br /&gt;
We will be using '''absolute''' position values.&lt;br /&gt;
&lt;br /&gt;
As noted in the [[Introduction to Scripting the GUI|Previous tutorial]], all the GUI must be made client side. &lt;br /&gt;
&lt;br /&gt;
If you are following on from that tutorial, open up your gui.lua file to work with.&lt;br /&gt;
&lt;br /&gt;
If you are not, browse to /Your MTA Server/mods/deathmatch/resources/myserver/ directory, and create a folder named &amp;quot;client&amp;quot;. &lt;br /&gt;
Under /client/ directory, create a text file and name it &amp;quot;gui.lua&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
If you have not already done so, do not forget to include the new gui.lua file in the meta.xml of the main resource, and label it as a client script:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;xml&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;script src=&amp;quot;client/gui.lua&amp;quot; type=&amp;quot;client&amp;quot; /&amp;gt;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Making the window===&lt;br /&gt;
In this file we will write a funtion that draws the window:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
-- create the function that will hold our gui creation code&lt;br /&gt;
function createRulesWindow()&lt;br /&gt;
	-- get the screen width and height&lt;br /&gt;
	local sWidth, sHeight = guiGetScreenSize()&lt;br /&gt;
 &lt;br /&gt;
	-- create the window, using some maths to find the centre of the screen&lt;br /&gt;
	local Width,Height = 445,445&lt;br /&gt;
	local X = (sWidth/2) - (Width/2)&lt;br /&gt;
	local Y = (sHeight/2) - (Height/2)&lt;br /&gt;
&lt;br /&gt;
	-- create the window&lt;br /&gt;
	rulesWindow = guiCreateWindow(X,Y,Width,Height,&amp;quot;Rules&amp;quot;,false)&lt;br /&gt;
	&lt;br /&gt;
	-- stop players from being able to simply move the window out of the way&lt;br /&gt;
	guiWindowSetMovable(rulesWindow,false)&lt;br /&gt;
	&lt;br /&gt;
	-- stop players from being able to resize the window&lt;br /&gt;
	guiWindowSetSizable(rulesWindow,false)&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
This will create a basic window in the centre of the screen that cannot be moved and cannot be resized.&lt;br /&gt;
&lt;br /&gt;
===Making the button===&lt;br /&gt;
Next, we will add the button to the bottom of our window that players can click on to accept the rules:&lt;br /&gt;
&lt;br /&gt;
'''Note that we are now writing more code for our existing 'createRulesWindow' function. This is not a new function and is meant to replace what you already have.'''&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
function createRulesWindow()&lt;br /&gt;
	-- get the screen width and height&lt;br /&gt;
	local sWidth, sHeight = guiGetScreenSize()&lt;br /&gt;
 &lt;br /&gt;
	-- create the window, using some maths to find the centre of the screen&lt;br /&gt;
	local Width,Height = 445,445&lt;br /&gt;
	local X = (sWidth/2) - (Width/2)&lt;br /&gt;
	local Y = (sHeight/2) - (Height/2)&lt;br /&gt;
&lt;br /&gt;
	-- create the window and save the window gui element in a variable called 'rulesWindow'&lt;br /&gt;
	rulesWindow = guiCreateWindow(X,Y,Width,Height,&amp;quot;Rules&amp;quot;,false)&lt;br /&gt;
	&lt;br /&gt;
	-- stop players from being able to simply move the window out of the way&lt;br /&gt;
	-- note that we use our 'rulesWindow' variable to make changes to the window&lt;br /&gt;
	guiWindowSetMovable(rulesWindow,false)&lt;br /&gt;
	&lt;br /&gt;
	-- stop players from being able to resize the window&lt;br /&gt;
	guiWindowSetSizable(rulesWindow,false)&lt;br /&gt;
	&lt;br /&gt;
	-- create the button and save the button gui element in a variable called 'rulesButton'&lt;br /&gt;
	rulesButton = guiCreateButton(137,394,158,37,&amp;quot;Accept&amp;quot;,false,rulesWindow)&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Making the label===&lt;br /&gt;
Next, we will add the label to the centre of our window that our rules will be displayed on:&lt;br /&gt;
&lt;br /&gt;
'''Note that we are now writing more code for our existing 'createRulesWindow' function. This is not a new function and is meant to replace what you already have.'''&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
function createRulesWindow()&lt;br /&gt;
	-- get the screen width and height&lt;br /&gt;
	local sWidth, sHeight = guiGetScreenSize()&lt;br /&gt;
 &lt;br /&gt;
	-- create the window, using some maths to find the centre of the screen&lt;br /&gt;
	local Width,Height = 445,445&lt;br /&gt;
	local X = (sWidth/2) - (Width/2)&lt;br /&gt;
	local Y = (sHeight/2) - (Height/2)&lt;br /&gt;
&lt;br /&gt;
	-- create the window and save the window gui element in a variable called 'rulesWindow'&lt;br /&gt;
	rulesWindow = guiCreateWindow(X,Y,Width,Height,&amp;quot;Rules&amp;quot;,false)&lt;br /&gt;
	&lt;br /&gt;
	-- stop players from being able to simply move the window out of the way&lt;br /&gt;
	-- note that we use our 'rulesWindow' variable to make changes to the window&lt;br /&gt;
	guiWindowSetMovable(rulesWindow,false)&lt;br /&gt;
	&lt;br /&gt;
	-- stop players from being able to resize the window&lt;br /&gt;
	guiWindowSetSizable(rulesWindow,false)&lt;br /&gt;
	&lt;br /&gt;
	-- create the button and save the button gui element in a variable called 'rulesButton'&lt;br /&gt;
	rulesButton = guiCreateButton(137,394,158,37,&amp;quot;Accept&amp;quot;,false,rulesWindow)&lt;br /&gt;
	&lt;br /&gt;
	-- create the label and save the label gui element in a variable called 'rulesLabel'&lt;br /&gt;
	-- we set the text of the label to our rules&lt;br /&gt;
	rulesLabel = guiCreateLabel(10,25,425,359,[[&lt;br /&gt;
	Welcome to my MTA Server!&lt;br /&gt;
&lt;br /&gt;
	Please carefully read the rules before accepting.&lt;br /&gt;
&lt;br /&gt;
	By accepting the rules, you are agreeing to play by them.&lt;br /&gt;
	Anyone caught breaking these rules will be kicked and/or banned from this server.&lt;br /&gt;
&lt;br /&gt;
	If you do not accept the rules within 90 seconds, you will be kicked.&lt;br /&gt;
&lt;br /&gt;
	1: No cheating.&lt;br /&gt;
&lt;br /&gt;
	2: No bug abuse.&lt;br /&gt;
&lt;br /&gt;
	3: No mods to your game.&lt;br /&gt;
&lt;br /&gt;
	4: No flaming.&lt;br /&gt;
&lt;br /&gt;
	5: Respect other players.&lt;br /&gt;
&lt;br /&gt;
	6: Be nice!]],false,rulesWindow)&lt;br /&gt;
	&lt;br /&gt;
	-- set the horizontal alignment of the label to center (ie: in the middle of the window)&lt;br /&gt;
	-- also note the final argument &amp;quot;true&amp;quot; &lt;br /&gt;
	-- this turns on wordwrap so if your text goes over the edge of the label, it will wrap around and start a new line automatically&lt;br /&gt;
	guiLabelSetHorizontalAlign(rulesLabel,&amp;quot;center&amp;quot;,true)	&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
''Note that the text is added in a different way to usual (we are not using quotation marks, &amp;quot;&amp;quot;).''&lt;br /&gt;
&lt;br /&gt;
===Text===&lt;br /&gt;
There are ''two'' ways to define text for a label.&lt;br /&gt;
For most situations, the recommended method is to enter all your text between quotation marks:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
guiSetText(guiElement,&amp;quot;My text here&amp;quot;)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
However, when we want to have more than 1 line in our text, it becomes just as easy to use the second method. &lt;br /&gt;
It is purely dependant on situation and personal choice which method you chose.&lt;br /&gt;
For clarity's sake, i will briefly outline both here.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
When using quotation marks, we can make use of the newline character: &amp;quot;\n&amp;quot;&lt;br /&gt;
This allows us to break onto a new line in our text by entering &amp;quot;\n&amp;quot;. For example:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
guiSetText(guiElement,&amp;quot;This is line 1. \n This is line 2. \n This is line 3.&amp;quot;)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
However, if we use brackets to enclose the text instead of quotation marks, we do not need to worry about entering any extra characters.&lt;br /&gt;
We can simply type the text out as we want it to appear in the label. For example:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
guiSetText(guiElement,[[This is line 1.&lt;br /&gt;
This is line 2.&lt;br /&gt;
This is line 3.]])&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Both of these examples will create exactly the same text on the label.&lt;br /&gt;
It is entirely up to you which method you chose to use.&lt;br /&gt;
&lt;br /&gt;
===Using the function we wrote===&lt;br /&gt;
The createRulesWindow function is now complete, but it won't do anything until we call it. &lt;br /&gt;
It is recommended to create all GUI when the client resource starts, hide them, and show them to the player later when needed. &lt;br /&gt;
&lt;br /&gt;
Therefore, we'll write an event handler for [[onClientResourceStart]] to create the window:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
-- attach the event handler to the root element of the resource&lt;br /&gt;
-- this means it will only trigger when its own resource is started&lt;br /&gt;
addEventHandler(&amp;quot;onClientResourceStart&amp;quot;, getResourceRootElement(getThisResource()), &lt;br /&gt;
	function ()&lt;br /&gt;
		-- call the createRulesWindow function to create our gui&lt;br /&gt;
		createRulesWindow()&lt;br /&gt;
	end&lt;br /&gt;
)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
As this is a rules window, we need to show the window when the player joins the game. &lt;br /&gt;
Fortunately, GUI elements are visible by default so we do not need to write any more code to achieve this.&lt;br /&gt;
&lt;br /&gt;
However, we will also need to show the cursor for the player. &lt;br /&gt;
This can be done using the same event, [[onClientResourceStart]], so we can modify the above code to include showing the cursor:&lt;br /&gt;
&lt;br /&gt;
'''Note that we are now writing more code for our 'onClientResourceStart' event. This is not a new function and is meant to replace what you already have.'''&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
-- attach the event handler to the root element of the resource&lt;br /&gt;
-- this means it will only trigger when its own resource is started&lt;br /&gt;
addEventHandler(&amp;quot;onClientResourceStart&amp;quot;, getResourceRootElement(getThisResource()), &lt;br /&gt;
	function ()&lt;br /&gt;
		-- call the createRulesWindow function to create our gui&lt;br /&gt;
		createRulesWindow()&lt;br /&gt;
		&lt;br /&gt;
		-- show the cursor to the player&lt;br /&gt;
		showCursor(true,true)&lt;br /&gt;
	end&lt;br /&gt;
)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
We now have a completed GUI rules window. Next, we need to write the button functionality for the accept button.&lt;br /&gt;
&lt;br /&gt;
==Scripting the Button==&lt;br /&gt;
Now that we have created our GUI, we need to make it work.&lt;br /&gt;
&lt;br /&gt;
===Detecting the click===&lt;br /&gt;
When the player clicks on any part of the GUI, the event &amp;quot;[[onClientGUIClick]]&amp;quot; will be triggered for the GUI component you clicked on. This allows us to easily detect any clicks on the GUI elements we want to use.&lt;br /&gt;
For example, we can attach the event to the 'rulesButton' button to catch any clicks on it:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
-- attach the event onClientGUIClick to rulesButton and set it to trigger the 'acceptRules' function&lt;br /&gt;
addEventHandler(&amp;quot;onClientGUIClick&amp;quot;, rulesButton, acceptRules, false)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
'''Note the final argument passed is &amp;quot;false&amp;quot;. This indicates that the event will only trigger directly on rulesButton, not if the event has propagated up or down the tree. Setting this to &amp;quot;true&amp;quot; while attaching to gui elements will mean that clicking on any element in the same branch will trigger this event.'''&lt;br /&gt;
&lt;br /&gt;
This line of code can now be added inside the 'createRulesWindow' function. It is a common mistake to try and attach events to non-existant GUI elements, so make sure you always attach your events '''after''' the GUI element (in this case, the button) has been created:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
function createRulesWindow()&lt;br /&gt;
	-- create all our GUI elements&lt;br /&gt;
	...&lt;br /&gt;
&lt;br /&gt;
	-- now add our onClientGUIClick event to the button we just created&lt;br /&gt;
	addEventHandler(&amp;quot;onClientGUIClick&amp;quot;, rulesButton, acceptRules, false)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Managing the click===&lt;br /&gt;
Now that we can detect when the player clicks on the button, we need to write code to manage what happens when they do.&lt;br /&gt;
In our [[onClientGUIClick]] event handle, we told it to call the function 'acceptRules' whenever 'rulesButton' is clicked.&lt;br /&gt;
Therefore, we can now use the function 'acceptRules' to control what happens when the button is clicked:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
-- create the function and define the 'button' and 'state' parameters&lt;br /&gt;
-- (these are passed automatically by onClientGUIClick)&lt;br /&gt;
function acceptRules(button,state)&lt;br /&gt;
	-- if our accept button was clicked with the left mouse button, and the state of the mouse button is up&lt;br /&gt;
	if button == &amp;quot;left&amp;quot; and state == &amp;quot;up&amp;quot; then&lt;br /&gt;
		-- hide the window and all the components&lt;br /&gt;
		guiSetVisible(rulesWindow, false)&lt;br /&gt;
		&lt;br /&gt;
		-- hide the mouse cursor&lt;br /&gt;
		showCursor(false,false)&lt;br /&gt;
		&lt;br /&gt;
		-- output a message to the player&lt;br /&gt;
		outputChatBox(&amp;quot;Thank you for accepting our rules. Have fun!&amp;quot;)&lt;br /&gt;
		&lt;br /&gt;
		&lt;br /&gt;
		-- if the warning timer exists&lt;br /&gt;
		if rulesWarningTimer then&lt;br /&gt;
			-- stop the timer and set the variable to nil&lt;br /&gt;
			-- this is the timer used to kick players who do not accept the rules. We will cover this in more detail in the next section.&lt;br /&gt;
			killTimer(rulesWarningTimer)&lt;br /&gt;
			rulesWarningTimer = nil&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Now, when the button is clicked, the window and the cursor will be hidden.&lt;br /&gt;
&lt;br /&gt;
==Checking for agreement==&lt;br /&gt;
Currently, our window will show when the player joins the server, and they must click accept to remove it.&lt;br /&gt;
However, if they do not accept it they can stay in the server indefinately with the window open.&lt;br /&gt;
&lt;br /&gt;
===Setting a timer===&lt;br /&gt;
To combat this, we will add a timer using [[setTimer]] to kick them from the server after a period of time if they have not accepted the rules.&lt;br /&gt;
First, we will need a global variable to store the timer pointer:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
local rulesWarningTimer = nil&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Put this line at the very top of your script (it does not need to be inside a function)&lt;br /&gt;
&lt;br /&gt;
Next, we will create our timer:&lt;br /&gt;
&lt;br /&gt;
'''Note that we are now writing more code for our existing 'createRulesWindow' function.'''&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
function createRulesWindow()&lt;br /&gt;
	-- create all of our gui&lt;br /&gt;
	...&lt;br /&gt;
	&lt;br /&gt;
	-- set a timer for 30 seconds and set it to call our 'inactivePlayer' function with &amp;quot;1&amp;quot; as an argument&lt;br /&gt;
	rulesWarningTimer = setTimer(inactivePlayer,30000,1,1)&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Put this [[setTimer]] line at the bottom of your 'createRulesWindow' function.&lt;br /&gt;
This will create a timer that will trigger after 30 seconds.&lt;br /&gt;
&lt;br /&gt;
===Giving a warning===&lt;br /&gt;
Now we will write our 'inactivePlayer' function, to administer warnings to the player and finally kick him if he does not accept:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
-- create our function and define the 'status' parameter&lt;br /&gt;
-- the value of status will be passed from our setTimer function call&lt;br /&gt;
function inactivePlayer(status)&lt;br /&gt;
	-- if status is 1 (this means it is the first warning)&lt;br /&gt;
	if status == 1 then&lt;br /&gt;
		-- output a warning&lt;br /&gt;
		outputChatBox(&amp;quot;Please accept our rules or be kicked.&amp;quot;)&lt;br /&gt;
		&lt;br /&gt;
		-- set another timer to call inactivePlayer in another 30 seconds, with &amp;quot;2&amp;quot; as an argument&lt;br /&gt;
		rulesWarningTimer = setTimer(inactivePlayer,30000,1,2)&lt;br /&gt;
		&lt;br /&gt;
	-- if status is 2 (the second warning)&lt;br /&gt;
	elseif status == 2 then&lt;br /&gt;
		-- output a final warning&lt;br /&gt;
		outputChatBox(&amp;quot;FINAL WARNING: Please accept our rules or be kicked.&amp;quot;)&lt;br /&gt;
		&lt;br /&gt;
		-- set a final timer to call inactivePlayer in another 30 seconds, with &amp;quot;3&amp;quot; as an argument&lt;br /&gt;
		rulesWarningTimer = setTimer(inactivePlayer,30000,1,3)	&lt;br /&gt;
	elseif status == 3 then&lt;br /&gt;
		-- trigger the server so we can kick the player&lt;br /&gt;
		triggerServerEvent(&amp;quot;clientKickInactivePlayer&amp;quot;,getLocalPlayer())&lt;br /&gt;
	end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Note the use of [[triggerServerEvent]] to call the server. You should have experience with client-server interaction from the [[Introduction to Scripting the GUI|Previous tutorial]]. &lt;br /&gt;
If not, you can go back and read the full explanation there.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
We have now completed all the clientside code for this tutorial.&lt;br /&gt;
&lt;br /&gt;
===Kicking the player===&lt;br /&gt;
We now need to catch the event on the server that we triggered from the client, so open up a serverside lua file to work with.&lt;br /&gt;
&lt;br /&gt;
To begin, we will add the event on the server:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
-- add the event, note the final argument &amp;quot;true&amp;quot; indicates it can be triggered from the client&lt;br /&gt;
addEvent(&amp;quot;clientKickInactivePlayer&amp;quot;,true)&lt;br /&gt;
-- add an event handler for this event to trigger the kickInactivePlayer function&lt;br /&gt;
addEventHandler(&amp;quot;clientKickInactivePlayer&amp;quot;,root,kickInactivePlayer)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
'''Make sure you add your event handler after you have defined your 'kickInactivePlayer' function.'''&lt;br /&gt;
&lt;br /&gt;
Note the use of [[addEvent]] and [[addEventHandler]] on the server. You should have experience with client-server interaction from the [[Introduction to Scripting the GUI|Previous tutorial]]. &lt;br /&gt;
If not, you can go back and read the full explanation there.&lt;br /&gt;
&lt;br /&gt;
Finally, we will add the 'kickInactivePlayer' function to control kicking of the player:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
-- create our function&lt;br /&gt;
function kickInactivePlayer()&lt;br /&gt;
	-- kick the player&lt;br /&gt;
	kickPlayer(client,&amp;quot;Please accept our rules.&amp;quot;)&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Note the use of the 'client' variable, this is an MTA variable that holds the value of the client (player) that triggered the event.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
'''Note that [[kickPlayer]] will require your resource to have kick access in your ACL.'''&lt;br /&gt;
&lt;br /&gt;
'''This is most easily accomplished by adding your resource into your admin group in the ACL:'''&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;xml&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;group name=&amp;quot;Admin&amp;quot;&amp;gt;&lt;br /&gt;
	...&lt;br /&gt;
    &amp;lt;object name=&amp;quot;resource.YourResourceName&amp;quot; /&amp;gt;&lt;br /&gt;
	...&lt;br /&gt;
&amp;lt;/group&amp;gt;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
For more information on the [[ACL]], see the [[ACL]] wiki page.&lt;br /&gt;
&lt;br /&gt;
That concludes this tutorial. You should now have a fully working rules window for your server.&lt;br /&gt;
&lt;br /&gt;
[[Category:GUI_Tutorials]]&lt;/div&gt;</summary>
		<author><name>R3mp</name></author>
	</entry>
	<entry>
		<id>https://wiki.multitheftauto.com/index.php?title=Introduction_to_Scripting_the_GUI&amp;diff=22193</id>
		<title>Introduction to Scripting the GUI</title>
		<link rel="alternate" type="text/html" href="https://wiki.multitheftauto.com/index.php?title=Introduction_to_Scripting_the_GUI&amp;diff=22193"/>
		<updated>2010-01-06T01:03:17Z</updated>

		<summary type="html">&lt;p&gt;R3mp: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;!-- place holder --&amp;gt;&lt;br /&gt;
One important feature in MTA:SA is the ability to script customized GUI (Graphic User Interface). The GUI consists of windows, button, edit boxes, check boxes... Almost every standard form components in graphical environments. They can be displayed while the user is in game, and used for inputs and outputs in place of traditional commands. &lt;br /&gt;
&lt;br /&gt;
[[Image:AdminGUI.png|thumb|Admin Console GUI]]&lt;br /&gt;
&lt;br /&gt;
==A tutorial to make a login window==&lt;br /&gt;
In this tutorial we'll make a simple login window, with two input boxes and a button. The window appears when the player joins the game, and once the button is clicked, the player is spawned. The tutorial will continue the gamemode we made in [[Scripting Introduction|Introduction to Scripting]] ''(If you have used the [[Scripting Introduction|Introduction to Scripting]], you will need to remove or comment the [[spawnPlayer]] line in the &amp;quot;joinHandler&amp;quot; function in your code, as we will be replacing it with a gui alternative in this tutorial)''. We'll also take a look at client-side scripting. &lt;br /&gt;
&lt;br /&gt;
===Draw the window===&lt;br /&gt;
All the GUI must be made client side. It is also a good practice to keep all the client scripts in a separate folder. Browse to /Your MTA Server/mods/deathmatch/resources/myserver/ directory, and create a folder named &amp;quot;client&amp;quot;. Under /client/ directory, create a text file and name it &amp;quot;gui.lua&amp;quot;, and in this file we will write a funtion that draws the window:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
function createLoginWindow()&lt;br /&gt;
	-- define the X and Y positions of the window&lt;br /&gt;
	local X = 0.375&lt;br /&gt;
	local Y = 0.375&lt;br /&gt;
	-- define the width and height of the window&lt;br /&gt;
	local Width = 0.25&lt;br /&gt;
	local Height = 0.25&lt;br /&gt;
	-- create the window and save its element value into the variable 'wdwLogin'&lt;br /&gt;
	-- click on the function's name to read its documentation&lt;br /&gt;
	wdwLogin = guiCreateWindow(X, Y, Width, Height, &amp;quot;Please Log In&amp;quot;, true)&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Relative and Absolute===&lt;br /&gt;
Note that the final argument passed to guiCreateWindow in the above example is ''true''. This indicates that the coordinates and dimensions of the window are '''relative''', meaning they are a ''percentage'' of the total screen size. This means that if the far left side of the screen is 0, and the far right is 1, an X position of 0.5 would represent the centre point of the screen. Similarly, if the top of the screen is 0 and the bottom is 1, a Y position of 0.2 would be 20% of the way down the screen. The same principles apply to both Width and Height as well (with a Width value of 0.5 meaning the window will be half as wide as the screen).&lt;br /&gt;
&lt;br /&gt;
The alternative to using relative values is using '''absolute''' (by passing ''false'' instead of true to guiCreateWindow). Absolute values are calculated as the total number of pixels from the top-left corner of the parent (if no gui element parent is specified, the parent is the screen itself). If we assume a screen resolution of 1920x1200, the far left side of the screen being 0 pixels and the far right being 1920 pixels, an X position of 960 will represent the centre point of the screen. Similarly, if the top of the screen is 0 pixels and the bottom is 1200, a Y position of 20 would be 20 pixels down from the top of the screen. The same principles apple to both Width and Height as well (with a Width value of 50 meaning the window will be 50 pixels wide). ''You can use [[guiGetScreenSize]] and a little maths to calculate certain absolute positions.''&lt;br /&gt;
&lt;br /&gt;
The differences between using relative and absolute values is quite simple; gui created using absolute values will always remain exactly the same pixel size and position, while gui created using relative values will always be a percentage of its parent's size.&lt;br /&gt;
&lt;br /&gt;
Absolute is generally easier to maintain when editing code by hand, however your choice of type depends on the situation you are using it for.&lt;br /&gt;
&lt;br /&gt;
For the purposes of this introduction we will be using relative values.&lt;br /&gt;
&lt;br /&gt;
===Adding the components===&lt;br /&gt;
Next, we'll add the text labels (saying &amp;quot;username:&amp;quot; and &amp;quot;password:&amp;quot;), edit boxes (for entering your data) and a button to log in: &lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
function createLoginWindow()&lt;br /&gt;
	local X = 0.375&lt;br /&gt;
	local Y = 0.375&lt;br /&gt;
	local Width = 0.25&lt;br /&gt;
	local Height = 0.25&lt;br /&gt;
	wdwLogin = guiCreateWindow(X, Y, Width, Height, &amp;quot;Please Log In&amp;quot;, true)&lt;br /&gt;
	&lt;br /&gt;
	-- define new X and Y positions for the first label&lt;br /&gt;
	X = 0.0825&lt;br /&gt;
	Y = 0.2&lt;br /&gt;
	-- define new Width and Height values for the first label&lt;br /&gt;
	Width = 0.25&lt;br /&gt;
	Height = 0.25&lt;br /&gt;
	-- create the first label, note the final argument passed is 'wdwLogin' meaning the window&lt;br /&gt;
	-- we created above is the parent of this label (so all the position and size values are now relative to the position of that window)&lt;br /&gt;
	guiCreateLabel(X, Y, Width, Height, &amp;quot;Username&amp;quot;, true, wdwLogin)&lt;br /&gt;
	-- alter the Y value, so the second label is slightly below the first&lt;br /&gt;
	Y = 0.5&lt;br /&gt;
	guiCreateLabel(X, Y, Width, Height, &amp;quot;Password&amp;quot;, true, wdwLogin)&lt;br /&gt;
	&lt;br /&gt;
&lt;br /&gt;
	X = 0.415&lt;br /&gt;
	Y = 0.2&lt;br /&gt;
	Width = 0.5&lt;br /&gt;
	Height = 0.15&lt;br /&gt;
	edtUser = guiCreateEdit(X, Y, Width, Height, &amp;quot;&amp;quot;, true, wdwLogin)&lt;br /&gt;
	Y = 0.5&lt;br /&gt;
	edtPass = guiCreateEdit(X, Y, Width, Height, &amp;quot;&amp;quot;, true, wdwLogin)&lt;br /&gt;
	-- set the maximum character length for the username and password fields to 50&lt;br /&gt;
	guiEditSetMaxLength(edtUser, 50)&lt;br /&gt;
	guiEditSetMaxLength(edtPass, 50)&lt;br /&gt;
	&lt;br /&gt;
	X = 0.415&lt;br /&gt;
	Y = 0.7&lt;br /&gt;
	Width = 0.25&lt;br /&gt;
	Height = 0.2&lt;br /&gt;
	btnLogin = guiCreateButton(X, Y, Width, Height, &amp;quot;Log In&amp;quot;, true, wdwLogin)&lt;br /&gt;
	&lt;br /&gt;
	-- make the window invisible&lt;br /&gt;
	guiSetVisible(wdwLogin, false)&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Note that every GUI component created is a child of the window, this is done by specifying the parent element (wdwLogin, in this case) when creating the component. &lt;br /&gt;
&lt;br /&gt;
This is very useful because not only does it mean that all the components are attached to the window and will move with it, but also that any changes done to the parent window will be applied down the tree to these child components. For example, we can now hide all of the GUI we just created by simply hiding the window:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
guiSetVisible(wdwLogin, false) --hides all the GUI we made so we can show them to the player at the appropriate moment. &lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Using the function we wrote===&lt;br /&gt;
The createLoginWindow function is now complete, but it won't do anything until we call it. It is recommended to create all GUI when the client resource starts, hide them, and show them to the player later when needed. Therefore, we'll write an event handler for &amp;quot;[[onClientResourceStart]]&amp;quot; to create the window:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
-- attach the event handler to the root element of the resource&lt;br /&gt;
-- this means it will only trigger when its own resource is started&lt;br /&gt;
addEventHandler(&amp;quot;onClientResourceStart&amp;quot;, getResourceRootElement(getThisResource()), &lt;br /&gt;
	function ()&lt;br /&gt;
		createLoginWindow()&lt;br /&gt;
	end&lt;br /&gt;
)	&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
As this is a log in window, we now need to show the window when the player joins the game. &lt;br /&gt;
This can be done using the same event, &amp;quot;[[onClientResourceStart]]&amp;quot;, so we can modify the above code to include showing the window:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
addEventHandler(&amp;quot;onClientResourceStart&amp;quot;, getResourceRootElement(getThisResource()), &lt;br /&gt;
	function ()&lt;br /&gt;
		-- create the log in window and its components&lt;br /&gt;
		createLoginWindow()&lt;br /&gt;
&lt;br /&gt;
		-- output a brief welcome message to the player&lt;br /&gt;
                outputChatBox(&amp;quot;Welcome to My MTA:SA Server, please log in.&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
		-- if the GUI was successfully created, then show the GUI to the player&lt;br /&gt;
	        if (wdwLogin ~= nil) then&lt;br /&gt;
			guiSetVisible(wdwLogin, true)&lt;br /&gt;
		else&lt;br /&gt;
			-- if the GUI hasnt been properly created, tell the player&lt;br /&gt;
			outputChatBox(&amp;quot;An unexpected error has occurred and the log in GUI has not been created.&amp;quot;)&lt;br /&gt;
	        end &lt;br /&gt;
&lt;br /&gt;
		-- enable the players cursor (so they can select and click on the components)&lt;br /&gt;
	        showCursor(true)&lt;br /&gt;
		-- set the input focus onto the GUI, allowing players (for example) to press 'T' without the chatbox opening&lt;br /&gt;
	        guiSetInputEnabled(true)&lt;br /&gt;
	end&lt;br /&gt;
)	&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Note that we have a simple security check before making the window visible, so in the unlikely event that the window has not been created, meaning wdwLogin is not a valid element, we don't get an error and just inform the player what has happened. &lt;br /&gt;
In the next step, we will create the button functionality for the log in button.&lt;br /&gt;
&lt;br /&gt;
==Scripting the button==&lt;br /&gt;
Now that we have created our GUI and shown it to the player, we need to make it work. &lt;br /&gt;
&lt;br /&gt;
===Detecting the click===&lt;br /&gt;
When the player clicks on any part of the GUI, the event &amp;quot;[[onClientGUIClick]]&amp;quot; will be triggered for the GUI component you clicked on. This allows us to easily detect any clicks on the GUI elements we want to use.&lt;br /&gt;
For example, we can attach the event to the btnLogin button to catch any clicks on it:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
-- attach the event onClientGUIClick to btnLogin and set it to trigger the 'clientSubmitLogin' function&lt;br /&gt;
addEventHandler(&amp;quot;onClientGUIClick&amp;quot;, btnLogin, clientSubmitLogin, false)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
'''Note the final argument passed is &amp;quot;false&amp;quot;. This indicates that the event will only trigger directly on btnLogin, not if the event has propagated up or down the tree. Setting this to &amp;quot;true&amp;quot; while attaching to gui elements will mean that clicking on any element in the same branch will trigger this event.'''&lt;br /&gt;
&lt;br /&gt;
This line of code can now be added inside the createLoginWindow function. It is a common mistake to try and attach events to non-existant GUI elements, so make sure you always attach your events '''after''' the gui element (in this case, the button) has been created:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
function createLoginWindow()&lt;br /&gt;
	-- create all our GUI elements&lt;br /&gt;
	...&lt;br /&gt;
&lt;br /&gt;
	-- now add our onClientGUIClick event to the button we just created&lt;br /&gt;
	addEventHandler(&amp;quot;onClientGUIClick&amp;quot;, btnLogin, clientSubmitLogin, false)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Managing the click===&lt;br /&gt;
Now that we can detect when the player clicks on the button, we need to write code to manage what happens when they do.&lt;br /&gt;
In our [[onClientGUIClick]] event handle, we told it to call the function clientSubmitLogin whenever btnLogin is clicked.&lt;br /&gt;
Therefore, we can now use the function clientSubmitLogin to control what happens when the button is clicked:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
-- create the function and define the 'button' and 'state' parameters&lt;br /&gt;
-- (these are passed automatically by onClientGUIClick)&lt;br /&gt;
function clientSubmitLogin(button,state)&lt;br /&gt;
	-- if our login button was clicked with the left mouse button, and the state of the mouse button is up&lt;br /&gt;
	if button == &amp;quot;left&amp;quot; and state == &amp;quot;up&amp;quot; then&lt;br /&gt;
		-- move the input focus back onto the game (allowing players to move around, open the chatbox, etc)&lt;br /&gt;
		guiSetInputEnabled(false)&lt;br /&gt;
		-- hide the window and all the components&lt;br /&gt;
		guiSetVisible(wdwLogin, false)&lt;br /&gt;
		-- hide the mouse cursor&lt;br /&gt;
		showCursor(false)&lt;br /&gt;
	end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Now, when the button is clicked, the window will be hidden and all controls will be returned to the player. Next, we will tell the server to allow the player to spawn.&lt;br /&gt;
&lt;br /&gt;
===Triggering the server===&lt;br /&gt;
Triggering the server can be done using [[triggerServerEvent]]. This allows you to trigger a specified event on the server from the client. The same can be done in reverse using [[triggerClientEvent]].&lt;br /&gt;
Here, we use the [[triggerServerEvent]] function to call our own custom event on the server, named &amp;quot;submitLogin&amp;quot;, which will then control the spawning of the player serverside.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
function clientSubmitLogin(button,state)&lt;br /&gt;
	if button == &amp;quot;left&amp;quot; and state == &amp;quot;up&amp;quot; then&lt;br /&gt;
		-- get the text entered in the 'username' field&lt;br /&gt;
		local username = guiGetText(edtUser)&lt;br /&gt;
		-- get the text entered in the 'password' field&lt;br /&gt;
		local password = guiGetText(edtPass)&lt;br /&gt;
&lt;br /&gt;
		-- if the username and password both exist&lt;br /&gt;
		if username and password then&lt;br /&gt;
			-- trigger the server event 'submitLogin' and pass the username and password to it&lt;br /&gt;
			triggerServerEvent(&amp;quot;submitLogin&amp;quot;, getRootElement(), username, password)&lt;br /&gt;
&lt;br /&gt;
			-- hide the gui, hide the cursor and return control to the player&lt;br /&gt;
			guiSetInputEnabled(false)&lt;br /&gt;
			guiSetVisible(wdwLogin, false)&lt;br /&gt;
			showCursor(false)&lt;br /&gt;
		else&lt;br /&gt;
			-- otherwise, output a message to the player, do not trigger the server&lt;br /&gt;
			-- and do not hide the gui&lt;br /&gt;
			outputChatBox(&amp;quot;Please enter a username and password.&amp;quot;)&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Creating the serverside event===&lt;br /&gt;
At this point we now have all the code needed on the client side, so open up your serverside 'script.lua' file (from the [[Scripting Introduction|Introduction to Scripting]]) or another suitable serverside file to work with.&lt;br /&gt;
&lt;br /&gt;
On the server side, recall that we are spawning the player as soon as they login.&lt;br /&gt;
So, first of all, we will need to define the custom event that we used before on the client. This can be done using [[addEvent]] and [[addEventHandler]].&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
-- create our loginHandler function, with username and password parameters (passed from the client gui)&lt;br /&gt;
function loginHandler(username,password)&lt;br /&gt;
&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
-- define our custom event, and allow it to be triggered from the client ('true')&lt;br /&gt;
addEvent(&amp;quot;submitLogin&amp;quot;,true)&lt;br /&gt;
-- add an event handler so that when submitLogin is triggered, the function loginHandler is called&lt;br /&gt;
addEventHandler(&amp;quot;submitLogin&amp;quot;,root,loginHandler)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Logging in===&lt;br /&gt;
Now we have a function that is called through the custom event 'submitLogin', we can start to work on logging in and spawning the player, using our 'loginHandler' function:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
function loginHandler(username,password)&lt;br /&gt;
	-- check that the username and password are correct&lt;br /&gt;
	if username == &amp;quot;user&amp;quot; and password == &amp;quot;apple&amp;quot; then&lt;br /&gt;
		-- the player has successfully logged in, so spawn them&lt;br /&gt;
		if (client) then&lt;br /&gt;
			spawnPlayer(client, 1959.55, -1714.46, 10)&lt;br /&gt;
			fadeCamera(client, true)&lt;br /&gt;
			outputChatBox(&amp;quot;Welcome to My Server.&amp;quot;, client)&lt;br /&gt;
		end&lt;br /&gt;
	else&lt;br /&gt;
		-- if the username or password are not correct, output a message to the player&lt;br /&gt;
		outputChatBox(&amp;quot;Invalid username and password. Please re-connect and try again.&amp;quot;,client)&lt;br /&gt;
        end			&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
addEvent(&amp;quot;submitLogin&amp;quot;,true)&lt;br /&gt;
addEventHandler(&amp;quot;submitLogin&amp;quot;,root,loginHandler)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
'''For the purposes of this tutorial, a very basic username and password system is shown. For a more comprehensive alternative, you can use the Account System or a MySQL database.'''&lt;br /&gt;
&lt;br /&gt;
Also note the use of the variable &amp;quot;client&amp;quot;, it's an internal variable used by MTA to identify the player who triggered the event. &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Finally, do not forget to include the new gui.lua file in the meta.xml of the main resource, and label it as a client script:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;xml&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;script src=&amp;quot;client/gui.lua&amp;quot; type=&amp;quot;client&amp;quot; /&amp;gt;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
At this point, we now have a basic login window that checks the player's username and password when the login button is clicked. If they are correct, the player is automatically spawned.&lt;br /&gt;
&lt;br /&gt;
For further GUI tutorials, see [[Scripting the GUI - Tutorial 1|Scripting the GUI - Tutorial 1 (Gridlists)]]&lt;br /&gt;
&lt;br /&gt;
[[Category:GUI_Tutorials]]&lt;br /&gt;
[[it:Introduzione_allo_scripting_della_GUI]]&lt;br /&gt;
[[ru:Introduction to Scripting the GUI]]&lt;/div&gt;</summary>
		<author><name>R3mp</name></author>
	</entry>
	<entry>
		<id>https://wiki.multitheftauto.com/index.php?title=Category:GUI_Tutorials&amp;diff=22192</id>
		<title>Category:GUI Tutorials</title>
		<link rel="alternate" type="text/html" href="https://wiki.multitheftauto.com/index.php?title=Category:GUI_Tutorials&amp;diff=22192"/>
		<updated>2010-01-06T01:02:38Z</updated>

		<summary type="html">&lt;p&gt;R3mp: Created page with 'These are a set of tutorials with information on how to include and manipulate GUI elements in your resources.'&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;These are a set of tutorials with information on how to include and manipulate [[GUI widgets|GUI elements]] in your resources.&lt;/div&gt;</summary>
		<author><name>R3mp</name></author>
	</entry>
	<entry>
		<id>https://wiki.multitheftauto.com/index.php?title=Introduction_to_Scripting_the_GUI_-_Part_2&amp;diff=22191</id>
		<title>Introduction to Scripting the GUI - Part 2</title>
		<link rel="alternate" type="text/html" href="https://wiki.multitheftauto.com/index.php?title=Introduction_to_Scripting_the_GUI_-_Part_2&amp;diff=22191"/>
		<updated>2010-01-06T00:49:10Z</updated>

		<summary type="html">&lt;p&gt;R3mp: Created page with 'In this tutorial we will make a simple rules window, with an accept button and a list of all the server rules &amp;amp; information.  ==Making the GUI==  ===Getting set up=== The first t…'&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;In this tutorial we will make a simple rules window, with an accept button and a list of all the server rules &amp;amp; information.&lt;br /&gt;
&lt;br /&gt;
==Making the GUI==&lt;br /&gt;
&lt;br /&gt;
===Getting set up===&lt;br /&gt;
The first thing we need to do is create our GUI elements.&lt;br /&gt;
For this tutorial we will be using one [[Element/GUI/Window|window]], one [[Element/GUI/Button|button]] and one [[Element/GUI/Text_label|label]].&lt;br /&gt;
We will be using '''absolute''' position values.&lt;br /&gt;
&lt;br /&gt;
As noted in the [[Introduction to Scripting the GUI|Previous tutorial]], all the GUI must be made client side. &lt;br /&gt;
&lt;br /&gt;
If you are following on from that tutorial, open up your gui.lua file to work with.&lt;br /&gt;
&lt;br /&gt;
If you are not, browse to /Your MTA Server/mods/deathmatch/resources/myserver/ directory, and create a folder named &amp;quot;client&amp;quot;. &lt;br /&gt;
Under /client/ directory, create a text file and name it &amp;quot;gui.lua&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
If you have not already done so, do not forget to include the new gui.lua file in the meta.xml of the main resource, and label it as a client script:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;xml&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;script src=&amp;quot;client/gui.lua&amp;quot; type=&amp;quot;client&amp;quot; /&amp;gt;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Making the window===&lt;br /&gt;
In this file we will write a funtion that draws the window:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
-- create the function that will hold our gui creation code&lt;br /&gt;
function createRulesWindow()&lt;br /&gt;
	-- get the screen width and height&lt;br /&gt;
	local sWidth, sHeight = guiGetScreenSize()&lt;br /&gt;
 &lt;br /&gt;
	-- create the window, using some maths to find the centre of the screen&lt;br /&gt;
	local Width,Height = 445,445&lt;br /&gt;
	local X = (sWidth/2) - (Width/2)&lt;br /&gt;
	local Y = (sHeight/2) - (Height/2)&lt;br /&gt;
&lt;br /&gt;
	-- create the window&lt;br /&gt;
	rulesWindow = guiCreateWindow(X,Y,Width,Height,&amp;quot;Rules&amp;quot;,false)&lt;br /&gt;
	&lt;br /&gt;
	-- stop players from being able to simply move the window out of the way&lt;br /&gt;
	guiWindowSetMovable(rulesWindow,false)&lt;br /&gt;
	&lt;br /&gt;
	-- stop players from being able to resize the window&lt;br /&gt;
	guiWindowSetSizable(rulesWindow,false)&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
This will create a basic window in the centre of the screen that cannot be moved and cannot be resized.&lt;br /&gt;
&lt;br /&gt;
===Making the button===&lt;br /&gt;
Next, we will add the button to the bottom of our window that players can click on to accept the rules:&lt;br /&gt;
&lt;br /&gt;
'''Note that we are now writing more code for our existing 'createRulesWindow' function. This is not a new function and is meant to replace what you already have.'''&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
function createRulesWindow()&lt;br /&gt;
	-- get the screen width and height&lt;br /&gt;
	local sWidth, sHeight = guiGetScreenSize()&lt;br /&gt;
 &lt;br /&gt;
	-- create the window, using some maths to find the centre of the screen&lt;br /&gt;
	local Width,Height = 445,445&lt;br /&gt;
	local X = (sWidth/2) - (Width/2)&lt;br /&gt;
	local Y = (sHeight/2) - (Height/2)&lt;br /&gt;
&lt;br /&gt;
	-- create the window and save the window gui element in a variable called 'rulesWindow'&lt;br /&gt;
	rulesWindow = guiCreateWindow(X,Y,Width,Height,&amp;quot;Rules&amp;quot;,false)&lt;br /&gt;
	&lt;br /&gt;
	-- stop players from being able to simply move the window out of the way&lt;br /&gt;
	-- note that we use our 'rulesWindow' variable to make changes to the window&lt;br /&gt;
	guiWindowSetMovable(rulesWindow,false)&lt;br /&gt;
	&lt;br /&gt;
	-- stop players from being able to resize the window&lt;br /&gt;
	guiWindowSetSizable(rulesWindow,false)&lt;br /&gt;
	&lt;br /&gt;
	-- create the button and save the button gui element in a variable called 'rulesButton'&lt;br /&gt;
	rulesButton = guiCreateButton(137,394,158,37,&amp;quot;Accept&amp;quot;,false,rulesWindow)&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Making the label===&lt;br /&gt;
Next, we will add the label to the centre of our window that our rules will be displayed on:&lt;br /&gt;
&lt;br /&gt;
'''Note that we are now writing more code for our existing 'createRulesWindow' function. This is not a new function and is meant to replace what you already have.'''&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
function createRulesWindow()&lt;br /&gt;
	-- get the screen width and height&lt;br /&gt;
	local sWidth, sHeight = guiGetScreenSize()&lt;br /&gt;
 &lt;br /&gt;
	-- create the window, using some maths to find the centre of the screen&lt;br /&gt;
	local Width,Height = 445,445&lt;br /&gt;
	local X = (sWidth/2) - (Width/2)&lt;br /&gt;
	local Y = (sHeight/2) - (Height/2)&lt;br /&gt;
&lt;br /&gt;
	-- create the window and save the window gui element in a variable called 'rulesWindow'&lt;br /&gt;
	rulesWindow = guiCreateWindow(X,Y,Width,Height,&amp;quot;Rules&amp;quot;,false)&lt;br /&gt;
	&lt;br /&gt;
	-- stop players from being able to simply move the window out of the way&lt;br /&gt;
	-- note that we use our 'rulesWindow' variable to make changes to the window&lt;br /&gt;
	guiWindowSetMovable(rulesWindow,false)&lt;br /&gt;
	&lt;br /&gt;
	-- stop players from being able to resize the window&lt;br /&gt;
	guiWindowSetSizable(rulesWindow,false)&lt;br /&gt;
	&lt;br /&gt;
	-- create the button and save the button gui element in a variable called 'rulesButton'&lt;br /&gt;
	rulesButton = guiCreateButton(137,394,158,37,&amp;quot;Accept&amp;quot;,false,rulesWindow)&lt;br /&gt;
	&lt;br /&gt;
	-- create the label and save the label gui element in a variable called 'rulesLabel'&lt;br /&gt;
	-- we set the text of the label to our rules&lt;br /&gt;
	rulesLabel = guiCreateLabel(10,25,425,359,[[&lt;br /&gt;
	Welcome to my MTA Server!&lt;br /&gt;
&lt;br /&gt;
	Please carefully read the rules before accepting.&lt;br /&gt;
&lt;br /&gt;
	By accepting the rules, you are agreeing to play by them.&lt;br /&gt;
	Anyone caught breaking these rules will be kicked and/or banned from this server.&lt;br /&gt;
&lt;br /&gt;
	If you do not accept the rules within 90 seconds, you will be kicked.&lt;br /&gt;
&lt;br /&gt;
	1: No cheating.&lt;br /&gt;
&lt;br /&gt;
	2: No bug abuse.&lt;br /&gt;
&lt;br /&gt;
	3: No mods to your game.&lt;br /&gt;
&lt;br /&gt;
	4: No flaming.&lt;br /&gt;
&lt;br /&gt;
	5: Respect other players.&lt;br /&gt;
&lt;br /&gt;
	6: Be nice!]],false,rulesWindow)&lt;br /&gt;
	&lt;br /&gt;
	-- set the horizontal alignment of the label to center (ie: in the middle of the window)&lt;br /&gt;
	-- also note the final argument &amp;quot;true&amp;quot; &lt;br /&gt;
	-- this turns on wordwrap so if your text goes over the edge of the label, it will wrap around and start a new line automatically&lt;br /&gt;
	guiLabelSetHorizontalAlign(rulesLabel,&amp;quot;center&amp;quot;,true)	&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
''Note that the text is added in a different way to usual (we are not using quotation marks, &amp;quot;&amp;quot;).''&lt;br /&gt;
&lt;br /&gt;
===Text===&lt;br /&gt;
There are ''two'' ways to define text for a label.&lt;br /&gt;
For most situations, the recommended method is to enter all your text between quotation marks:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
guiSetText(guiElement,&amp;quot;My text here&amp;quot;)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
However, when we want to have more than 1 line in our text, it becomes just as easy to use the second method. &lt;br /&gt;
It is purely dependant on situation and personal choice which method you chose.&lt;br /&gt;
For clarity's sake, i will briefly outline both here.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
When using quotation marks, we can make use of the newline character: &amp;quot;\n&amp;quot;&lt;br /&gt;
This allows us to break onto a new line in our text by entering &amp;quot;\n&amp;quot;. For example:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
guiSetText(guiElement,&amp;quot;This is line 1. \n This is line 2. \n This is line 3.&amp;quot;)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
However, if we use brackets to enclose the text instead of quotation marks, we do not need to worry about entering any extra characters.&lt;br /&gt;
We can simply type the text out as we want it to appear in the label. For example:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
guiSetText(guiElement,[[This is line 1.&lt;br /&gt;
This is line 2.&lt;br /&gt;
This is line 3.]])&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Both of these examples will create exactly the same text on the label.&lt;br /&gt;
It is entirely up to you which method you chose to use.&lt;br /&gt;
&lt;br /&gt;
===Using the function we wrote===&lt;br /&gt;
The createRulesWindow function is now complete, but it won't do anything until we call it. &lt;br /&gt;
It is recommended to create all GUI when the client resource starts, hide them, and show them to the player later when needed. &lt;br /&gt;
&lt;br /&gt;
Therefore, we'll write an event handler for [[onClientResourceStart]] to create the window:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
-- attach the event handler to the root element of the resource&lt;br /&gt;
-- this means it will only trigger when its own resource is started&lt;br /&gt;
addEventHandler(&amp;quot;onClientResourceStart&amp;quot;, getResourceRootElement(getThisResource()), &lt;br /&gt;
	function ()&lt;br /&gt;
		-- call the createRulesWindow function to create our gui&lt;br /&gt;
		createRulesWindow()&lt;br /&gt;
	end&lt;br /&gt;
)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
As this is a rules window, we need to show the window when the player joins the game. &lt;br /&gt;
Fortunately, GUI elements are visible by default so we do not need to write any more code to achieve this.&lt;br /&gt;
&lt;br /&gt;
However, we will also need to show the cursor for the player. &lt;br /&gt;
This can be done using the same event, [[onClientResourceStart]], so we can modify the above code to include showing the cursor:&lt;br /&gt;
&lt;br /&gt;
'''Note that we are now writing more code for our 'onClientResourceStart' event. This is not a new function and is meant to replace what you already have.'''&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
-- attach the event handler to the root element of the resource&lt;br /&gt;
-- this means it will only trigger when its own resource is started&lt;br /&gt;
addEventHandler(&amp;quot;onClientResourceStart&amp;quot;, getResourceRootElement(getThisResource()), &lt;br /&gt;
	function ()&lt;br /&gt;
		-- call the createRulesWindow function to create our gui&lt;br /&gt;
		createRulesWindow()&lt;br /&gt;
		&lt;br /&gt;
		-- show the cursor to the player&lt;br /&gt;
		showCursor(true,true)&lt;br /&gt;
	end&lt;br /&gt;
)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
We now have a completed GUI rules window. Next, we need to write the button functionality for the accept button.&lt;br /&gt;
&lt;br /&gt;
==Scripting the Button==&lt;br /&gt;
Now that we have created our GUI, we need to make it work.&lt;br /&gt;
&lt;br /&gt;
===Detecting the click===&lt;br /&gt;
When the player clicks on any part of the GUI, the event &amp;quot;[[onClientGUIClick]]&amp;quot; will be triggered for the GUI component you clicked on. This allows us to easily detect any clicks on the GUI elements we want to use.&lt;br /&gt;
For example, we can attach the event to the 'rulesButton' button to catch any clicks on it:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
-- attach the event onClientGUIClick to rulesButton and set it to trigger the 'acceptRules' function&lt;br /&gt;
addEventHandler(&amp;quot;onClientGUIClick&amp;quot;, rulesButton, acceptRules, false)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
'''Note the final argument passed is &amp;quot;false&amp;quot;. This indicates that the event will only trigger directly on rulesButton, not if the event has propagated up or down the tree. Setting this to &amp;quot;true&amp;quot; while attaching to gui elements will mean that clicking on any element in the same branch will trigger this event.'''&lt;br /&gt;
&lt;br /&gt;
This line of code can now be added inside the 'createRulesWindow' function. It is a common mistake to try and attach events to non-existant GUI elements, so make sure you always attach your events '''after''' the GUI element (in this case, the button) has been created:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
function createRulesWindow()&lt;br /&gt;
	-- create all our GUI elements&lt;br /&gt;
	...&lt;br /&gt;
&lt;br /&gt;
	-- now add our onClientGUIClick event to the button we just created&lt;br /&gt;
	addEventHandler(&amp;quot;onClientGUIClick&amp;quot;, rulesButton, acceptRules, false)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Managing the click===&lt;br /&gt;
Now that we can detect when the player clicks on the button, we need to write code to manage what happens when they do.&lt;br /&gt;
In our [[onClientGUIClick]] event handle, we told it to call the function 'acceptRules' whenever 'rulesButton' is clicked.&lt;br /&gt;
Therefore, we can now use the function 'acceptRules' to control what happens when the button is clicked:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
-- create the function and define the 'button' and 'state' parameters&lt;br /&gt;
-- (these are passed automatically by onClientGUIClick)&lt;br /&gt;
function acceptRules(button,state)&lt;br /&gt;
	-- if our accept button was clicked with the left mouse button, and the state of the mouse button is up&lt;br /&gt;
	if button == &amp;quot;left&amp;quot; and state == &amp;quot;up&amp;quot; then&lt;br /&gt;
		-- hide the window and all the components&lt;br /&gt;
		guiSetVisible(rulesWindow, false)&lt;br /&gt;
		&lt;br /&gt;
		-- hide the mouse cursor&lt;br /&gt;
		showCursor(false,false)&lt;br /&gt;
		&lt;br /&gt;
		-- output a message to the player&lt;br /&gt;
		outputChatBox(&amp;quot;Thank you for accepting our rules. Have fun!&amp;quot;)&lt;br /&gt;
		&lt;br /&gt;
		&lt;br /&gt;
		-- if the warning timer exists&lt;br /&gt;
		if rulesWarningTimer then&lt;br /&gt;
			-- stop the timer and set the variable to nil&lt;br /&gt;
			-- this is the timer used to kick players who do not accept the rules. We will cover this in more detail in the next section.&lt;br /&gt;
			killTimer(rulesWarningTimer)&lt;br /&gt;
			rulesWarningTimer = nil&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Now, when the button is clicked, the window and the cursor will be hidden.&lt;br /&gt;
&lt;br /&gt;
==Checking for agreement==&lt;br /&gt;
Currently, our window will show when the player joins the server, and they must click accept to remove it.&lt;br /&gt;
However, if they do not accept it they can stay in the server indefinately with the window open.&lt;br /&gt;
&lt;br /&gt;
===Setting a timer===&lt;br /&gt;
To combat this, we will add a timer using [[setTimer]] to kick them from the server after a period of time if they have not accepted the rules.&lt;br /&gt;
First, we will need a global variable to store the timer pointer:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
local rulesWarningTimer = nil&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Put this line at the very top of your script (it does not need to be inside a function)&lt;br /&gt;
&lt;br /&gt;
Next, we will create our timer:&lt;br /&gt;
&lt;br /&gt;
'''Note that we are now writing more code for our existing 'createRulesWindow' function.'''&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
function createRulesWindow()&lt;br /&gt;
	-- create all of our gui&lt;br /&gt;
	...&lt;br /&gt;
	&lt;br /&gt;
	-- set a timer for 30 seconds and set it to call our 'inactivePlayer' function with &amp;quot;1&amp;quot; as an argument&lt;br /&gt;
	rulesWarningTimer = setTimer(inactivePlayer,30000,1,1)&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Put this [[setTimer]] line at the bottom of your 'createRulesWindow' function.&lt;br /&gt;
This will create a timer that will trigger after 30 seconds.&lt;br /&gt;
&lt;br /&gt;
===Giving a warning===&lt;br /&gt;
Now we will write our 'inactivePlayer' function, to administer warnings to the player and finally kick him if he does not accept:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
-- create our function and define the 'status' parameter&lt;br /&gt;
-- the value of status will be passed from our setTimer function call&lt;br /&gt;
function inactivePlayer(status)&lt;br /&gt;
	-- if status is 1 (this means it is the first warning)&lt;br /&gt;
	if status == 1 then&lt;br /&gt;
		-- output a warning&lt;br /&gt;
		outputChatBox(&amp;quot;Please accept our rules or be kicked.&amp;quot;)&lt;br /&gt;
		&lt;br /&gt;
		-- set another timer to call inactivePlayer in another 30 seconds, with &amp;quot;2&amp;quot; as an argument&lt;br /&gt;
		rulesWarningTimer = setTimer(inactivePlayer,30000,1,2)&lt;br /&gt;
		&lt;br /&gt;
	-- if status is 2 (the second warning)&lt;br /&gt;
	elseif status == 2 then&lt;br /&gt;
		-- output a final warning&lt;br /&gt;
		outputChatBox(&amp;quot;FINAL WARNING: Please accept our rules or be kicked.&amp;quot;)&lt;br /&gt;
		&lt;br /&gt;
		-- set a final timer to call inactivePlayer in another 30 seconds, with &amp;quot;3&amp;quot; as an argument&lt;br /&gt;
		rulesWarningTimer = setTimer(inactivePlayer,30000,1,3)	&lt;br /&gt;
	elseif status == 3 then&lt;br /&gt;
		-- trigger the server so we can kick the player&lt;br /&gt;
		triggerServerEvent(&amp;quot;clientKickInactivePlayer&amp;quot;,getLocalPlayer())&lt;br /&gt;
	end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Note the use of [[triggerServerEvent]] to call the server. You should have experience with client-server interaction from the [[Introduction to Scripting the GUI|Previous tutorial]]. &lt;br /&gt;
If not, you can go back and read the full explanation there.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
We have now completed all the clientside code for this tutorial.&lt;br /&gt;
&lt;br /&gt;
===Kicking the player===&lt;br /&gt;
We now need to catch the event on the server that we triggered from the client, so open up a serverside lua file to work with.&lt;br /&gt;
&lt;br /&gt;
To begin, we will add the event on the server:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
-- add the event, note the final argument &amp;quot;true&amp;quot; indicates it can be triggered from the client&lt;br /&gt;
addEvent(&amp;quot;clientKickInactivePlayer&amp;quot;,true)&lt;br /&gt;
-- add an event handler for this event to trigger the kickInactivePlayer function&lt;br /&gt;
addEventHandler(&amp;quot;clientKickInactivePlayer&amp;quot;,root,kickInactivePlayer)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
'''Make sure you add your event handler after you have defined your 'kickInactivePlayer' function.'''&lt;br /&gt;
&lt;br /&gt;
Note the use of [[addEvent]] and [[addEventHandler]] on the server. You should have experience with client-server interaction from the [[Introduction to Scripting the GUI|Previous tutorial]]. &lt;br /&gt;
If not, you can go back and read the full explanation there.&lt;br /&gt;
&lt;br /&gt;
Finally, we will add the 'kickInactivePlayer' function to control kicking of the player:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
-- create our function&lt;br /&gt;
function kickInactivePlayer()&lt;br /&gt;
	-- kick the player&lt;br /&gt;
	kickPlayer(client,&amp;quot;Please accept our rules.&amp;quot;)&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Note the use of the 'client' variable, this is an MTA variable that holds the value of the client (player) that triggered the event.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
'''Note that [[kickPlayer]] will require your resource to have kick access in your ACL.'''&lt;br /&gt;
&lt;br /&gt;
'''This is most easily accomplished by adding your resource into your admin group in the ACL:'''&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;xml&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;group name=&amp;quot;Admin&amp;quot;&amp;gt;&lt;br /&gt;
	...&lt;br /&gt;
    &amp;lt;object name=&amp;quot;resource.YourResourceName&amp;quot; /&amp;gt;&lt;br /&gt;
	...&lt;br /&gt;
&amp;lt;/group&amp;gt;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
For more information on the [[ACL]], see the [[ACL]] wiki page.&lt;br /&gt;
&lt;br /&gt;
That concludes this tutorial. You should now have a fully working rules window for your server.&lt;/div&gt;</summary>
		<author><name>R3mp</name></author>
	</entry>
	<entry>
		<id>https://wiki.multitheftauto.com/index.php?title=Scripting_the_GUI_-_Tutorial_3&amp;diff=22190</id>
		<title>Scripting the GUI - Tutorial 3</title>
		<link rel="alternate" type="text/html" href="https://wiki.multitheftauto.com/index.php?title=Scripting_the_GUI_-_Tutorial_3&amp;diff=22190"/>
		<updated>2010-01-05T22:44:11Z</updated>

		<summary type="html">&lt;p&gt;R3mp: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;'''Scripting the GUI - Tutorial 3 (Scrolling News Feed)'''&lt;br /&gt;
&lt;br /&gt;
In this tutorial we will explore how to create a simple scrolling news feed GUI, &lt;br /&gt;
allowing you to quickly and easily show server updates and other server information to your players.&lt;br /&gt;
We will store all news items in a clientside xml file and use some simple xml reading to load them into the game.&lt;br /&gt;
&lt;br /&gt;
We will then animate the news item to scroll along the bottom of the screen, updating the news text once it has scrolled beyond the edge of the screen.&lt;br /&gt;
&lt;br /&gt;
'''Note that this tutorial assumes you are familiar with all the content covered in the [[Introduction to Scripting GUI|GUI Scripting Introduction]].'''&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Setting up the News Feed==&lt;br /&gt;
To begin, open up a clientside lua file (if you have been following the [[Introduction to Scripting GUI|GUI Scripting Introduction]], this is gui.lua) to work with.&lt;br /&gt;
&lt;br /&gt;
===Creating the GUI===&lt;br /&gt;
As with the previous tutorial, you should be suitably familiar with GUI creation already so we will not go into too much detail here. &lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
function createNewsFeed()&lt;br /&gt;
	-- get the screen width and height&lt;br /&gt;
	local sWidth, sHeight = guiGetScreenSize()&lt;br /&gt;
 &lt;br /&gt;
	-- create the gridlist, using some maths to find the bottom-centre of the screen&lt;br /&gt;
	local Width,Height = 800,45&lt;br /&gt;
	local X = (sWidth/2) - (Width/2)&lt;br /&gt;
	local Y = sHeight - (Height/2)&lt;br /&gt;
	&lt;br /&gt;
	-- the gridlist will act as the background to our news reel&lt;br /&gt;
	newsGridlist = guiCreateGridList(X,Y,Width,Height,false)&lt;br /&gt;
	&lt;br /&gt;
	-- create the label in the same place, but as a child of the gridlist&lt;br /&gt;
	-- also make it half the height of the gridlist, as half of the gridlist is off the bottom of the screen&lt;br /&gt;
	newsLabel = guiCreateLabel(X,Y,Width,Height/2,&amp;quot;Test text&amp;quot;,false,newsGridlist)&lt;br /&gt;
	&lt;br /&gt;
	-- call our function to read the news out of the xml file&lt;br /&gt;
	loadNews()&lt;br /&gt;
	&lt;br /&gt;
	-- load the first news item in the table&lt;br /&gt;
	updateNewsItem(1)&lt;br /&gt;
	&lt;br /&gt;
	-- define a global variable called 'currentItem' with the value 1&lt;br /&gt;
	currentItem = 1&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
addEventHandler(&amp;quot;onClientResourceStart&amp;quot;,resourceRoot,createNewsFeed)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Note that the label is created as a child of the gridlist. &lt;br /&gt;
Not only is this good practice in general, but it means that we can freely move parts of the label beyond the edge of the gridlist without them showing, which is critical to the visual effect of this tutorial.&lt;br /&gt;
&lt;br /&gt;
Also notice the use of the 'resourceRoot' variable. This is an MTA variable that holds the root element value of the resource you are using it in.&lt;br /&gt;
&lt;br /&gt;
The 'currentItem' variable is what we will use to keep track of which news item we are currently showing&lt;br /&gt;
&lt;br /&gt;
===Writing the News===&lt;br /&gt;
Now that we have our GUI created, we need some news to fill it with.&lt;br /&gt;
To do this, we will read our news items out of a clientside xml file.&lt;br /&gt;
&lt;br /&gt;
So, navigate to your resource directory and create a new xml file called newsfeed.xml (don't forget to add it to your meta.xml with the appropriate client tag).&lt;br /&gt;
&lt;br /&gt;
Inside this file enter the following information:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;root&amp;gt;&lt;br /&gt;
	&amp;lt;news&amp;gt;This is an example news item.&amp;lt;/news&amp;gt;&lt;br /&gt;
	&amp;lt;news&amp;gt;From the 'Scripting the GUI' tutorial.&amp;lt;/news&amp;gt;&lt;br /&gt;
	&amp;lt;news&amp;gt;Showing scrolling news text.&amp;lt;/news&amp;gt;&lt;br /&gt;
	&amp;lt;news&amp;gt;Written on a GUI news feed.&amp;lt;/news&amp;gt;&lt;br /&gt;
&amp;lt;/root&amp;gt;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
As you can see, each news item is defined as a &amp;lt;news&amp;gt; node with the value being the news text you want to display.&lt;br /&gt;
There is no limit on how many news items you can add.&lt;br /&gt;
&lt;br /&gt;
===Collecting the News===&lt;br /&gt;
Once we have written all our news items, we will need to collect them all and store them in a table on the client.&lt;br /&gt;
We will do this when the resource starts, saving us from having to repeatedly access the xml for new news items.&lt;br /&gt;
&lt;br /&gt;
First, we need to define a table to store the items in:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
local newsItems = {}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Add this line to the top of your script.&lt;br /&gt;
Make sure it is not inside a function otherwise it will not exist outside of that function (as denoted by the prefix &amp;quot;local&amp;quot;).&lt;br /&gt;
When defined in the main body of the script it will exist in all functions.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Next, we will need to load the xml file:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
function loadNews()&lt;br /&gt;
	-- load our &amp;quot;newsfeed.xml&amp;quot; file&lt;br /&gt;
	local newsfile = xmlLoadFile(&amp;quot;newsfeed.xml&amp;quot;)&lt;br /&gt;
	&lt;br /&gt;
	-- if it was successfully loaded&lt;br /&gt;
	if newsfile then&lt;br /&gt;
	&lt;br /&gt;
		-- always remember to unload files once you are finished&lt;br /&gt;
		xmlUnloadFile(newsfile)&lt;br /&gt;
	end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
'''Always remember to unload files once you are finished using them.'''&lt;br /&gt;
&lt;br /&gt;
Finally, we can add some more code to our loadNews function to read the news items into our newsItems table:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
function loadNews()&lt;br /&gt;
	local newsfile = xmlLoadFile(&amp;quot;newsfeed.xml&amp;quot;)&lt;br /&gt;
	&lt;br /&gt;
	if newsfile then&lt;br /&gt;
		-- loop through all the children of the root node (the &amp;quot;news&amp;quot; nodes)&lt;br /&gt;
		for index,itemNode in ipairs(xmlNodeGetChildren(newsfile)) do&lt;br /&gt;
			-- get the text (the news item) from the node&lt;br /&gt;
			local item = xmlNodeGetValue(itemNode)&lt;br /&gt;
			&lt;br /&gt;
			-- insert it into our newsItems table&lt;br /&gt;
			table.insert(newsItems,item)&lt;br /&gt;
		end&lt;br /&gt;
	&lt;br /&gt;
		xmlUnloadFile(newsfile)&lt;br /&gt;
	end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
We now have a table called 'newsItems' holding all of our news text from the xml file.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Updating the News==&lt;br /&gt;
Now that we have our GUI created and our news items ready, we need to write some code to update the news item being shown to players.&lt;br /&gt;
As stated earlier, our news items will be shown on our 'newsLabel' GUI label.&lt;br /&gt;
&lt;br /&gt;
To do this, we will write a simple function to get the next news item from our 'newsItems' table and display it in our label.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
-- define our function with a newIndex parameter, so that we can pass which news item we want to show&lt;br /&gt;
function updateNewsItem(newIndex)&lt;br /&gt;
	-- get the new news item from the table&lt;br /&gt;
	local item = newsItems[newIndex]&lt;br /&gt;
	&lt;br /&gt;
	-- update the label text&lt;br /&gt;
	guiSetText(newsLabel,item)&lt;br /&gt;
	&lt;br /&gt;
	-- update the 'currentItem' global variable&lt;br /&gt;
	currentItem = newIndex&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Sizing the Label===&lt;br /&gt;
To make our news scrolling as accurate as possible, we need to be able to make the GUI label the same size as the news item text it is showing.&lt;br /&gt;
&lt;br /&gt;
While this may seem like a tricky thing to do, it is made very easy with the function [[guiLabelGetTextExtent]].&lt;br /&gt;
This will tell us the extent, or width, of the text currently shown in our label.&lt;br /&gt;
So with a few modifications to our 'updateNewsItems' function, we get:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
function updateNewsItem(newIndex)&lt;br /&gt;
	local item = newsItems[newIndex]&lt;br /&gt;
	&lt;br /&gt;
	guiSetText(newsLabel,item)&lt;br /&gt;
	&lt;br /&gt;
	currentItem = newIndex&lt;br /&gt;
	&lt;br /&gt;
	-- get the current dimensions of the gui label&lt;br /&gt;
	local width,height = guiGetSize(newsLabel,false)&lt;br /&gt;
	&lt;br /&gt;
	-- get the text width of the label&lt;br /&gt;
	local extent = guiLabelGetTextExtent(newsLabel)&lt;br /&gt;
	&lt;br /&gt;
	-- update the size of the label with the new width (we do not change the height)&lt;br /&gt;
	guiSetSize(newsLabel,extent,height,false)&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Positioning the Label===&lt;br /&gt;
Now that our GUI label is the correct width, we need to move it to a position where it is ready to scroll onto the screen.&lt;br /&gt;
&lt;br /&gt;
Again, we can do this with a small modification to our 'updateNewsItems' function:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
function updateNewsItem(newIndex)&lt;br /&gt;
	local item = newsItems[newIndex]&lt;br /&gt;
	&lt;br /&gt;
	guiSetText(newsLabel,item)&lt;br /&gt;
	&lt;br /&gt;
	currentItem = newIndex&lt;br /&gt;
	&lt;br /&gt;
	local width,height = guiGetSize(newsLabel,false)&lt;br /&gt;
	&lt;br /&gt;
	local extent = guiLabelGetTextExtent(newsLabel)&lt;br /&gt;
	&lt;br /&gt;
	guiSetSize(newsLabel,extent,height,false)&lt;br /&gt;
	&lt;br /&gt;
	-- set the positon to the far right side of the gridlist, ready to scroll on to the left&lt;br /&gt;
	guiSetPosition(newsLabel,1,0,true)&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Note the use of '''relative''' position values in the final line of the function. &lt;br /&gt;
&lt;br /&gt;
In this case, it is far easier than calculating pixel values.&lt;br /&gt;
&lt;br /&gt;
You can use both relative and absolute in the same script if you want to, the only limitation is that you cannot mix them in the same function call. The type of values you are using is defined by the final argument (true or false).&lt;br /&gt;
 &lt;br /&gt;
This means you cannot do the following and have it set to 400 pixels in, but 0.5% down&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
guiSetPosition(yourElement,400,0.5,false)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
The final argument &amp;quot;false&amp;quot; means both 400 and 0.5 will be read as pixel values.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Scrolling the News==&lt;br /&gt;
The next step is to animate our news feed.&lt;br /&gt;
&lt;br /&gt;
===Looking at Frames===&lt;br /&gt;
To do this, we will introduce a new event: [[onClientRender]].&lt;br /&gt;
As stated on the [[onClientRender]] wiki page, this event is called every time GTA renders a new frame (ie: very often).&lt;br /&gt;
&lt;br /&gt;
As usual, to use this event we will need to create an event handler for it:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
addEventHandler(&amp;quot;onClientRender&amp;quot;,root,scrollNews)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
This will call our scrollNews function every frame, which we will then use to update the position of our news item.&lt;br /&gt;
&lt;br /&gt;
'''Make sure you add this handler after you have defined your scrollNews function.'''&lt;br /&gt;
&lt;br /&gt;
For our purposes, [[onClientRender]] has one main advantage over, for example, [[setTimer]].&lt;br /&gt;
As it is called every frame (and therefore is dependant on the players FPS), the movement of the news item will always appear to be completely smooth,&lt;br /&gt;
unlike using a timer which would often appear to lag.&lt;br /&gt;
&lt;br /&gt;
===Moving the News===&lt;br /&gt;
In our 'updateNewsItem' function, we position the 'newsLabel' to the far right, so we will scroll in from the right to the left.&lt;br /&gt;
&lt;br /&gt;
For this we will simply move the X position by -1 every frame:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
function scrollNews()&lt;br /&gt;
	-- if the newsLabel exists&lt;br /&gt;
	if newsLabel then&lt;br /&gt;
		-- get the current position of the label&lt;br /&gt;
		local x,y = guiGetPosition(newsLabel,false)&lt;br /&gt;
		&lt;br /&gt;
		-- set the new x position of the label as the old position -1&lt;br /&gt;
		guiSetPosition(newsLabel,x-1,y,false)&lt;br /&gt;
	end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Looping around===&lt;br /&gt;
Now that our news scrolls across the screen, we need to be able to check when it has scrolled too far to the left&lt;br /&gt;
so we can start scrolling from the far-right side again.&lt;br /&gt;
&lt;br /&gt;
We will also need to update the news item, so we should check the next item exists, and if it doesn't, go back to the first.&lt;br /&gt;
&lt;br /&gt;
For this we will use some simple maths in a modification to our 'scrollNews' function:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
function scrollNews()&lt;br /&gt;
	local x,y = guiGetPosition(newsLabel,false)&lt;br /&gt;
	&lt;br /&gt;
	local labelWidth, labelHeight = guiGetSize(newsLabel,false)&lt;br /&gt;
	&lt;br /&gt;
	-- if the far right position of the label (x + labelWidth) is greater than or equal to 0 (ie: still showing on the gridlist)&lt;br /&gt;
	if ((x-1) + labelWidth) &amp;gt;= 0 then&lt;br /&gt;
		-- compensate for a small off-by-one bug in MTA&lt;br /&gt;
		if x &amp;lt;= 0 then x = x - 1 end&lt;br /&gt;
		&lt;br /&gt;
		-- update the position as normal&lt;br /&gt;
		guiSetPosition(newsLabel,x-1,y,false)&lt;br /&gt;
		&lt;br /&gt;
	-- otherwise, we move on to the next item and reset the position&lt;br /&gt;
	else&lt;br /&gt;
		-- get the total number of items in the 'newsItems' table&lt;br /&gt;
		local totalItems = #newsItems&lt;br /&gt;
		&lt;br /&gt;
		-- if the next item on our list does not exist in our table&lt;br /&gt;
		if (currentItem + 1) &amp;gt; totalItems then&lt;br /&gt;
			-- loop back to the first item in the list&lt;br /&gt;
			updateNewsItem(1)&lt;br /&gt;
		else&lt;br /&gt;
			-- otherwise move onto the next item in the list&lt;br /&gt;
			updateNewsItem(currentItem + 1)&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Notice the use of the '#' symbol to get the size of the 'newsItems' table. &lt;br /&gt;
This is the Lua length operator, but it only works on tables that have numerical indexes (like an array or a list).&lt;br /&gt;
It also works on strings, eg: #&amp;quot;hello&amp;quot; would return 5.&lt;br /&gt;
&lt;br /&gt;
That completes this section of the tutorial.&lt;br /&gt;
For ideas on how to further improve and advance this code, continue reading the next section.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Improving the code==&lt;br /&gt;
This section will detail several ways to improve upon the code you now have.&lt;br /&gt;
&lt;br /&gt;
===GUI Customisation===&lt;br /&gt;
To give your GUI a more unique feel, you have the ability to customise some aspects of your GUI elements.&lt;br /&gt;
&lt;br /&gt;
For ideas on what is possible, browse the [[Client_Scripting_Functions#GUI_functions|MTA GUI functions]].&lt;br /&gt;
&lt;br /&gt;
For the purposes of this tutorial, we will be using Font, Colour and Alpha.&lt;br /&gt;
&lt;br /&gt;
To start, we will change the alpha of the background gridlist GUI element we are using.&lt;br /&gt;
To set the alpha, use [[guiSetAlpha]] and pass a value between 1 and 0; 1 being fully opaque and 0 being fully transparent.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
guiSetAlpha(newsGridlist,0.8)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Place this line of code in your 'createNewsFeed' function, after your gridlist has been created.&lt;br /&gt;
&lt;br /&gt;
I find an alpha level of 0.8 looks best, however this is personal preference and you can experiment to suit your needs.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Next, we will look at the font of the label text.&lt;br /&gt;
To set the font, use [[guiSetFont]] and pass the string name of the font you want to use (available to see on the [[GUI Fonts]] page).&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
guiSetFont(newsLabel,&amp;quot;default-bold-small&amp;quot;)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Place this line of code in your 'createNewsFeed' function, after your label has been created.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Finally, we will look at setting the colour of the label text.&lt;br /&gt;
To set the colour, use [[guiLabelSetColor]] and pass the individual red,green and blue values.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
guiLabelSetColor(newsLabel,255,70,0)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Place this line of code in your 'createNewsFeed' function, after your label has been created.&lt;br /&gt;
&lt;br /&gt;
This will give your news items an orange-red colour.&lt;br /&gt;
&lt;br /&gt;
===Multiple News Items===&lt;br /&gt;
In its current form, this code is only capable of showing one news item at a time.&lt;br /&gt;
However, with a few modifications we can show multiple news items at once, one after another.&lt;br /&gt;
&lt;br /&gt;
To begin with, we need to make sure we have a 'newItems' table defined at the very start of our script,&lt;br /&gt;
as well as a 'distance' variable that will control the pixel distance between each news item:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
local newsItems = {}&lt;br /&gt;
local distance = 30&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
So put these lines at the top of the file.&lt;br /&gt;
&lt;br /&gt;
Next, we will not know how many items we have (and consequently, how many labels we need) until we have loaded the file.&lt;br /&gt;
With that in mind, we will move around some of the code in our 'createNewsFeed' function to support this:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
function createNewsFeed()&lt;br /&gt;
	-- get the screen width and height&lt;br /&gt;
	local sWidth, sHeight = guiGetScreenSize()&lt;br /&gt;
 &lt;br /&gt;
	-- create the gridlist, using some maths to find the bottom-centre of the screen&lt;br /&gt;
	local Width,Height = 800,45&lt;br /&gt;
	local X = (sWidth/2) - (Width/2)&lt;br /&gt;
	local Y = sHeight - (Height/2)&lt;br /&gt;
	&lt;br /&gt;
	-- the gridlist will act as the background to our news reel&lt;br /&gt;
	newsGridlist = guiCreateGridList(X,Y,Width,Height,false)&lt;br /&gt;
	&lt;br /&gt;
	guiSetAlpha(newsGridlist,0.8)&lt;br /&gt;
	&lt;br /&gt;
	-- call our function to read the news out of the xml file, before we create the labels&lt;br /&gt;
	loadNews()&lt;br /&gt;
		&lt;br /&gt;
	-- define a table to hold our labels&lt;br /&gt;
	newsLabel = {}&lt;br /&gt;
	&lt;br /&gt;
	-- now we can loop all our news items, and create a label for each one&lt;br /&gt;
	for index,item in ipairs(newsItems) do&lt;br /&gt;
	&lt;br /&gt;
		-- because we now have one label for every item, we can just set the text here and it wont need to be changed again.&lt;br /&gt;
		newsLabel[index] = guiCreateLabel(0,0,Width,Height/2,item,false,newsGridlist)&lt;br /&gt;
		&lt;br /&gt;
		guiSetFont(newsLabel[index],&amp;quot;default-bold-small&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
		guiLabelSetColor(newsLabel[index],255,70,0)		&lt;br /&gt;
&lt;br /&gt;
		-- modify the width of the label to fit the text&lt;br /&gt;
		local extent = guiLabelGetTextExtent(newsLabel[index])		&lt;br /&gt;
		guiSetSize(newsLabel[index],extent,Height/2,false)&lt;br /&gt;
		&lt;br /&gt;
		&lt;br /&gt;
		-- get the size of the gridlist&lt;br /&gt;
		local x,y = guiGetSize(newsGridlist,false)&lt;br /&gt;
		&lt;br /&gt;
		-- loop from 1 until index-1 in steps of 1&lt;br /&gt;
		-- this allows us to loop every label before the label we are currently on&lt;br /&gt;
		for i=1, index-1, 1 do&lt;br /&gt;
			-- tally up the sizes of all labels before our current one and store them in x&lt;br /&gt;
			local width = guiGetSize(newsLabel[i],false)&lt;br /&gt;
			x = x + width&lt;br /&gt;
		end&lt;br /&gt;
		&lt;br /&gt;
		-- put a 'distance' pixel gap between each news item&lt;br /&gt;
		x = x + (distance*(index-1))&lt;br /&gt;
		&lt;br /&gt;
		-- set the positon to the far right side of the gridlist, ready to scroll on to the left&lt;br /&gt;
		guiSetPosition(newsLabel[index],x,0,false)	&lt;br /&gt;
	end	&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Now we need to update our 'updateNewsItem' function to account for having multiple labels:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
function updateNewsItem(newIndex)&lt;br /&gt;
	-- find the index of the news item directly infront (in the looping order) of the newIndex item&lt;br /&gt;
	local index = newIndex - 1&lt;br /&gt;
	if index == 0 then index = #newsItems end&lt;br /&gt;
	&lt;br /&gt;
	-- find the position of the right-edge of the label directly infront of the newIndex label&lt;br /&gt;
	local x = guiGetPosition(newsLabel[index],false) &lt;br /&gt;
	local width = guiGetSize(newsLabel[index],false)&lt;br /&gt;
	x = x + width&lt;br /&gt;
&lt;br /&gt;
	-- add a 'distance' pixel gap in&lt;br /&gt;
	x = x + distance&lt;br /&gt;
&lt;br /&gt;
	-- check the new position isnt actually on the gridlist (ie: so it wont suddenly appear in the centre of the list)&lt;br /&gt;
	local gridlistWidth = guiGetSize(newsGridlist,false)&lt;br /&gt;
	&lt;br /&gt;
	if x &amp;lt; gridlistWidth then&lt;br /&gt;
		-- if it is, simple move it back to the edge&lt;br /&gt;
		x = gridlistWidth&lt;br /&gt;
	end&lt;br /&gt;
	&lt;br /&gt;
	-- set the new position&lt;br /&gt;
	guiSetPosition(newsLabel[newIndex],x,0,false)&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Finally, we need to make some small adjustments to our 'scrollNews' function:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
function scrollNews()&lt;br /&gt;
	if newsItems then&lt;br /&gt;
		-- loop every news item&lt;br /&gt;
		for index,item in ipairs(newsItems) do&lt;br /&gt;
			local x,y = guiGetPosition(newsLabel[index],false)&lt;br /&gt;
			&lt;br /&gt;
			local labelWidth, labelHeight = guiGetSize(newsLabel[index],false)&lt;br /&gt;
			&lt;br /&gt;
			-- if the far right position of the label (x + labelWidth) is greater than or equal to 0 (ie: still showing on the gridlist)&lt;br /&gt;
			if ((x-1) + labelWidth) &amp;gt;= 0 then&lt;br /&gt;
				-- compensate for a small off-by-one bug in MTA&lt;br /&gt;
				if x &amp;lt;= 0 then x = x - 1 end&lt;br /&gt;
			&lt;br /&gt;
				-- update the position as normal&lt;br /&gt;
				guiSetPosition(newsLabel[index],x-1,y,false)&lt;br /&gt;
				&lt;br /&gt;
			-- otherwise, we move on to the next item and reset the position&lt;br /&gt;
			else&lt;br /&gt;
				updateNewsItem(index)&lt;br /&gt;
			end&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
You should now have multiple news items scrolling along your news feed simultaneously.&lt;br /&gt;
&lt;br /&gt;
===Globally controlled scroll speed===&lt;br /&gt;
As with the 'distance' variable above, we can set a global variable for controlling the scroll speed of the news items as well.&lt;br /&gt;
Note that the speed will still be dependant on the players FPS (ie: lower FPS means slightly slower scrolling).&lt;br /&gt;
&lt;br /&gt;
To do this, we simply need to create the variable at the start of our code:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
local scrollSpeed = 1&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Put this line at the top of your file.&lt;br /&gt;
&lt;br /&gt;
Then, we just replace the instance of &amp;quot;x-1&amp;quot; in our 'scrollNews' function with &amp;quot;x-scrollSpeed&amp;quot;:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
function scrollNews()&lt;br /&gt;
		...&lt;br /&gt;
				-- update the position as normal&lt;br /&gt;
				guiSetPosition(newsLabel[index],x-scrollSpeed,y,false)&lt;br /&gt;
		...&lt;br /&gt;
	end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
That concludes this section of the tutorial.&lt;/div&gt;</summary>
		<author><name>R3mp</name></author>
	</entry>
	<entry>
		<id>https://wiki.multitheftauto.com/index.php?title=Scripting_the_GUI_-_Tutorial_3&amp;diff=22189</id>
		<title>Scripting the GUI - Tutorial 3</title>
		<link rel="alternate" type="text/html" href="https://wiki.multitheftauto.com/index.php?title=Scripting_the_GUI_-_Tutorial_3&amp;diff=22189"/>
		<updated>2010-01-05T22:43:19Z</updated>

		<summary type="html">&lt;p&gt;R3mp: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;'''Scripting the GUI - Tutorial 3 (Scrolling News Feed)'''&lt;br /&gt;
&lt;br /&gt;
In this tutorial we will explore how to create a simple scrolling news feed GUI, &lt;br /&gt;
allowing you to quickly and easily show server updates and other server information to your players.&lt;br /&gt;
We will store all news items in a clientside xml file and use some simple xml reading to load them into the game.&lt;br /&gt;
&lt;br /&gt;
We will then animate the news item to scroll along the bottom of the screen, updating the news text once it has scrolled beyond the edge of the screen.&lt;br /&gt;
&lt;br /&gt;
'''Note that this tutorial assumes you are familiar with all the content covered in the [[Introduction to Scripting GUI|GUI Scripting Introduction]].'''&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Setting up the News Feed==&lt;br /&gt;
To begin, open up a clientside lua file (if you have been following the [[Introduction to Scripting GUI|GUI Scripting Introduction]], this is gui.lua) to work with.&lt;br /&gt;
&lt;br /&gt;
===Creating the GUI===&lt;br /&gt;
As with the previous tutorial, you should be suitably familiar with GUI creation already so we will not go into too much detail here. &lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
function createNewsFeed()&lt;br /&gt;
	-- get the screen width and height&lt;br /&gt;
	local sWidth, sHeight = guiGetScreenSize()&lt;br /&gt;
 &lt;br /&gt;
	-- create the gridlist, using some maths to find the bottom-centre of the screen&lt;br /&gt;
	local Width,Height = 800,45&lt;br /&gt;
	local X = (sWidth/2) - (Width/2)&lt;br /&gt;
	local Y = sHeight - (Height/2)&lt;br /&gt;
	&lt;br /&gt;
	-- the gridlist will act as the background to our news reel&lt;br /&gt;
	newsGridlist = guiCreateGridList(X,Y,Width,Height,false)&lt;br /&gt;
	&lt;br /&gt;
	-- create the label in the same place, but as a child of the gridlist&lt;br /&gt;
	-- also make it half the height of the gridlist, as half of the gridlist is off the bottom of the screen&lt;br /&gt;
	newsLabel = guiCreateLabel(X,Y,Width,Height/2,&amp;quot;Test text&amp;quot;,false,newsGridlist)&lt;br /&gt;
	&lt;br /&gt;
	-- call our function to read the news out of the xml file&lt;br /&gt;
	loadNews()&lt;br /&gt;
	&lt;br /&gt;
	-- load the first news item in the table&lt;br /&gt;
	updateNewsItem(1)&lt;br /&gt;
	&lt;br /&gt;
	-- define a global variable called 'currentItem' with the value 1&lt;br /&gt;
	currentItem = 1&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
addEventHandler(&amp;quot;onClientResourceStart&amp;quot;,resourceRoot,createNewsFeed)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Note that the label is created as a child of the gridlist. &lt;br /&gt;
Not only is this good practice in general, but it means that we can freely move parts of the label beyond the edge of the gridlist without them showing, which is critical to the visual effect of this tutorial.&lt;br /&gt;
&lt;br /&gt;
Also notice the use of the 'resourceRoot' variable. This is an MTA variable that holds the root element value of the resource you are using it in.&lt;br /&gt;
&lt;br /&gt;
The 'currentItem' variable is what we will use to keep track of which news item we are currently showing&lt;br /&gt;
&lt;br /&gt;
===Writing the News===&lt;br /&gt;
Now that we have our GUI created, we need some news to fill it with.&lt;br /&gt;
To do this, we will read our news items out of a clientside xml file.&lt;br /&gt;
&lt;br /&gt;
So, navigate to your resource directory and create a new xml file called newsfeed.xml (don't forget to add it to your meta.xml with the appropriate client tag).&lt;br /&gt;
&lt;br /&gt;
Inside this file enter the following information:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;root&amp;gt;&lt;br /&gt;
	&amp;lt;news&amp;gt;This is an example news item.&amp;lt;/news&amp;gt;&lt;br /&gt;
	&amp;lt;news&amp;gt;From the 'Scripting the GUI' tutorial.&amp;lt;/news&amp;gt;&lt;br /&gt;
	&amp;lt;news&amp;gt;Showing scrolling news text.&amp;lt;/news&amp;gt;&lt;br /&gt;
	&amp;lt;news&amp;gt;Written on a GUI news feed.&amp;lt;/news&amp;gt;&lt;br /&gt;
&amp;lt;/root&amp;gt;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
As you can see, each news item is defined as a &amp;lt;news&amp;gt; node with the value being the news text you want to display.&lt;br /&gt;
There is no limit on how many news items you can add.&lt;br /&gt;
&lt;br /&gt;
===Collecting the News===&lt;br /&gt;
Once we have written all our news items, we will need to collect them all and store them in a table on the client.&lt;br /&gt;
We will do this when the resource starts, saving us from having to repeatedly access the xml for new news items.&lt;br /&gt;
&lt;br /&gt;
First, we need to define a table to store the items in:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
local newsItems = {}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Add this line to the top of your script.&lt;br /&gt;
Make sure it is not inside a function otherwise it will not exist outside of that function (as denoted by the prefix &amp;quot;local&amp;quot;).&lt;br /&gt;
When defined in the main body of the script it will exist in all functions.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Next, we will need to load the xml file:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
function loadNews()&lt;br /&gt;
	-- load our &amp;quot;newsfeed.xml&amp;quot; file&lt;br /&gt;
	local newsfile = xmlLoadFile(&amp;quot;newsfeed.xml&amp;quot;)&lt;br /&gt;
	&lt;br /&gt;
	-- if it was successfully loaded&lt;br /&gt;
	if newsfile then&lt;br /&gt;
	&lt;br /&gt;
		-- always remember to unload files once you are finished&lt;br /&gt;
		xmlUnloadFile(newsfile)&lt;br /&gt;
	end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
'''Always remember to unload files once you are finished using them.'''&lt;br /&gt;
&lt;br /&gt;
Finally, we can add some more code to our loadNews function to read the news items into our newsItems table:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
function loadNews()&lt;br /&gt;
	local newsfile = xmlLoadFile(&amp;quot;newsfeed.xml&amp;quot;)&lt;br /&gt;
	&lt;br /&gt;
	if newsfile then&lt;br /&gt;
		-- loop through all the children of the root node (the &amp;quot;news&amp;quot; nodes)&lt;br /&gt;
		for index,itemNode in ipairs(xmlNodeGetChildren(newsfile)) do&lt;br /&gt;
			-- get the text (the news item) from the node&lt;br /&gt;
			local item = xmlNodeGetValue(itemNode)&lt;br /&gt;
			&lt;br /&gt;
			-- insert it into our newsItems table&lt;br /&gt;
			table.insert(newsItems,item)&lt;br /&gt;
		end&lt;br /&gt;
	&lt;br /&gt;
		xmlUnloadFile(newsfile)&lt;br /&gt;
	end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
We now have a table called 'newsItems' holding all of our news text from the xml file.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Updating the News==&lt;br /&gt;
Now that we have our GUI created and our news items ready, we need to write some code to update the news item being shown to players.&lt;br /&gt;
As stated earlier, our news items will be shown on our 'newsLabel' GUI label.&lt;br /&gt;
&lt;br /&gt;
To do this, we will write a simple function to get the next news item from our 'newsItems' table and display it in our label.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
-- define our function with a newIndex parameter, so that we can pass which news item we want to show&lt;br /&gt;
function updateNewsItem(newIndex)&lt;br /&gt;
	-- get the new news item from the table&lt;br /&gt;
	local item = newsItems[newIndex]&lt;br /&gt;
	&lt;br /&gt;
	-- update the label text&lt;br /&gt;
	guiSetText(newsLabel,item)&lt;br /&gt;
	&lt;br /&gt;
	-- update the 'currentItem' global variable&lt;br /&gt;
	currentItem = newIndex&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Sizing the Label===&lt;br /&gt;
To make our news scrolling as accurate as possible, we need to be able to make the GUI label the same size as the news item text it is showing.&lt;br /&gt;
&lt;br /&gt;
While this may seem like a tricky thing to do, it is made very easy with the function [[guiLabelGetTextExtent]].&lt;br /&gt;
This will tell us the extent, or width, of the text currently shown in our label.&lt;br /&gt;
So with a few modifications to our 'updateNewsItems' function, we get:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
function updateNewsItem(newIndex)&lt;br /&gt;
	local item = newsItems[newIndex]&lt;br /&gt;
	&lt;br /&gt;
	guiSetText(newsLabel,item)&lt;br /&gt;
	&lt;br /&gt;
	currentItem = newIndex&lt;br /&gt;
	&lt;br /&gt;
	-- get the current dimensions of the gui label&lt;br /&gt;
	local width,height = guiGetSize(newsLabel,false)&lt;br /&gt;
	&lt;br /&gt;
	-- get the text width of the label&lt;br /&gt;
	local extent = guiLabelGetTextExtent(newsLabel)&lt;br /&gt;
	&lt;br /&gt;
	-- update the size of the label with the new width (we do not change the height)&lt;br /&gt;
	guiSetSize(newsLabel,extent,height,false)&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Positioning the Label===&lt;br /&gt;
Now that our GUI label is the correct width, we need to move it to a position where it is ready to scroll onto the screen.&lt;br /&gt;
&lt;br /&gt;
Again, we can do this with a small modification to our 'updateNewsItems' function:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
function updateNewsItem(newIndex)&lt;br /&gt;
	local item = newsItems[newIndex]&lt;br /&gt;
	&lt;br /&gt;
	guiSetText(newsLabel,item)&lt;br /&gt;
	&lt;br /&gt;
	currentItem = newIndex&lt;br /&gt;
	&lt;br /&gt;
	local width,height = guiGetSize(newsLabel,false)&lt;br /&gt;
	&lt;br /&gt;
	local extent = guiLabelGetTextExtent(newsLabel)&lt;br /&gt;
	&lt;br /&gt;
	guiSetSize(newsLabel,extent,height,false)&lt;br /&gt;
	&lt;br /&gt;
	-- set the positon to the far right side of the gridlist, ready to scroll on to the left&lt;br /&gt;
	guiSetPosition(newsLabel,1,0,true)&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Note the use of '''relative''' position values in the final line of the function. &lt;br /&gt;
&lt;br /&gt;
In this case, it is far easier than calculating pixel values.&lt;br /&gt;
&lt;br /&gt;
You can use both relative and absolute in the same script if you want to, the only limitation is that you cannot mix them in the same function call. The type of values you are using is defined by the final argument (true or false).&lt;br /&gt;
 &lt;br /&gt;
This means you cannot do the following and have it set to 400 pixels in, but 0.5% down&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
guiSetPosition(yourElement,400,0.5,false)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
The final argument &amp;quot;true&amp;quot; means both 400 and 0.5 will be read as pixel values.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Scrolling the News==&lt;br /&gt;
The next step is to animate our news feed.&lt;br /&gt;
&lt;br /&gt;
===Looking at Frames===&lt;br /&gt;
To do this, we will introduce a new event: [[onClientRender]].&lt;br /&gt;
As stated on the [[onClientRender]] wiki page, this event is called every time GTA renders a new frame (ie: very often).&lt;br /&gt;
&lt;br /&gt;
As usual, to use this event we will need to create an event handler for it:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
addEventHandler(&amp;quot;onClientRender&amp;quot;,root,scrollNews)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
This will call our scrollNews function every frame, which we will then use to update the position of our news item.&lt;br /&gt;
&lt;br /&gt;
'''Make sure you add this handler after you have defined your scrollNews function.'''&lt;br /&gt;
&lt;br /&gt;
For our purposes, [[onClientRender]] has one main advantage over, for example, [[setTimer]].&lt;br /&gt;
As it is called every frame (and therefore is dependant on the players FPS), the movement of the news item will always appear to be completely smooth,&lt;br /&gt;
unlike using a timer which would often appear to lag.&lt;br /&gt;
&lt;br /&gt;
===Moving the News===&lt;br /&gt;
In our 'updateNewsItem' function, we position the 'newsLabel' to the far right, so we will scroll in from the right to the left.&lt;br /&gt;
&lt;br /&gt;
For this we will simply move the X position by -1 every frame:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
function scrollNews()&lt;br /&gt;
	-- if the newsLabel exists&lt;br /&gt;
	if newsLabel then&lt;br /&gt;
		-- get the current position of the label&lt;br /&gt;
		local x,y = guiGetPosition(newsLabel,false)&lt;br /&gt;
		&lt;br /&gt;
		-- set the new x position of the label as the old position -1&lt;br /&gt;
		guiSetPosition(newsLabel,x-1,y,false)&lt;br /&gt;
	end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Looping around===&lt;br /&gt;
Now that our news scrolls across the screen, we need to be able to check when it has scrolled too far to the left&lt;br /&gt;
so we can start scrolling from the far-right side again.&lt;br /&gt;
&lt;br /&gt;
We will also need to update the news item, so we should check the next item exists, and if it doesn't, go back to the first.&lt;br /&gt;
&lt;br /&gt;
For this we will use some simple maths in a modification to our 'scrollNews' function:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
function scrollNews()&lt;br /&gt;
	local x,y = guiGetPosition(newsLabel,false)&lt;br /&gt;
	&lt;br /&gt;
	local labelWidth, labelHeight = guiGetSize(newsLabel,false)&lt;br /&gt;
	&lt;br /&gt;
	-- if the far right position of the label (x + labelWidth) is greater than or equal to 0 (ie: still showing on the gridlist)&lt;br /&gt;
	if ((x-1) + labelWidth) &amp;gt;= 0 then&lt;br /&gt;
		-- compensate for a small off-by-one bug in MTA&lt;br /&gt;
		if x &amp;lt;= 0 then x = x - 1 end&lt;br /&gt;
		&lt;br /&gt;
		-- update the position as normal&lt;br /&gt;
		guiSetPosition(newsLabel,x-1,y,false)&lt;br /&gt;
		&lt;br /&gt;
	-- otherwise, we move on to the next item and reset the position&lt;br /&gt;
	else&lt;br /&gt;
		-- get the total number of items in the 'newsItems' table&lt;br /&gt;
		local totalItems = #newsItems&lt;br /&gt;
		&lt;br /&gt;
		-- if the next item on our list does not exist in our table&lt;br /&gt;
		if (currentItem + 1) &amp;gt; totalItems then&lt;br /&gt;
			-- loop back to the first item in the list&lt;br /&gt;
			updateNewsItem(1)&lt;br /&gt;
		else&lt;br /&gt;
			-- otherwise move onto the next item in the list&lt;br /&gt;
			updateNewsItem(currentItem + 1)&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Notice the use of the '#' symbol to get the size of the 'newsItems' table. &lt;br /&gt;
This is the Lua length operator, but it only works on tables that have numerical indexes (like an array or a list).&lt;br /&gt;
It also works on strings, eg: #&amp;quot;hello&amp;quot; would return 5.&lt;br /&gt;
&lt;br /&gt;
That completes this section of the tutorial.&lt;br /&gt;
For ideas on how to further improve and advance this code, continue reading the next section.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Improving the code==&lt;br /&gt;
This section will detail several ways to improve upon the code you now have.&lt;br /&gt;
&lt;br /&gt;
===GUI Customisation===&lt;br /&gt;
To give your GUI a more unique feel, you have the ability to customise some aspects of your GUI elements.&lt;br /&gt;
&lt;br /&gt;
For ideas on what is possible, browse the [[Client_Scripting_Functions#GUI_functions|MTA GUI functions]].&lt;br /&gt;
&lt;br /&gt;
For the purposes of this tutorial, we will be using Font, Colour and Alpha.&lt;br /&gt;
&lt;br /&gt;
To start, we will change the alpha of the background gridlist GUI element we are using.&lt;br /&gt;
To set the alpha, use [[guiSetAlpha]] and pass a value between 1 and 0; 1 being fully opaque and 0 being fully transparent.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
guiSetAlpha(newsGridlist,0.8)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Place this line of code in your 'createNewsFeed' function, after your gridlist has been created.&lt;br /&gt;
&lt;br /&gt;
I find an alpha level of 0.8 looks best, however this is personal preference and you can experiment to suit your needs.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Next, we will look at the font of the label text.&lt;br /&gt;
To set the font, use [[guiSetFont]] and pass the string name of the font you want to use (available to see on the [[GUI Fonts]] page).&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
guiSetFont(newsLabel,&amp;quot;default-bold-small&amp;quot;)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Place this line of code in your 'createNewsFeed' function, after your label has been created.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Finally, we will look at setting the colour of the label text.&lt;br /&gt;
To set the colour, use [[guiLabelSetColor]] and pass the individual red,green and blue values.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
guiLabelSetColor(newsLabel,255,70,0)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Place this line of code in your 'createNewsFeed' function, after your label has been created.&lt;br /&gt;
&lt;br /&gt;
This will give your news items an orange-red colour.&lt;br /&gt;
&lt;br /&gt;
===Multiple News Items===&lt;br /&gt;
In its current form, this code is only capable of showing one news item at a time.&lt;br /&gt;
However, with a few modifications we can show multiple news items at once, one after another.&lt;br /&gt;
&lt;br /&gt;
To begin with, we need to make sure we have a 'newItems' table defined at the very start of our script,&lt;br /&gt;
as well as a 'distance' variable that will control the pixel distance between each news item:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
local newsItems = {}&lt;br /&gt;
local distance = 30&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
So put these lines at the top of the file.&lt;br /&gt;
&lt;br /&gt;
Next, we will not know how many items we have (and consequently, how many labels we need) until we have loaded the file.&lt;br /&gt;
With that in mind, we will move around some of the code in our 'createNewsFeed' function to support this:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
function createNewsFeed()&lt;br /&gt;
	-- get the screen width and height&lt;br /&gt;
	local sWidth, sHeight = guiGetScreenSize()&lt;br /&gt;
 &lt;br /&gt;
	-- create the gridlist, using some maths to find the bottom-centre of the screen&lt;br /&gt;
	local Width,Height = 800,45&lt;br /&gt;
	local X = (sWidth/2) - (Width/2)&lt;br /&gt;
	local Y = sHeight - (Height/2)&lt;br /&gt;
	&lt;br /&gt;
	-- the gridlist will act as the background to our news reel&lt;br /&gt;
	newsGridlist = guiCreateGridList(X,Y,Width,Height,false)&lt;br /&gt;
	&lt;br /&gt;
	guiSetAlpha(newsGridlist,0.8)&lt;br /&gt;
	&lt;br /&gt;
	-- call our function to read the news out of the xml file, before we create the labels&lt;br /&gt;
	loadNews()&lt;br /&gt;
		&lt;br /&gt;
	-- define a table to hold our labels&lt;br /&gt;
	newsLabel = {}&lt;br /&gt;
	&lt;br /&gt;
	-- now we can loop all our news items, and create a label for each one&lt;br /&gt;
	for index,item in ipairs(newsItems) do&lt;br /&gt;
	&lt;br /&gt;
		-- because we now have one label for every item, we can just set the text here and it wont need to be changed again.&lt;br /&gt;
		newsLabel[index] = guiCreateLabel(0,0,Width,Height/2,item,false,newsGridlist)&lt;br /&gt;
		&lt;br /&gt;
		guiSetFont(newsLabel[index],&amp;quot;default-bold-small&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
		guiLabelSetColor(newsLabel[index],255,70,0)		&lt;br /&gt;
&lt;br /&gt;
		-- modify the width of the label to fit the text&lt;br /&gt;
		local extent = guiLabelGetTextExtent(newsLabel[index])		&lt;br /&gt;
		guiSetSize(newsLabel[index],extent,Height/2,false)&lt;br /&gt;
		&lt;br /&gt;
		&lt;br /&gt;
		-- get the size of the gridlist&lt;br /&gt;
		local x,y = guiGetSize(newsGridlist,false)&lt;br /&gt;
		&lt;br /&gt;
		-- loop from 1 until index-1 in steps of 1&lt;br /&gt;
		-- this allows us to loop every label before the label we are currently on&lt;br /&gt;
		for i=1, index-1, 1 do&lt;br /&gt;
			-- tally up the sizes of all labels before our current one and store them in x&lt;br /&gt;
			local width = guiGetSize(newsLabel[i],false)&lt;br /&gt;
			x = x + width&lt;br /&gt;
		end&lt;br /&gt;
		&lt;br /&gt;
		-- put a 'distance' pixel gap between each news item&lt;br /&gt;
		x = x + (distance*(index-1))&lt;br /&gt;
		&lt;br /&gt;
		-- set the positon to the far right side of the gridlist, ready to scroll on to the left&lt;br /&gt;
		guiSetPosition(newsLabel[index],x,0,false)	&lt;br /&gt;
	end	&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Now we need to update our 'updateNewsItem' function to account for having multiple labels:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
function updateNewsItem(newIndex)&lt;br /&gt;
	-- find the index of the news item directly infront (in the looping order) of the newIndex item&lt;br /&gt;
	local index = newIndex - 1&lt;br /&gt;
	if index == 0 then index = #newsItems end&lt;br /&gt;
	&lt;br /&gt;
	-- find the position of the right-edge of the label directly infront of the newIndex label&lt;br /&gt;
	local x = guiGetPosition(newsLabel[index],false) &lt;br /&gt;
	local width = guiGetSize(newsLabel[index],false)&lt;br /&gt;
	x = x + width&lt;br /&gt;
&lt;br /&gt;
	-- add a 'distance' pixel gap in&lt;br /&gt;
	x = x + distance&lt;br /&gt;
&lt;br /&gt;
	-- check the new position isnt actually on the gridlist (ie: so it wont suddenly appear in the centre of the list)&lt;br /&gt;
	local gridlistWidth = guiGetSize(newsGridlist,false)&lt;br /&gt;
	&lt;br /&gt;
	if x &amp;lt; gridlistWidth then&lt;br /&gt;
		-- if it is, simple move it back to the edge&lt;br /&gt;
		x = gridlistWidth&lt;br /&gt;
	end&lt;br /&gt;
	&lt;br /&gt;
	-- set the new position&lt;br /&gt;
	guiSetPosition(newsLabel[newIndex],x,0,false)&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Finally, we need to make some small adjustments to our 'scrollNews' function:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
function scrollNews()&lt;br /&gt;
	if newsItems then&lt;br /&gt;
		-- loop every news item&lt;br /&gt;
		for index,item in ipairs(newsItems) do&lt;br /&gt;
			local x,y = guiGetPosition(newsLabel[index],false)&lt;br /&gt;
			&lt;br /&gt;
			local labelWidth, labelHeight = guiGetSize(newsLabel[index],false)&lt;br /&gt;
			&lt;br /&gt;
			-- if the far right position of the label (x + labelWidth) is greater than or equal to 0 (ie: still showing on the gridlist)&lt;br /&gt;
			if ((x-1) + labelWidth) &amp;gt;= 0 then&lt;br /&gt;
				-- compensate for a small off-by-one bug in MTA&lt;br /&gt;
				if x &amp;lt;= 0 then x = x - 1 end&lt;br /&gt;
			&lt;br /&gt;
				-- update the position as normal&lt;br /&gt;
				guiSetPosition(newsLabel[index],x-1,y,false)&lt;br /&gt;
				&lt;br /&gt;
			-- otherwise, we move on to the next item and reset the position&lt;br /&gt;
			else&lt;br /&gt;
				updateNewsItem(index)&lt;br /&gt;
			end&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
You should now have multiple news items scrolling along your news feed simultaneously.&lt;br /&gt;
&lt;br /&gt;
===Globally controlled scroll speed===&lt;br /&gt;
As with the 'distance' variable above, we can set a global variable for controlling the scroll speed of the news items as well.&lt;br /&gt;
Note that the speed will still be dependant on the players FPS (ie: lower FPS means slightly slower scrolling).&lt;br /&gt;
&lt;br /&gt;
To do this, we simply need to create the variable at the start of our code:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
local scrollSpeed = 1&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Put this line at the top of your file.&lt;br /&gt;
&lt;br /&gt;
Then, we just replace the instance of &amp;quot;x-1&amp;quot; in our 'scrollNews' function with &amp;quot;x-scrollSpeed&amp;quot;:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
function scrollNews()&lt;br /&gt;
		...&lt;br /&gt;
				-- update the position as normal&lt;br /&gt;
				guiSetPosition(newsLabel[index],x-scrollSpeed,y,false)&lt;br /&gt;
		...&lt;br /&gt;
	end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
That concludes this section of the tutorial.&lt;/div&gt;</summary>
		<author><name>R3mp</name></author>
	</entry>
	<entry>
		<id>https://wiki.multitheftauto.com/index.php?title=Scripting_the_GUI_-_Tutorial_1&amp;diff=22188</id>
		<title>Scripting the GUI - Tutorial 1</title>
		<link rel="alternate" type="text/html" href="https://wiki.multitheftauto.com/index.php?title=Scripting_the_GUI_-_Tutorial_1&amp;diff=22188"/>
		<updated>2010-01-05T21:52:53Z</updated>

		<summary type="html">&lt;p&gt;R3mp: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;'''Scripting the Gui - Tutorial 1 (Gridlists)'''&lt;br /&gt;
&lt;br /&gt;
In this tutorial we will explore the use of gridlists in creating a vehicle selection screen, with optional clientside vehicle xml data reading.&lt;br /&gt;
&lt;br /&gt;
'''Note that this tutorial assumes you are familiar with all the content covered in the [[Introduction to Scripting GUI|Previous tutorial]].'''&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Setting up the Vehicle Selection==&lt;br /&gt;
&lt;br /&gt;
===Creating the GUI===&lt;br /&gt;
To begin, open up a clientside lua file (if you have been following the [[Scripting Introduction]], this is gui.lua) to work with.&lt;br /&gt;
&lt;br /&gt;
In this file, we will start writing our function for creating the GUI.&lt;br /&gt;
As covered in the [[Introduction to Scripting GUI|Previous tutorial]], there are 2 value type options available when creating gui: '''relative''' and '''absolute'''.&lt;br /&gt;
&lt;br /&gt;
For the purposes of this tutorial, we will be using '''absolute''' values.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
This will create a simple GUI with a window, gridlist and button:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
function createVehicleSelection()&lt;br /&gt;
	-- get the screen width and height&lt;br /&gt;
	local sWidth, sHeight = guiGetScreenSize()&lt;br /&gt;
	&lt;br /&gt;
	-- use some simple maths to position the window in the centre of the screen&lt;br /&gt;
	local Width,Height = 376,259&lt;br /&gt;
	local X = (sWidth/2) - (Width/2)&lt;br /&gt;
	local Y = (sHeight/2) - (Height/2)&lt;br /&gt;
	windowVehicleSelection = guiCreateWindow(X,Y,Width,Height,&amp;quot;Vehicle Selection Window&amp;quot;,false)&lt;br /&gt;
	&lt;br /&gt;
	gridlistVehicleSelection = guiCreateGridList(10,26,357,192,false,windowVehicleSelection)&lt;br /&gt;
	-- add a &amp;quot;Vehicle&amp;quot; and a &amp;quot;Type&amp;quot; collumn to the gridlist&lt;br /&gt;
	guiGridListAddColumn(gridlistVehicleSelection,&amp;quot;Vehicle&amp;quot;,0.2)&lt;br /&gt;
	guiGridListAddColumn(gridlistVehicleSelection,&amp;quot;Type&amp;quot;,0.2)&lt;br /&gt;
	&lt;br /&gt;
	-- set the default width of the columns to roughly half the size of the gridlist (each)&lt;br /&gt;
	guiGridListSetColumnWidth(gridlistVehicleSelection,1,0.4,true)&lt;br /&gt;
	guiGridListSetColumnWidth(gridlistVehicleSelection,2,0.5,true)&lt;br /&gt;
	&lt;br /&gt;
	buttonCreate = guiCreateButton(121,227,120,20,&amp;quot;Create&amp;quot;,false,windowVehicleSelection)&lt;br /&gt;
	&lt;br /&gt;
	-- add the event handler for when the button is clicked&lt;br /&gt;
	addEventHandler(&amp;quot;onClientGUIClick&amp;quot;,buttonCreate,createVehicleHandler,false)&lt;br /&gt;
	&lt;br /&gt;
	-- hide the GUI&lt;br /&gt;
	guiSetVisible(windowVehicleSelection,false)&lt;br /&gt;
	&lt;br /&gt;
	-- this will add all the vehicle options onto the gridlist, it is explained later in this tutorial&lt;br /&gt;
	populateGridlist()&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
We now also need to call this function somewhere, otherwise the GUI will never be created.&lt;br /&gt;
As in previous tutorials, to do this we can use [[onClientResourceStart]].&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
-- when the resource is started, create the GUI and hide it&lt;br /&gt;
addEventHandler(&amp;quot;onClientResourceStart&amp;quot;,getResourceRootElement(getThisResource()),&lt;br /&gt;
	function()&lt;br /&gt;
		createVehicleSelection()&lt;br /&gt;
	end&lt;br /&gt;
)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Showing the GUI===&lt;br /&gt;
Unlike in previous tutorials, we want players to be able to open this window whenever they chose, not when the resource starts. &lt;br /&gt;
So, we can add a [[addCommandHandler|Command]] to do this.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
-- create the function that will show the window&lt;br /&gt;
function showVehicleSelection()&lt;br /&gt;
	-- if the window isnt visible, show it&lt;br /&gt;
	if not guiGetVisible(windowVehicleSelection) then&lt;br /&gt;
		guiSetVisible(windowVehicleSelection,true)&lt;br /&gt;
		&lt;br /&gt;
		showCursor(true,true)&lt;br /&gt;
	end&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
-- add the command /vehicleselection and set it to call the showVehicleSelection function&lt;br /&gt;
addCommandHandler(&amp;quot;vehicleselection&amp;quot;,showVehicleSelection)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Populating the Gridlist from a table===&lt;br /&gt;
Now that we have our basic GUI created, we need to fill the gridlist with all of our vehicles.&lt;br /&gt;
&lt;br /&gt;
To begin with, we will do this using a simple clientside table. &lt;br /&gt;
Later in the tutorial, we will explore expanding this method to use .xml files for storing information.&lt;br /&gt;
To begin, we must create a small table containing a selection of vehicles that we can spawn.&lt;br /&gt;
&lt;br /&gt;
The table contains vehicles in the format [&amp;quot;description&amp;quot;] = vehicle_id :&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
-- create the table and fill it with a selection of vehicle ids and names&lt;br /&gt;
local vehicleSelectionTable = {&lt;br /&gt;
	[&amp;quot;Sparrow&amp;quot;] = 469,&lt;br /&gt;
	[&amp;quot;Stuntplane&amp;quot;] = 513,&lt;br /&gt;
	[&amp;quot;BF-400&amp;quot;] = 581,&lt;br /&gt;
	[&amp;quot;Freeway&amp;quot;] = 463,&lt;br /&gt;
	[&amp;quot;Speeder&amp;quot;] = 452,&lt;br /&gt;
	[&amp;quot;Jester&amp;quot;] = 559,&lt;br /&gt;
	[&amp;quot;Sabre&amp;quot;] = 475,&lt;br /&gt;
	[&amp;quot;Police Ranger&amp;quot;] = 599,&lt;br /&gt;
	[&amp;quot;Utility Van&amp;quot;] = 552,&lt;br /&gt;
	[&amp;quot;Tug&amp;quot;] = 583&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Place this code at the very top of your file (it does not need to be inside a function).&lt;br /&gt;
&lt;br /&gt;
Next, we can write our &amp;quot;populateGridlist&amp;quot; function which will fill the Gridlist with all the vehicles in the table.&lt;br /&gt;
To do this we simply need to loop through all the values in the table, adding each one to the gridlist as we go.&lt;br /&gt;
We will also set hidden data using [[guiGridListSetItemData]] to store the vehicle id:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
function populateGridlist()&lt;br /&gt;
	-- loop through the table&lt;br /&gt;
	for name,vehicle in pairs(vehicleSelectionTable) do&lt;br /&gt;
		-- add a new row to the gridlist&lt;br /&gt;
		local row = guiGridListAddRow(gridlistVehicleSelection)&lt;br /&gt;
&lt;br /&gt;
		-- set the text in the first column to the vehicle name&lt;br /&gt;
		guiGridListSetItemText(gridlistVehicleSelection,row,1,name,false,false)&lt;br /&gt;
		-- set the text in the second column to the vehicle type&lt;br /&gt;
		guiGridListSetItemText(gridlistVehicleSelection,row,2,getVehicleType(vehicle),false,false)&lt;br /&gt;
		&lt;br /&gt;
		-- set the data for gridlist slot as the vehicle id&lt;br /&gt;
		guiGridListSetItemData(gridlistVehicleSelection,row,1,tostring(vehicle))&lt;br /&gt;
	end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt; &lt;br /&gt;
&lt;br /&gt;
===Managing the click===&lt;br /&gt;
Now that we have our GUI completed, we need to be able to catch any clicks made on the &amp;quot;create&amp;quot; button.&lt;br /&gt;
We have attached the [[onClientGUIClick]] event to buttonCreate already, so now we need to write the function that it calls.&lt;br /&gt;
In this function we do some basic error checking, such as making sure a vehicle has been selected in the list. &lt;br /&gt;
We can then use some maths to find a position infront of the player and send the server this information to spawn the vehicle (using [[triggerServerEvent]]) &lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
function createVehicleHandler(button,state)&lt;br /&gt;
	if button == &amp;quot;left&amp;quot; and state == &amp;quot;up&amp;quot; then&lt;br /&gt;
		-- get the selected item in the gridlist&lt;br /&gt;
		local row,col = guiGridListGetSelectedItem(gridlistVehicleSelection)&lt;br /&gt;
		&lt;br /&gt;
		-- if something is selected&lt;br /&gt;
		if row and col and row ~= -1 and col ~= -1 then&lt;br /&gt;
			-- get the vehicle id data from the gridlist that is selected&lt;br /&gt;
			local selected = guiGridListGetItemData(gridlistVehicleSelection,row,col)&lt;br /&gt;
			&lt;br /&gt;
			-- make sure the vehicle id is a number not a string&lt;br /&gt;
			selected = tonumber(selected)&lt;br /&gt;
						&lt;br /&gt;
			-- get the players position and rotation&lt;br /&gt;
			local rotz = getPedRotation(getLocalPlayer())&lt;br /&gt;
			local x,y,z = getElementPosition(getLocalPlayer())&lt;br /&gt;
			-- find the position directly infront of the player&lt;br /&gt;
			x = x + ( math.cos ( math.rad ( rotz+90 ) ) * 3)&lt;br /&gt;
			y = y + ( math.sin ( math.rad ( rotz+90 ) ) * 3)&lt;br /&gt;
			&lt;br /&gt;
			if selected and x and y and z then&lt;br /&gt;
				-- trigger the server&lt;br /&gt;
				triggerServerEvent(&amp;quot;createVehicleFromGUI&amp;quot;,getRootElement(),selected,x,y,z)&lt;br /&gt;
				&lt;br /&gt;
				-- hide the gui and the cursor&lt;br /&gt;
				guiSetVisible(windowVehicleSelection,false)&lt;br /&gt;
				showCursor(false,false)&lt;br /&gt;
			else&lt;br /&gt;
				outputChatBox(&amp;quot;Invalid arguments.&amp;quot;)&lt;br /&gt;
			end&lt;br /&gt;
		else&lt;br /&gt;
			-- otherwise, output a message to the player&lt;br /&gt;
			outputChatBox(&amp;quot;Please select a vehicle.&amp;quot;)&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Creating the Vehicle===&lt;br /&gt;
At this point we now have all the code needed on the client side, so open up a serverside .lua file to work with. &lt;br /&gt;
&lt;br /&gt;
On the server side, we will first of all need to define the custom event that we triggered before from the client. This can be done using [[addEvent]] and [[addEventHandler]].&lt;br /&gt;
Finally we will need a small function for creating the vehicle:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
function createMyVehicle(vehicleid,x,y,z)&lt;br /&gt;
	-- check all the arguments exist&lt;br /&gt;
	if vehicleid and x and y and z then&lt;br /&gt;
		createVehicle(vehicleid,x,y,z)&lt;br /&gt;
	end&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
addEvent(&amp;quot;createVehicleFromGUI&amp;quot;,true)&lt;br /&gt;
addEventHandler(&amp;quot;createVehicleFromGUI&amp;quot;,root,createMyVehicle)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Note the use of the &amp;quot;root&amp;quot; variable. This is an MTA variable containing the root element; every resource has one.&lt;br /&gt;
&lt;br /&gt;
This completes the first section of the tutorial. You should now have a basic, working vehicle spawn script.&lt;br /&gt;
&lt;br /&gt;
In the second section, we will cover collapsible gridlist data and clientside xml file reading.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Expanding the code==&lt;br /&gt;
This section will detail several ways to improve upon the code you now have.&lt;br /&gt;
&lt;br /&gt;
===Importing Data===&lt;br /&gt;
One big improvement over the previously mentioned method is to use external files to store the vehicle information, allowing us to much more quickly and easily manage large amounts of data.&lt;br /&gt;
For this tutorial, we will use a clientside xml file to hold the information.&lt;br /&gt;
&lt;br /&gt;
First of all you will need to create your xml file, so navigate to your resources directory and create a new file named vehicles.xml:&lt;br /&gt;
&lt;br /&gt;
''For the purpose of this example, we will include only a small fraction of the total vehicles, however the file can easily be expanded to include them all.''&lt;br /&gt;
&lt;br /&gt;
If you are unsure of xml data structures, you can browse the [http://wiki.multitheftauto.com/wiki/Server_Scripting_Functions#XML_functions| MTA xml functions] for help.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;root&amp;gt;&lt;br /&gt;
	&amp;lt;group type=&amp;quot;Bikes&amp;quot;&amp;gt;&lt;br /&gt;
		&amp;lt;vehicle id=&amp;quot;581&amp;quot; name=&amp;quot;BF-400&amp;quot;/&amp;gt;&lt;br /&gt;
		&amp;lt;vehicle id=&amp;quot;463&amp;quot; name=&amp;quot;Freeway&amp;quot;/&amp;gt;&lt;br /&gt;
		&amp;lt;vehicle id=&amp;quot;481&amp;quot; name=&amp;quot;BMX&amp;quot;/&amp;gt;&lt;br /&gt;
	&amp;lt;/group&amp;gt;&lt;br /&gt;
	&amp;lt;group type=&amp;quot;Boats&amp;quot;&amp;gt;&lt;br /&gt;
		&amp;lt;vehicle id=&amp;quot;472&amp;quot; name=&amp;quot;Coastguard&amp;quot;/&amp;gt;&lt;br /&gt;
		&amp;lt;vehicle id=&amp;quot;452&amp;quot; name=&amp;quot;Speeder&amp;quot;/&amp;gt;&lt;br /&gt;
	&amp;lt;/group&amp;gt;&lt;br /&gt;
	&amp;lt;group type=&amp;quot;Helicopters&amp;quot;&amp;gt;&lt;br /&gt;
		&amp;lt;vehicle id=&amp;quot;487&amp;quot; name=&amp;quot;Maverick&amp;quot;/&amp;gt;&lt;br /&gt;
		&amp;lt;vehicle id=&amp;quot;469&amp;quot; name=&amp;quot;Sparrow&amp;quot;/&amp;gt;	&lt;br /&gt;
	&amp;lt;/group&amp;gt;&lt;br /&gt;
	&amp;lt;group type=&amp;quot;Planes&amp;quot;&amp;gt;&lt;br /&gt;
		&amp;lt;vehicle id=&amp;quot;593&amp;quot; name=&amp;quot;Dodo&amp;quot;/&amp;gt;&lt;br /&gt;
		&amp;lt;vehicle id=&amp;quot;513&amp;quot; name=&amp;quot;Stuntplane&amp;quot;/&amp;gt;	&lt;br /&gt;
	&amp;lt;/group&amp;gt;&lt;br /&gt;
	&amp;lt;group type=&amp;quot;Sports Cars&amp;quot;&amp;gt;&lt;br /&gt;
		&amp;lt;vehicle id=&amp;quot;565&amp;quot; name=&amp;quot;Flash&amp;quot;/&amp;gt;&lt;br /&gt;
		&amp;lt;vehicle id=&amp;quot;559&amp;quot; name=&amp;quot;Jester&amp;quot;/&amp;gt;&lt;br /&gt;
		&amp;lt;vehicle id=&amp;quot;477&amp;quot; name=&amp;quot;ZR-350&amp;quot;/&amp;gt;	&lt;br /&gt;
	&amp;lt;/group&amp;gt;&lt;br /&gt;
	&amp;lt;group type=&amp;quot;2-Door&amp;quot;&amp;gt;&lt;br /&gt;
		&amp;lt;vehicle id=&amp;quot;474&amp;quot; name=&amp;quot;Hermes&amp;quot;/&amp;gt;&lt;br /&gt;
		&amp;lt;vehicle id=&amp;quot;475&amp;quot; name=&amp;quot;Sabre&amp;quot;/&amp;gt;&lt;br /&gt;
	&amp;lt;/group&amp;gt;&lt;br /&gt;
	&amp;lt;group type=&amp;quot;Emergency&amp;quot;&amp;gt;&lt;br /&gt;
		&amp;lt;vehicle id=&amp;quot;416&amp;quot; name=&amp;quot;Ambulance&amp;quot;/&amp;gt;&lt;br /&gt;
		&amp;lt;vehicle id=&amp;quot;599&amp;quot; name=&amp;quot;Police ranger&amp;quot;/&amp;gt;&lt;br /&gt;
	&amp;lt;/group&amp;gt;&lt;br /&gt;
	&amp;lt;group type=&amp;quot;Industrial&amp;quot;&amp;gt;&lt;br /&gt;
		&amp;lt;vehicle id=&amp;quot;573&amp;quot; name=&amp;quot;Dune&amp;quot;/&amp;gt;&lt;br /&gt;
		&amp;lt;vehicle id=&amp;quot;552&amp;quot; name=&amp;quot;Utility van&amp;quot;/&amp;gt;	&lt;br /&gt;
	&amp;lt;/group&amp;gt;&lt;br /&gt;
	&amp;lt;group type=&amp;quot;Misc&amp;quot;&amp;gt;&lt;br /&gt;
		&amp;lt;vehicle id=&amp;quot;457&amp;quot; name=&amp;quot;Caddy&amp;quot;/&amp;gt;&lt;br /&gt;
		&amp;lt;vehicle id=&amp;quot;583&amp;quot; name=&amp;quot;Tug&amp;quot;/&amp;gt;&lt;br /&gt;
	&amp;lt;/group&amp;gt;&lt;br /&gt;
&amp;lt;/root&amp;gt;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Once you have created your file, do not forget to add it to the meta.xml of your resource with the appropriate client tag.&lt;br /&gt;
&lt;br /&gt;
Note the group &amp;quot;type&amp;quot; tag. This is an arbitrary description of the vehicles contained within the group and can be renamed or added as any text.&lt;br /&gt;
Similarly, the vehicle &amp;quot;name&amp;quot; tag is also just a textual description of the vehicle and does not need to be the exact vehicle name.&lt;br /&gt;
&lt;br /&gt;
Now that we have the data, we can import it into the game and display it in the GUI.&lt;br /&gt;
'''If you are following on from the first section of this tutorial, this new code will replace what is inside your existing 'populateGridlist' function.'''&lt;br /&gt;
First, we need to load the file:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
function populateGridlist()&lt;br /&gt;
	-- load the file and save the root node value it returns&lt;br /&gt;
	local rootnode = xmlLoadFile(&amp;quot;vehicles.xml&amp;quot;)&lt;br /&gt;
	&lt;br /&gt;
	-- check that the file exists and has been correctly loaded&lt;br /&gt;
	if rootnode then		&lt;br /&gt;
		-- unload the xml file&lt;br /&gt;
		xmlUnloadFile(rootnode)&lt;br /&gt;
	end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Always make sure you unload any files once you are finished using them.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
We can now start collecting the data from the file and entering it into our gridlist.&lt;br /&gt;
We can do this by looping through the xml data (in a similar manner to looping through the vehicle table earlier in this tutorial) and adding each entry into the list.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
function populateGridlist()&lt;br /&gt;
	local rootnode = xmlLoadFile(&amp;quot;vehicles.xml&amp;quot;)&lt;br /&gt;
	&lt;br /&gt;
	if rootnode then		&lt;br /&gt;
		-- first, we find every &amp;quot;group&amp;quot; node (they are direct children of the root)&lt;br /&gt;
		for _,group in ipairs(xmlNodeGetChildren(rootnode)) do&lt;br /&gt;
			-- add a new row to the gridlist&lt;br /&gt;
			local row = guiGridListAddRow(gridlistVehicleSelection)&lt;br /&gt;
&lt;br /&gt;
			-- get the group name&lt;br /&gt;
			local name = xmlNodeGetAttribute(group,&amp;quot;type&amp;quot;)&lt;br /&gt;
			&lt;br /&gt;
			-- set the text in the first column to the group type and indicate it is a section ('true')&lt;br /&gt;
			-- (sections on gridlists show up in bold and cannot be clicked)&lt;br /&gt;
			guiGridListSetItemText(gridlistVehicleSelection,row,1,name,true,false)			&lt;br /&gt;
		&lt;br /&gt;
			-- then, for every group that we find, loop all of its children (the vehicle nodes)&lt;br /&gt;
			-- and add them into the gridlist&lt;br /&gt;
			for _,vehicle in ipairs(xmlNodeGetChildren(group)) do&lt;br /&gt;
				-- add a new row to the gridlist&lt;br /&gt;
				row = guiGridListAddRow(gridlistVehicleSelection)&lt;br /&gt;
&lt;br /&gt;
				-- get the vehicle name and id&lt;br /&gt;
				name = xmlNodeGetAttribute(vehicle,&amp;quot;name&amp;quot;)&lt;br /&gt;
				local id = xmlNodeGetAttribute(vehicle,&amp;quot;id&amp;quot;)&lt;br /&gt;
				&lt;br /&gt;
				-- set the text in the first column to the vehicle name&lt;br /&gt;
				guiGridListSetItemText(gridlistVehicleSelection,row,1,name,false,false)&lt;br /&gt;
				-- set the text in the second column to the vehicle type&lt;br /&gt;
				guiGridListSetItemText(gridlistVehicleSelection,row,2,getVehicleType(tonumber(id)),false,false)		&lt;br /&gt;
				&lt;br /&gt;
				-- finally, set the vehicle id as data so we can access it later&lt;br /&gt;
				guiGridListSetItemData(gridlistVehicleSelection,row,1,tostring(id))&lt;br /&gt;
			end&lt;br /&gt;
		end	&lt;br /&gt;
	&lt;br /&gt;
		-- unload the xml file now that we are finished&lt;br /&gt;
		xmlUnloadFile(rootnode)&lt;br /&gt;
	end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Note the use of for loops in the code with [[xmlNodeGetChildren]]. This saves us a lot of time and effort as we do not have to manually code each group and vehicle into the list.&lt;br /&gt;
&lt;br /&gt;
You should now have a fully working vehicle selection menu, reading all of its data from a clientside xml file.&lt;br /&gt;
Next, we will examine how to generate the appearance of collapsing and expanding sections in a gridlist.&lt;br /&gt;
&lt;br /&gt;
===Collapsing/Expanding the Gridlist===&lt;br /&gt;
Allowing sections of the gridlist to be collapsed or expanded gives much more control over the visible content to the user.&lt;br /&gt;
This frees up space on the screen and makes the whole menu much more comfortable to use.&lt;br /&gt;
&lt;br /&gt;
===Loading the data===&lt;br /&gt;
To be able to achieve this effect (as it is not a natural feature of gridlists) we will need to load the vehicle information into a table (from the xml file), rather than directly including it all in the gridlist.&lt;br /&gt;
'''If you are following on from a previous section of this tutorial, this new code will replace what is inside your existing 'populateGridlist' function.'''&lt;br /&gt;
&lt;br /&gt;
This works in much the same way the previous xml loading example does, only this time instead of saving the data into the gridlist, we save it into a table entry instead.&lt;br /&gt;
We also set the custom data &amp;quot;header&amp;quot; on the gridlist slots to denote which gridlist entries are our &amp;quot;group&amp;quot; entries and which are vehicles.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
function populateGridlist()&lt;br /&gt;
	local rootnode = xmlLoadFile(&amp;quot;vehicles.xml&amp;quot;)&lt;br /&gt;
	&lt;br /&gt;
	-- create a blank global table to store our imported data&lt;br /&gt;
	vehicleTable = {}&lt;br /&gt;
	&lt;br /&gt;
	if rootnode then		&lt;br /&gt;
		for _,group in ipairs(xmlNodeGetChildren(rootnode)) do&lt;br /&gt;
			-- create an entry in the gridlist for every vehicle &amp;quot;group&amp;quot;&lt;br /&gt;
			local row = guiGridListAddRow(gridlistVehicleSelection)&lt;br /&gt;
&lt;br /&gt;
			local name = xmlNodeGetAttribute(group,&amp;quot;type&amp;quot;)&lt;br /&gt;
			&lt;br /&gt;
			guiGridListSetItemText(gridlistVehicleSelection,row,1,name,false,false)	&lt;br /&gt;
&lt;br /&gt;
			-- add an entry containing the group name into the table&lt;br /&gt;
			vehicleTable[name] = {}&lt;br /&gt;
			&lt;br /&gt;
			-- we will use the custom data &amp;quot;header&amp;quot; to indicate that this entry can be expanded/collapsed&lt;br /&gt;
			guiGridListSetItemData(gridlistVehicleSelection,row,1,&amp;quot;header&amp;quot;)	&lt;br /&gt;
		&lt;br /&gt;
			-- then, for every group that we find, loop all of its children (the vehicle nodes) and store them in a table&lt;br /&gt;
			for _,vehicle in ipairs(xmlNodeGetChildren(group)) do&lt;br /&gt;
				local vname = xmlNodeGetAttribute(vehicle,&amp;quot;name&amp;quot;)&lt;br /&gt;
				local id = xmlNodeGetAttribute(vehicle,&amp;quot;id&amp;quot;)			&lt;br /&gt;
			&lt;br /&gt;
				-- insert both the vehicle id and the vehicle description into the table&lt;br /&gt;
				table.insert(vehicleTable[name],{id,vname})&lt;br /&gt;
			end&lt;br /&gt;
		end	&lt;br /&gt;
	&lt;br /&gt;
		-- set element data on the gridlist so we know which group is currently showing&lt;br /&gt;
		setElementData(gridlistVehicleSelection,&amp;quot;expanded&amp;quot;,&amp;quot;none&amp;quot;)&lt;br /&gt;
	&lt;br /&gt;
		-- unload the xml file now that we are finished&lt;br /&gt;
		xmlUnloadFile(rootnode)&lt;br /&gt;
	end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Now that we have all the data stored, we can quickly manipulate it when neccessary.&lt;br /&gt;
&lt;br /&gt;
===Managing the double click===&lt;br /&gt;
To enable the player to simply double click on a group name to expand/collapse it we need to use the [[onClientGUIDoubleClick]] event.&lt;br /&gt;
If we attach it to the gridlist, we can then catch any double clicks on the group names in it:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
-- attach the onClientGUIDoubleClick event to the gridlist and set it to call processDoubleClick&lt;br /&gt;
addEventHandler(&amp;quot;onClientGUIDoubleClick&amp;quot;,gridlistVehicleSelection,processDoubleClick,false)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Add this line of code in your createVehicleSelection, after the gridlist has been created.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
As the gridlist items are not separate GUI elements, we must capture all clicks from anywhere on the gridlist then process them to filter out the ones we do not want.&lt;br /&gt;
This can be done by checking if an item is selected, then checking if the item is one of our &amp;quot;group&amp;quot; values (using our previously mentioned &amp;quot;header&amp;quot; data):&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
function processDoubleClick(button,state)&lt;br /&gt;
	if button == &amp;quot;left&amp;quot; and state == &amp;quot;up&amp;quot; then&lt;br /&gt;
		local row,col = guiGridListGetSelectedItem(gridlistVehicleSelection)&lt;br /&gt;
		&lt;br /&gt;
		-- if something in the gridlist has been selected&lt;br /&gt;
		if row and col and row ~= -1 and col ~= -1 then		&lt;br /&gt;
			-- if it is a header&lt;br /&gt;
			if guiGridListGetItemData(gridlistVehicleSelection,row,col) == &amp;quot;header&amp;quot; then&lt;br /&gt;
				local selected = guiGridListGetItemText(gridlistVehicleSelection,row,col)&lt;br /&gt;
				&lt;br /&gt;
				-- call the function to collapse or expand the menu and pass which section it is as an argument&lt;br /&gt;
				changeGridlistState(selected)&lt;br /&gt;
			end&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Once we have narrowed down the double clicks to only those done on our group headers, we can expand/collapse them appropriately.&lt;br /&gt;
This can be done by simply setting new text values in the gridlist according to the newly expanded/collapsed group, which creates the convincing illusion of collapsable menus.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Note that much of the following code is reused from previous areas of this tutorial. While it is generally bad practice to clone sections of code in this way, for the purposes of this example it is far easier to understand.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
function changeGridlistState(group)&lt;br /&gt;
	if group then&lt;br /&gt;
		-- if the group is already expanded, we want to collapse it&lt;br /&gt;
		if getElementData(gridlistVehicleSelection,&amp;quot;expanded&amp;quot;) == group then&lt;br /&gt;
			-- first, we clear all previous data from the gridlist&lt;br /&gt;
			guiGridListClear(gridlistVehicleSelection)&lt;br /&gt;
			&lt;br /&gt;
			-- now, loop all the group entries in the vehicle table that we created earlier&lt;br /&gt;
			for group,_ in pairs(vehicleTable) do&lt;br /&gt;
				-- add each group to the list and mark them with &amp;quot;header&amp;quot;			&lt;br /&gt;
				local row = guiGridListAddRow(gridlistVehicleSelection)&lt;br /&gt;
				&lt;br /&gt;
				guiGridListSetItemText(gridlistVehicleSelection,row,1,group,false,false)	&lt;br /&gt;
				guiGridListSetItemData(gridlistVehicleSelection,row,1,&amp;quot;header&amp;quot;)	&lt;br /&gt;
			end&lt;br /&gt;
			&lt;br /&gt;
			-- update the data to indicate that no groups are currently expanded&lt;br /&gt;
			setElementData(gridlistVehicleSelection,&amp;quot;expanded&amp;quot;,&amp;quot;none&amp;quot;)&lt;br /&gt;
			&lt;br /&gt;
		-- otherwise, we want to expand it&lt;br /&gt;
		else&lt;br /&gt;
			guiGridListClear(gridlistVehicleSelection)&lt;br /&gt;
			&lt;br /&gt;
			local row = guiGridListAddRow(gridlistVehicleSelection)&lt;br /&gt;
			&lt;br /&gt;
			guiGridListSetItemText(gridlistVehicleSelection,row,1,group,false,false)	&lt;br /&gt;
			guiGridListSetItemData(gridlistVehicleSelection,row,1,&amp;quot;header&amp;quot;)				&lt;br /&gt;
			&lt;br /&gt;
			-- loop every vehicle in the specified groups table&lt;br /&gt;
			for _,vehicle in ipairs(vehicleTable[group]) do&lt;br /&gt;
				-- add them to the gridlist and set the vehicle id as data&lt;br /&gt;
				row = guiGridListAddRow(gridlistVehicleSelection)&lt;br /&gt;
			&lt;br /&gt;
				-- format a &amp;quot;-&amp;quot; into the string to make it visually easier to distinguish between groups and vehicles&lt;br /&gt;
				guiGridListSetItemText(gridlistVehicleSelection,row,1,&amp;quot;- &amp;quot;..vehicle[2],false,false)	&lt;br /&gt;
				guiGridListSetItemText(gridlistVehicleSelection,row,2,getVehicleType(tonumber(vehicle[1])),false,false)	&lt;br /&gt;
											&lt;br /&gt;
				guiGridListSetItemData(gridlistVehicleSelection,row,1,tostring(vehicle[1]))&lt;br /&gt;
			end	&lt;br /&gt;
&lt;br /&gt;
			-- update the data to indicate which group is currently expanded&lt;br /&gt;
			setElementData(gridlistVehicleSelection,&amp;quot;expanded&amp;quot;,group)			&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This comletes the second section of the tutorial.&lt;br /&gt;
&lt;br /&gt;
For further GUI tutorials, see [[Scripting the GUI - Tutorial 2|Tutorial 2 (Gates and Keypads)]]&lt;/div&gt;</summary>
		<author><name>R3mp</name></author>
	</entry>
	<entry>
		<id>https://wiki.multitheftauto.com/index.php?title=Scripting_the_GUI_-_Tutorial_3&amp;diff=22187</id>
		<title>Scripting the GUI - Tutorial 3</title>
		<link rel="alternate" type="text/html" href="https://wiki.multitheftauto.com/index.php?title=Scripting_the_GUI_-_Tutorial_3&amp;diff=22187"/>
		<updated>2010-01-05T21:50:30Z</updated>

		<summary type="html">&lt;p&gt;R3mp: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;'''Scripting the GUI - Tutorial 3 (Scrolling News Feed)'''&lt;br /&gt;
&lt;br /&gt;
In this tutorial we will explore how to create a simple scrolling news feed GUI, &lt;br /&gt;
allowing you to quickly and easily show server updates and other server information to your players.&lt;br /&gt;
We will store all news items in a clientside xml file and use some simple xml reading to load them into the game.&lt;br /&gt;
&lt;br /&gt;
We will then animate the news item to scroll along the bottom of the screen, updating the news text once it has scrolled beyond the edge of the screen.&lt;br /&gt;
&lt;br /&gt;
'''Note that this tutorial assumes you are familiar with all the content covered in the [[Introduction to Scripting GUI|GUI Scripting Introduction]].'''&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Setting up the News Feed==&lt;br /&gt;
To begin, open up a clientside lua file (if you have been following the [[Introduction to Scripting GUI|GUI Scripting Introduction]], this is gui.lua) to work with.&lt;br /&gt;
&lt;br /&gt;
===Creating the GUI===&lt;br /&gt;
As with the previous tutorial, you should be suitably familiar with GUI creation already so we will not go into too much detail here. &lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
function createNewsFeed()&lt;br /&gt;
	-- get the screen width and height&lt;br /&gt;
	local sWidth, sHeight = guiGetScreenSize()&lt;br /&gt;
 &lt;br /&gt;
	-- create the gridlist, using some maths to find the bottom-centre of the screen&lt;br /&gt;
	local Width,Height = 800,45&lt;br /&gt;
	local X = (sWidth/2) - (Width/2)&lt;br /&gt;
	local Y = sHeight - (Height/2)&lt;br /&gt;
	&lt;br /&gt;
	-- the gridlist will act as the background to our news reel&lt;br /&gt;
	newsGridlist = guiCreateGridList(X,Y,Width,Height,false)&lt;br /&gt;
	&lt;br /&gt;
	-- create the label in the same place, but as a child of the gridlist&lt;br /&gt;
	-- also make it half the height of the gridlist, as half of the gridlist is off the bottom of the screen&lt;br /&gt;
	newsLabel = guiCreateLabel(X,Y,Width,Height/2,&amp;quot;Test text&amp;quot;,false,newsGridlist)&lt;br /&gt;
	&lt;br /&gt;
	-- call our function to read the news out of the xml file&lt;br /&gt;
	loadNews()&lt;br /&gt;
	&lt;br /&gt;
	-- load the first news item in the table&lt;br /&gt;
	updateNewsItem(1)&lt;br /&gt;
	&lt;br /&gt;
	-- define a global variable called 'currentItem' with the value 1&lt;br /&gt;
	currentItem = 1&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
addEventHandler(&amp;quot;onClientResourceStart&amp;quot;,resourceRoot,createNewsFeed)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Note that the label is created as a child of the gridlist. &lt;br /&gt;
Not only is this good practice in general, but it means that we can freely move parts of the label beyond the edge of the gridlist without them showing, which is critical to the visual effect of this tutorial.&lt;br /&gt;
&lt;br /&gt;
Also notice the use of the 'resourceRoot' variable. This is an MTA variable that holds the root element value of the resource you are using it in.&lt;br /&gt;
&lt;br /&gt;
The 'currentItem' variable is what we will use to keep track of which news item we are currently showing&lt;br /&gt;
&lt;br /&gt;
===Writing the News===&lt;br /&gt;
Now that we have our GUI created, we need some news to fill it with.&lt;br /&gt;
To do this, we will read our news items out of a clientside xml file.&lt;br /&gt;
&lt;br /&gt;
So, navigate to your resource directory and create a new xml file called newsfeed.xml (don't forget to add it to your meta.xml with the appropriate client tag).&lt;br /&gt;
&lt;br /&gt;
Inside this file enter the following information:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;root&amp;gt;&lt;br /&gt;
	&amp;lt;news&amp;gt;This is an example news item.&amp;lt;/news&amp;gt;&lt;br /&gt;
	&amp;lt;news&amp;gt;From the 'Scripting the GUI' tutorial.&amp;lt;/news&amp;gt;&lt;br /&gt;
	&amp;lt;news&amp;gt;Showing scrolling news text.&amp;lt;/news&amp;gt;&lt;br /&gt;
	&amp;lt;news&amp;gt;Written on a GUI news feed.&amp;lt;/news&amp;gt;&lt;br /&gt;
&amp;lt;/root&amp;gt;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
As you can see, each news item is defined as a &amp;lt;news&amp;gt; node with the value being the news text you want to display.&lt;br /&gt;
There is no limit on how many news items you can add.&lt;br /&gt;
&lt;br /&gt;
===Collecting the News===&lt;br /&gt;
Once we have written all our news items, we will need to collect them all and store them in a table on the client.&lt;br /&gt;
We will do this when the resource starts, saving us from having to repeatedly access the xml for new news items.&lt;br /&gt;
&lt;br /&gt;
First, we need to define a table to store the items in:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
local newsItems = {}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Add this line to the top of your script.&lt;br /&gt;
Make sure it is not inside a function otherwise it will not exist outside of that function (as denoted by the prefix &amp;quot;local&amp;quot;).&lt;br /&gt;
When defined in the main body of the script it will exist in all functions.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Next, we will need to load the xml file:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
function loadNews()&lt;br /&gt;
	-- load our &amp;quot;newsfeed.xml&amp;quot; file&lt;br /&gt;
	local newsfile = xmlLoadFile(&amp;quot;newsfeed.xml&amp;quot;)&lt;br /&gt;
	&lt;br /&gt;
	-- if it was successfully loaded&lt;br /&gt;
	if newsfile then&lt;br /&gt;
	&lt;br /&gt;
		-- always remember to unload files once you are finished&lt;br /&gt;
		xmlUnloadFile(newsfile)&lt;br /&gt;
	end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
'''Always remember to unload files once you are finished using them.'''&lt;br /&gt;
&lt;br /&gt;
Finally, we can add some more code to our loadNews function to read the news items into our newsItems table:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
function loadNews()&lt;br /&gt;
	local newsfile = xmlLoadFile(&amp;quot;newsfeed.xml&amp;quot;)&lt;br /&gt;
	&lt;br /&gt;
	if newsfile then&lt;br /&gt;
		-- loop through all the children of the root node (the &amp;quot;news&amp;quot; nodes)&lt;br /&gt;
		for index,itemNode in ipairs(xmlNodeGetChildren(newsfile)) do&lt;br /&gt;
			-- get the text (the news item) from the node&lt;br /&gt;
			local item = xmlNodeGetValue(itemNode)&lt;br /&gt;
			&lt;br /&gt;
			-- insert it into our newsItems table&lt;br /&gt;
			table.insert(newsItems,item)&lt;br /&gt;
		end&lt;br /&gt;
	&lt;br /&gt;
		xmlUnloadFile(newsfile)&lt;br /&gt;
	end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
We now have a table called 'newsItems' holding all of our news text from the xml file.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Updating the News==&lt;br /&gt;
Now that we have our GUI created and our news items ready, we need to write some code to update the news item being shown to players.&lt;br /&gt;
As stated earlier, our news items will be shown on our 'newsLabel' GUI label.&lt;br /&gt;
&lt;br /&gt;
To do this, we will write a simple function to get the next news item from our 'newsItems' table and display it in our label.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
-- define our function with a newIndex parameter, so that we can pass which news item we want to show&lt;br /&gt;
function updateNewsItem(newIndex)&lt;br /&gt;
	-- get the new news item from the table&lt;br /&gt;
	local item = newsItems[newIndex]&lt;br /&gt;
	&lt;br /&gt;
	-- update the label text&lt;br /&gt;
	guiSetText(newsLabel,item)&lt;br /&gt;
	&lt;br /&gt;
	-- update the 'currentItem' global variable&lt;br /&gt;
	currentItem = newIndex&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Sizing the Label===&lt;br /&gt;
To make our news scrolling as accurate as possible, we need to be able to make the GUI label the same size as the news item text it is showing.&lt;br /&gt;
&lt;br /&gt;
While this may seem like a tricky thing to do, it is made very easy with the function [[guiLabelGetTextExtent]].&lt;br /&gt;
This will tell us the extent, or width, of the text currently shown in our label.&lt;br /&gt;
So with a few modifications to our 'updateNewsItems' function, we get:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
function updateNewsItem(newIndex)&lt;br /&gt;
	local item = newsItems[newIndex]&lt;br /&gt;
	&lt;br /&gt;
	guiSetText(newsLabel,item)&lt;br /&gt;
	&lt;br /&gt;
	currentItem = newIndex&lt;br /&gt;
	&lt;br /&gt;
	-- get the current dimensions of the gui label&lt;br /&gt;
	local width,height = guiGetSize(newsLabel,false)&lt;br /&gt;
	&lt;br /&gt;
	-- get the text width of the label&lt;br /&gt;
	local extent = guiLabelGetTextExtent(newsLabel)&lt;br /&gt;
	&lt;br /&gt;
	-- update the size of the label with the new width (we do not change the height)&lt;br /&gt;
	guiSetSize(newsLabel,extent,height,false)&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Positioning the Label===&lt;br /&gt;
Now that our GUI label is the correct width, we need to move it to a position where it is ready to scroll onto the screen.&lt;br /&gt;
&lt;br /&gt;
Again, we can do this with a small modification to our 'updateNewsItems' function:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
function updateNewsItem(newIndex)&lt;br /&gt;
	local item = newsItems[newIndex]&lt;br /&gt;
	&lt;br /&gt;
	guiSetText(newsLabel,item)&lt;br /&gt;
	&lt;br /&gt;
	currentItem = newIndex&lt;br /&gt;
	&lt;br /&gt;
	local width,height = guiGetSize(newsLabel,false)&lt;br /&gt;
	&lt;br /&gt;
	local extent = guiLabelGetTextExtent(newsLabel)&lt;br /&gt;
	&lt;br /&gt;
	guiSetSize(newsLabel,extent,height,false)&lt;br /&gt;
	&lt;br /&gt;
	-- set the positon to the far right side of the gridlist, ready to scroll on to the left&lt;br /&gt;
	guiSetPosition(newsLabel,1,0,true)&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Scrolling the News==&lt;br /&gt;
The next step is to animate our news feed.&lt;br /&gt;
&lt;br /&gt;
===Looking at Frames===&lt;br /&gt;
To do this, we will introduce a new event: [[onClientRender]].&lt;br /&gt;
As stated on the [[onClientRender]] wiki page, this event is called every time GTA renders a new frame (ie: very often).&lt;br /&gt;
&lt;br /&gt;
As usual, to use this event we will need to create an event handler for it:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
addEventHandler(&amp;quot;onClientRender&amp;quot;,root,scrollNews)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
This will call our scrollNews function every frame, which we will then use to update the position of our news item.&lt;br /&gt;
&lt;br /&gt;
'''Make sure you add this handler after you have defined your scrollNews function.'''&lt;br /&gt;
&lt;br /&gt;
For our purposes, [[onClientRender]] has one main advantage over, for example, [[setTimer]].&lt;br /&gt;
As it is called every frame (and therefore is dependant on the players FPS), the movement of the news item will always appear to be completely smooth,&lt;br /&gt;
unlike using a timer which would often appear to lag.&lt;br /&gt;
&lt;br /&gt;
===Moving the News===&lt;br /&gt;
In our 'updateNewsItem' function, we position the 'newsLabel' to the far right, so we will scroll in from the right to the left.&lt;br /&gt;
&lt;br /&gt;
For this we will simply move the X position by -1 every frame:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
function scrollNews()&lt;br /&gt;
	-- if the newsLabel exists&lt;br /&gt;
	if newsLabel then&lt;br /&gt;
		-- get the current position of the label&lt;br /&gt;
		local x,y = guiGetPosition(newsLabel,false)&lt;br /&gt;
		&lt;br /&gt;
		-- set the new x position of the label as the old position -1&lt;br /&gt;
		guiSetPosition(newsLabel,x-1,y,false)&lt;br /&gt;
	end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Looping around===&lt;br /&gt;
Now that our news scrolls across the screen, we need to be able to check when it has scrolled too far to the left&lt;br /&gt;
so we can start scrolling from the far-right side again.&lt;br /&gt;
&lt;br /&gt;
We will also need to update the news item, so we should check the next item exists, and if it doesn't, go back to the first.&lt;br /&gt;
&lt;br /&gt;
For this we will use some simple maths in a modification to our 'scrollNews' function:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
function scrollNews()&lt;br /&gt;
	local x,y = guiGetPosition(newsLabel,false)&lt;br /&gt;
	&lt;br /&gt;
	local labelWidth, labelHeight = guiGetSize(newsLabel,false)&lt;br /&gt;
	&lt;br /&gt;
	-- if the far right position of the label (x + labelWidth) is greater than or equal to 0 (ie: still showing on the gridlist)&lt;br /&gt;
	if ((x-1) + labelWidth) &amp;gt;= 0 then&lt;br /&gt;
		-- compensate for a small off-by-one bug in MTA&lt;br /&gt;
		if x &amp;lt;= 0 then x = x - 1 end&lt;br /&gt;
		&lt;br /&gt;
		-- update the position as normal&lt;br /&gt;
		guiSetPosition(newsLabel,x-1,y,false)&lt;br /&gt;
		&lt;br /&gt;
	-- otherwise, we move on to the next item and reset the position&lt;br /&gt;
	else&lt;br /&gt;
		-- get the total number of items in the 'newsItems' table&lt;br /&gt;
		local totalItems = #newsItems&lt;br /&gt;
		&lt;br /&gt;
		-- if the next item on our list does not exist in our table&lt;br /&gt;
		if (currentItem + 1) &amp;gt; totalItems then&lt;br /&gt;
			-- loop back to the first item in the list&lt;br /&gt;
			updateNewsItem(1)&lt;br /&gt;
		else&lt;br /&gt;
			-- otherwise move onto the next item in the list&lt;br /&gt;
			updateNewsItem(currentItem + 1)&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Notice the use of the '#' symbol to get the size of the 'newsItems' table. &lt;br /&gt;
This is the Lua length operator, but it only works on tables that have numerical indexes (like an array or a list).&lt;br /&gt;
It also works on strings, eg: #&amp;quot;hello&amp;quot; would return 5.&lt;br /&gt;
&lt;br /&gt;
That completes this section of the tutorial.&lt;br /&gt;
For ideas on how to further improve and advance this code, continue reading the next section.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Improving the code==&lt;br /&gt;
This section will detail several ways to improve upon the code you now have.&lt;br /&gt;
&lt;br /&gt;
===GUI Customisation===&lt;br /&gt;
To give your GUI a more unique feel, you have the ability to customise some aspects of your GUI elements.&lt;br /&gt;
&lt;br /&gt;
For ideas on what is possible, browse the [[Client_Scripting_Functions#GUI_functions|MTA GUI functions]].&lt;br /&gt;
&lt;br /&gt;
For the purposes of this tutorial, we will be using Font, Colour and Alpha.&lt;br /&gt;
&lt;br /&gt;
To start, we will change the alpha of the background gridlist GUI element we are using.&lt;br /&gt;
To set the alpha, use [[guiSetAlpha]] and pass a value between 1 and 0; 1 being fully opaque and 0 being fully transparent.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
guiSetAlpha(newsGridlist,0.8)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Place this line of code in your 'createNewsFeed' function, after your gridlist has been created.&lt;br /&gt;
&lt;br /&gt;
I find an alpha level of 0.8 looks best, however this is personal preference and you can experiment to suit your needs.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Next, we will look at the font of the label text.&lt;br /&gt;
To set the font, use [[guiSetFont]] and pass the string name of the font you want to use (available to see on the [[GUI Fonts]] page).&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
guiSetFont(newsLabel,&amp;quot;default-bold-small&amp;quot;)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Place this line of code in your 'createNewsFeed' function, after your label has been created.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Finally, we will look at setting the colour of the label text.&lt;br /&gt;
To set the colour, use [[guiLabelSetColor]] and pass the individual red,green and blue values.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
guiLabelSetColor(newsLabel,255,70,0)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Place this line of code in your 'createNewsFeed' function, after your label has been created.&lt;br /&gt;
&lt;br /&gt;
This will give your news items an orange-red colour.&lt;br /&gt;
&lt;br /&gt;
===Multiple News Items===&lt;br /&gt;
In its current form, this code is only capable of showing one news item at a time.&lt;br /&gt;
However, with a few modifications we can show multiple news items at once, one after another.&lt;br /&gt;
&lt;br /&gt;
To begin with, we need to make sure we have a 'newItems' table defined at the very start of our script,&lt;br /&gt;
as well as a 'distance' variable that will control the pixel distance between each news item:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
local newsItems = {}&lt;br /&gt;
local distance = 30&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
So put these lines at the top of the file.&lt;br /&gt;
&lt;br /&gt;
Next, we will not know how many items we have (and consequently, how many labels we need) until we have loaded the file.&lt;br /&gt;
With that in mind, we will move around some of the code in our 'createNewsFeed' function to support this:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
function createNewsFeed()&lt;br /&gt;
	-- get the screen width and height&lt;br /&gt;
	local sWidth, sHeight = guiGetScreenSize()&lt;br /&gt;
 &lt;br /&gt;
	-- create the gridlist, using some maths to find the bottom-centre of the screen&lt;br /&gt;
	local Width,Height = 800,45&lt;br /&gt;
	local X = (sWidth/2) - (Width/2)&lt;br /&gt;
	local Y = sHeight - (Height/2)&lt;br /&gt;
	&lt;br /&gt;
	-- the gridlist will act as the background to our news reel&lt;br /&gt;
	newsGridlist = guiCreateGridList(X,Y,Width,Height,false)&lt;br /&gt;
	&lt;br /&gt;
	guiSetAlpha(newsGridlist,0.8)&lt;br /&gt;
	&lt;br /&gt;
	-- call our function to read the news out of the xml file, before we create the labels&lt;br /&gt;
	loadNews()&lt;br /&gt;
		&lt;br /&gt;
	-- define a table to hold our labels&lt;br /&gt;
	newsLabel = {}&lt;br /&gt;
	&lt;br /&gt;
	-- now we can loop all our news items, and create a label for each one&lt;br /&gt;
	for index,item in ipairs(newsItems) do&lt;br /&gt;
	&lt;br /&gt;
		-- because we now have one label for every item, we can just set the text here and it wont need to be changed again.&lt;br /&gt;
		newsLabel[index] = guiCreateLabel(0,0,Width,Height/2,item,false,newsGridlist)&lt;br /&gt;
		&lt;br /&gt;
		guiSetFont(newsLabel[index],&amp;quot;default-bold-small&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
		guiLabelSetColor(newsLabel[index],255,70,0)		&lt;br /&gt;
&lt;br /&gt;
		-- modify the width of the label to fit the text&lt;br /&gt;
		local extent = guiLabelGetTextExtent(newsLabel[index])		&lt;br /&gt;
		guiSetSize(newsLabel[index],extent,Height/2,false)&lt;br /&gt;
		&lt;br /&gt;
		&lt;br /&gt;
		-- get the size of the gridlist&lt;br /&gt;
		local x,y = guiGetSize(newsGridlist,false)&lt;br /&gt;
		&lt;br /&gt;
		-- loop from 1 until index-1 in steps of 1&lt;br /&gt;
		-- this allows us to loop every label before the label we are currently on&lt;br /&gt;
		for i=1, index-1, 1 do&lt;br /&gt;
			-- tally up the sizes of all labels before our current one and store them in x&lt;br /&gt;
			local width = guiGetSize(newsLabel[i],false)&lt;br /&gt;
			x = x + width&lt;br /&gt;
		end&lt;br /&gt;
		&lt;br /&gt;
		-- put a 'distance' pixel gap between each news item&lt;br /&gt;
		x = x + (distance*(index-1))&lt;br /&gt;
		&lt;br /&gt;
		-- set the positon to the far right side of the gridlist, ready to scroll on to the left&lt;br /&gt;
		guiSetPosition(newsLabel[index],x,0,false)	&lt;br /&gt;
	end	&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Now we need to update our 'updateNewsItem' function to account for having multiple labels:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
function updateNewsItem(newIndex)&lt;br /&gt;
	-- find the index of the news item directly infront (in the looping order) of the newIndex item&lt;br /&gt;
	local index = newIndex - 1&lt;br /&gt;
	if index == 0 then index = #newsItems end&lt;br /&gt;
	&lt;br /&gt;
	-- find the position of the right-edge of the label directly infront of the newIndex label&lt;br /&gt;
	local x = guiGetPosition(newsLabel[index],false) &lt;br /&gt;
	local width = guiGetSize(newsLabel[index],false)&lt;br /&gt;
	x = x + width&lt;br /&gt;
&lt;br /&gt;
	-- add a 'distance' pixel gap in&lt;br /&gt;
	x = x + distance&lt;br /&gt;
&lt;br /&gt;
	-- check the new position isnt actually on the gridlist (ie: so it wont suddenly appear in the centre of the list)&lt;br /&gt;
	local gridlistWidth = guiGetSize(newsGridlist,false)&lt;br /&gt;
	&lt;br /&gt;
	if x &amp;lt; gridlistWidth then&lt;br /&gt;
		-- if it is, simple move it back to the edge&lt;br /&gt;
		x = gridlistWidth&lt;br /&gt;
	end&lt;br /&gt;
	&lt;br /&gt;
	-- set the new position&lt;br /&gt;
	guiSetPosition(newsLabel[newIndex],x,0,false)&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Finally, we need to make some small adjustments to our 'scrollNews' function:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
function scrollNews()&lt;br /&gt;
	if newsItems then&lt;br /&gt;
		-- loop every news item&lt;br /&gt;
		for index,item in ipairs(newsItems) do&lt;br /&gt;
			local x,y = guiGetPosition(newsLabel[index],false)&lt;br /&gt;
			&lt;br /&gt;
			local labelWidth, labelHeight = guiGetSize(newsLabel[index],false)&lt;br /&gt;
			&lt;br /&gt;
			-- if the far right position of the label (x + labelWidth) is greater than or equal to 0 (ie: still showing on the gridlist)&lt;br /&gt;
			if ((x-1) + labelWidth) &amp;gt;= 0 then&lt;br /&gt;
				-- compensate for a small off-by-one bug in MTA&lt;br /&gt;
				if x &amp;lt;= 0 then x = x - 1 end&lt;br /&gt;
			&lt;br /&gt;
				-- update the position as normal&lt;br /&gt;
				guiSetPosition(newsLabel[index],x-1,y,false)&lt;br /&gt;
				&lt;br /&gt;
			-- otherwise, we move on to the next item and reset the position&lt;br /&gt;
			else&lt;br /&gt;
				updateNewsItem(index)&lt;br /&gt;
			end&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
You should now have multiple news items scrolling along your news feed simultaneously.&lt;br /&gt;
&lt;br /&gt;
===Globally controlled scroll speed===&lt;br /&gt;
As with the 'distance' variable above, we can set a global variable for controlling the scroll speed of the news items as well.&lt;br /&gt;
Note that the speed will still be dependant on the players FPS (ie: lower FPS means slightly slower scrolling).&lt;br /&gt;
&lt;br /&gt;
To do this, we simply need to create the variable at the start of our code:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
local scrollSpeed = 1&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Put this line at the top of your file.&lt;br /&gt;
&lt;br /&gt;
Then, we just replace the instance of &amp;quot;x-1&amp;quot; in our 'scrollNews' function with &amp;quot;x-scrollSpeed&amp;quot;:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
function scrollNews()&lt;br /&gt;
		...&lt;br /&gt;
				-- update the position as normal&lt;br /&gt;
				guiSetPosition(newsLabel[index],x-scrollSpeed,y,false)&lt;br /&gt;
		...&lt;br /&gt;
	end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
That concludes this section of the tutorial.&lt;/div&gt;</summary>
		<author><name>R3mp</name></author>
	</entry>
	<entry>
		<id>https://wiki.multitheftauto.com/index.php?title=Scripting_the_GUI_-_Tutorial_3&amp;diff=22186</id>
		<title>Scripting the GUI - Tutorial 3</title>
		<link rel="alternate" type="text/html" href="https://wiki.multitheftauto.com/index.php?title=Scripting_the_GUI_-_Tutorial_3&amp;diff=22186"/>
		<updated>2010-01-05T21:19:29Z</updated>

		<summary type="html">&lt;p&gt;R3mp: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;'''Scripting the GUI - Tutorial 3 (Scrolling News Feed)'''&lt;br /&gt;
&lt;br /&gt;
In this tutorial we will explore how to create a simple scrolling news feed GUI, &lt;br /&gt;
allowing you to quickly and easily show server updates and other server information to your players.&lt;br /&gt;
We will store all news items in a clientside xml file and use some simple xml reading to load them into the game.&lt;br /&gt;
&lt;br /&gt;
We will then animate the news item to scroll along the bottom of the screen, updating the news text once it has scrolled beyond the edge of the screen.&lt;br /&gt;
&lt;br /&gt;
'''Note that this tutorial assumes you are familiar with all the content covered in the [[Introduction to Scripting GUI|GUI Scripting Introduction]].'''&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Setting up the News Feed==&lt;br /&gt;
To begin, open up a clientside lua file (if you have been following the [[Introduction to Scripting GUI|GUI Scripting Introduction]], this is gui.lua) to work with.&lt;br /&gt;
&lt;br /&gt;
===Creating the GUI===&lt;br /&gt;
As with the previous tutorial, you should be suitably familiar with GUI creation already so we will not go into too much detail here. &lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
function createNewsFeed()&lt;br /&gt;
	-- get the screen width and height&lt;br /&gt;
	local sWidth, sHeight = guiGetScreenSize()&lt;br /&gt;
 &lt;br /&gt;
	-- create the gridlist, using some maths to find the bottom-centre of the screen&lt;br /&gt;
	local Width,Height = 800,45&lt;br /&gt;
	local X = (sWidth/2) - (Width/2)&lt;br /&gt;
	local Y = sHeight - (Height/2)&lt;br /&gt;
	&lt;br /&gt;
	-- the gridlist will act as the background to our news reel&lt;br /&gt;
	newsGridlist = guiCreateGridList(X,Y,Width,Height,false)&lt;br /&gt;
	&lt;br /&gt;
	-- create the label in the same place, but as a child of the gridlist&lt;br /&gt;
	-- also make it half the height of the gridlist, as half of the gridlist is off the bottom of the screen&lt;br /&gt;
	newsLabel = guiCreateLabel(X,Y,Width,Height/2,&amp;quot;Test text&amp;quot;,false,newsGridlist)&lt;br /&gt;
	&lt;br /&gt;
	-- call our function to read the news out of the xml file&lt;br /&gt;
	loadNews()&lt;br /&gt;
	&lt;br /&gt;
	-- load the first news item in the table&lt;br /&gt;
	updateNewsItem(1)&lt;br /&gt;
	&lt;br /&gt;
	-- define a global variable called 'currentItem' with the value 1&lt;br /&gt;
	currentItem = 1&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
addEventHandler(&amp;quot;onClientResourceStart&amp;quot;,resourceRoot,createNewsFeed)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Note that the label is created as a child of the gridlist. &lt;br /&gt;
Not only is this good practice in general, but it means that we can freely move parts of the label beyond the edge of the gridlist without them showing, which is critical to the visual effect of this tutorial.&lt;br /&gt;
&lt;br /&gt;
Also notice the use of the 'resourceRoot' variable. This is an MTA variable that holds the root value of the resource you are using it in.&lt;br /&gt;
&lt;br /&gt;
The 'currentItem' variable is what we will use to keep track of which news item we are currently showing&lt;br /&gt;
&lt;br /&gt;
===Writing the News===&lt;br /&gt;
Now that we have our GUI created, we need some news to fill it with.&lt;br /&gt;
To do this, we will read our news items out of a clientside xml file.&lt;br /&gt;
&lt;br /&gt;
So, navigate to your resource directory and create a new xml file called newsfeed.xml (don't forget to add it to your meta.xml with the appropriate client tag).&lt;br /&gt;
&lt;br /&gt;
Inside this file enter the following information:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;root&amp;gt;&lt;br /&gt;
	&amp;lt;news&amp;gt;This is an example news item.&amp;lt;/news&amp;gt;&lt;br /&gt;
	&amp;lt;news&amp;gt;From the 'Scripting the GUI' tutorial.&amp;lt;/news&amp;gt;&lt;br /&gt;
	&amp;lt;news&amp;gt;Showing scrolling news text.&amp;lt;/news&amp;gt;&lt;br /&gt;
	&amp;lt;news&amp;gt;Written on a GUI news feed.&amp;lt;/news&amp;gt;&lt;br /&gt;
&amp;lt;/root&amp;gt;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
As you can see, each news item is defined as a &amp;lt;news&amp;gt; node with the value being the news text you want to display.&lt;br /&gt;
There is no limit on how many news items you can add.&lt;br /&gt;
&lt;br /&gt;
===Collecting the News===&lt;br /&gt;
Once we have written all our news items, we will need to collect them all and store them in a table on the client.&lt;br /&gt;
We will do this when the resource starts, saving us from having to repeatedly access the xml for new news items.&lt;br /&gt;
&lt;br /&gt;
First, we need to define a table to store the items in:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
local newsItems = {}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Add this line to the top of your script.&lt;br /&gt;
Make sure it is not inside a function otherwise it will not exist outside of that function (as denoted by the prefix &amp;quot;local&amp;quot;).&lt;br /&gt;
When defined in the main body of the script it will exist in all functions.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Next, we will need to load the xml file:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
function loadNews()&lt;br /&gt;
	-- load our &amp;quot;newsfeed.xml&amp;quot; file&lt;br /&gt;
	local newsfile = xmlLoadFile(&amp;quot;newsfeed.xml&amp;quot;)&lt;br /&gt;
	&lt;br /&gt;
	-- if it was successfully loaded&lt;br /&gt;
	if newsfile then&lt;br /&gt;
	&lt;br /&gt;
		-- always remember to unload files once you are finished&lt;br /&gt;
		xmlUnloadFile(newsfile)&lt;br /&gt;
	end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
'''Always remember to unload files once you are finished using them.'''&lt;br /&gt;
&lt;br /&gt;
Finally, we can add some more code to our loadNews function to read the news items into our newsItems table:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
function loadNews()&lt;br /&gt;
	local newsfile = xmlLoadFile(&amp;quot;newsfeed.xml&amp;quot;)&lt;br /&gt;
	&lt;br /&gt;
	if newsfile then&lt;br /&gt;
		-- loop through all the children of the root node (the &amp;quot;news&amp;quot; nodes)&lt;br /&gt;
		for index,itemNode in ipairs(xmlNodeGetChildren(newsfile)) do&lt;br /&gt;
			-- get the text (the news item) from the node&lt;br /&gt;
			local item = xmlNodeGetValue(itemNode)&lt;br /&gt;
			&lt;br /&gt;
			-- insert it into our newsItems table&lt;br /&gt;
			table.insert(newsItems,item)&lt;br /&gt;
		end&lt;br /&gt;
	&lt;br /&gt;
		xmlUnloadFile(newsfile)&lt;br /&gt;
	end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
We now have a table called 'newsItems' holding all of our news text from the xml file.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Updating the News==&lt;br /&gt;
Now that we have our GUI created and our news items ready, we need to write some code to update the news item being shown to players.&lt;br /&gt;
As stated earlier, our news items will be shown on our 'newsLabel' GUI label.&lt;br /&gt;
&lt;br /&gt;
To do this, we will write a simple function to get the next news item from our 'newsItems' table and display it in our label.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
-- define our function with a newIndex parameter, so that we can pass which news item we want to show&lt;br /&gt;
function updateNewsItem(newIndex)&lt;br /&gt;
	-- get the new news item from the table&lt;br /&gt;
	local item = newsItems[newIndex]&lt;br /&gt;
	&lt;br /&gt;
	-- update the label text&lt;br /&gt;
	guiSetText(newsLabel,item)&lt;br /&gt;
	&lt;br /&gt;
	-- update the 'currentItem' global variable&lt;br /&gt;
	currentItem = newIndex&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Sizing the Label===&lt;br /&gt;
To make our news scrolling as accurate as possible, we need to be able to make the GUI label the same size as the news item text it is showing.&lt;br /&gt;
&lt;br /&gt;
While this may seem like a tricky thing to do, it is made very easy with the function [[guiLabelGetTextExtent]].&lt;br /&gt;
This will tell us the extent, or width, of the text currently shown in our label.&lt;br /&gt;
So with a few modifications to our 'updateNewsItems' function, we get:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
function updateNewsItem(newIndex)&lt;br /&gt;
	local item = newsItems[newIndex]&lt;br /&gt;
	&lt;br /&gt;
	guiSetText(newsLabel,item)&lt;br /&gt;
	&lt;br /&gt;
	currentItem = newIndex&lt;br /&gt;
	&lt;br /&gt;
	-- get the current dimensions of the gui label&lt;br /&gt;
	local width,height = guiGetSize(newsLabel,false)&lt;br /&gt;
	&lt;br /&gt;
	-- get the text width of the label&lt;br /&gt;
	local extent = guiLabelGetTextExtent(newsLabel)&lt;br /&gt;
	&lt;br /&gt;
	-- update the size of the label with the new width (we do not change the height)&lt;br /&gt;
	guiSetSize(newsLabel,extent,height,false)&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Positioning the Label===&lt;br /&gt;
Now that our GUI label is the correct width, we need to move it to a position where it is ready to scroll onto the screen.&lt;br /&gt;
&lt;br /&gt;
Again, we can do this with a small modification to our 'updateNewsItems' function:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
function updateNewsItem(newIndex)&lt;br /&gt;
	local item = newsItems[newIndex]&lt;br /&gt;
	&lt;br /&gt;
	guiSetText(newsLabel,item)&lt;br /&gt;
	&lt;br /&gt;
	currentItem = newIndex&lt;br /&gt;
	&lt;br /&gt;
	local width,height = guiGetSize(newsLabel,false)&lt;br /&gt;
	&lt;br /&gt;
	local extent = guiLabelGetTextExtent(newsLabel)&lt;br /&gt;
	&lt;br /&gt;
	guiSetSize(newsLabel,extent,height,false)&lt;br /&gt;
	&lt;br /&gt;
	-- set the positon to the far right side of the gridlist, ready to scroll on to the left&lt;br /&gt;
	guiSetPosition(newsLabel,1,0,true)&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Scrolling the News==&lt;br /&gt;
The next step is to animate our news feed.&lt;br /&gt;
&lt;br /&gt;
===Looking at Frames===&lt;br /&gt;
To do this, we will introduce a new event: [[onClientRender]].&lt;br /&gt;
As stated on the [[onClientRender]] wiki page, this event is called every time GTA renders a new frame (ie: very often).&lt;br /&gt;
&lt;br /&gt;
As usual, to use this event we will need to create an event handler for it:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
addEventHandler(&amp;quot;onClientRender&amp;quot;,root,scrollNews)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
This will call our scrollNews function every frame, which we will then use to update the position of our news item.&lt;br /&gt;
&lt;br /&gt;
'''Make sure you add this handler after you have defined your scrollNews function.'''&lt;br /&gt;
&lt;br /&gt;
For our purposes, [[onClientRender]] has one main advantage over, for example, [[setTimer]].&lt;br /&gt;
As it is called every frame (and therefore is dependant on the players FPS), the movement of the news item will always appear to be completely smooth,&lt;br /&gt;
unlike using a timer which would often appear to lag.&lt;br /&gt;
&lt;br /&gt;
===Moving the News===&lt;br /&gt;
In our 'updateNewsItem' function, we position the 'newsLabel' to the far right, so we will scroll in from the right to the left.&lt;br /&gt;
&lt;br /&gt;
For this we will simply move the X position by -1 every frame:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
function scrollNews()&lt;br /&gt;
	-- if the newsLabel exists&lt;br /&gt;
	if newsLabel then&lt;br /&gt;
		-- get the current position of the label&lt;br /&gt;
		local x,y = guiGetPosition(newsLabel,false)&lt;br /&gt;
		&lt;br /&gt;
		-- set the new x position of the label as the old position -1&lt;br /&gt;
		guiSetPosition(newsLabel,x-1,y,false)&lt;br /&gt;
	end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Looping around===&lt;br /&gt;
Now that our news scrolls across the screen, we need to be able to check when it has scrolled too far to the left&lt;br /&gt;
so we can start scrolling from the far-right side again.&lt;br /&gt;
&lt;br /&gt;
We will also need to update the news item, so we should check the next item exists, and if it doesn't, go back to the first.&lt;br /&gt;
&lt;br /&gt;
For this we will use some simple maths in a modification to our 'scrollNews' function:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
function scrollNews()&lt;br /&gt;
	local x,y = guiGetPosition(newsLabel,false)&lt;br /&gt;
	&lt;br /&gt;
	local labelWidth, labelHeight = guiGetSize(newsLabel,false)&lt;br /&gt;
	&lt;br /&gt;
	-- if the far right position of the label (x + labelWidth) is greater than or equal to 0 (ie: still showing on the gridlist)&lt;br /&gt;
	if ((x-1) + labelWidth) &amp;gt;= 0 then&lt;br /&gt;
		-- compensate for a small off-by-one bug in MTA&lt;br /&gt;
		if x &amp;lt;= 0 then x = x - 1 end&lt;br /&gt;
		&lt;br /&gt;
		-- update the position as normal&lt;br /&gt;
		guiSetPosition(newsLabel,x-1,y,false)&lt;br /&gt;
		&lt;br /&gt;
	-- otherwise, we move on to the next item and reset the position&lt;br /&gt;
	else&lt;br /&gt;
		-- get the total number of items in the 'newsItems' table&lt;br /&gt;
		local totalItems = #newsItems&lt;br /&gt;
		&lt;br /&gt;
		-- if the next item on our list does not exist in our table&lt;br /&gt;
		if (currentItem + 1) &amp;gt; totalItems then&lt;br /&gt;
			-- loop back to the first item in the list&lt;br /&gt;
			updateNewsItem(1)&lt;br /&gt;
		else&lt;br /&gt;
			-- otherwise move onto the next item in the list&lt;br /&gt;
			updateNewsItem(currentItem + 1)&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Notice the use of the '#' symbol to get the size of the 'newsItems' table. &lt;br /&gt;
This is the Lua length operator, but it only works on tables that have numerical indexes (like an array or a list).&lt;br /&gt;
It also works on strings, eg: #&amp;quot;hello&amp;quot; would return 5.&lt;br /&gt;
&lt;br /&gt;
That completes this section of the tutorial.&lt;br /&gt;
For ideas on how to further improve and advance this code, continue reading the next section.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Improving the code==&lt;br /&gt;
This section will detail several ways to improve upon the code you now have.&lt;br /&gt;
&lt;br /&gt;
===GUI Customisation===&lt;br /&gt;
To give your GUI a more unique feel, you have the ability to customise some aspects of your GUI elements.&lt;br /&gt;
&lt;br /&gt;
For ideas on what is possible, browse the [[Client_Scripting_Functions#GUI_functions|MTA GUI functions]].&lt;br /&gt;
&lt;br /&gt;
For the purposes of this tutorial, we will be using Font, Colour and Alpha.&lt;br /&gt;
&lt;br /&gt;
To start, we will change the alpha of the background gridlist GUI element we are using.&lt;br /&gt;
To set the alpha, use [[guiSetAlpha]] and pass a value between 1 and 0; 1 being fully opaque and 0 being fully transparent.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
guiSetAlpha(newsGridlist,0.8)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Place this line of code in your 'createNewsFeed' function, after your gridlist has been created.&lt;br /&gt;
&lt;br /&gt;
I find an alpha level of 0.8 looks best, however this is personal preference and you can experiment to suit your needs.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Next, we will look at the font of the label text.&lt;br /&gt;
To set the font, use [[guiSetFont]] and pass the string name of the font you want to use (available to see on the [[GUI Fonts]] page).&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
guiSetFont(newsLabel,&amp;quot;default-bold-small&amp;quot;)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Place this line of code in your 'createNewsFeed' function, after your label has been created.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Finally, we will look at setting the colour of the label text.&lt;br /&gt;
To set the colour, use [[guiLabelSetColor]] and pass the individual red,green and blue values.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
guiLabelSetColor(newsLabel,255,70,0)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Place this line of code in your 'createNewsFeed' function, after your label has been created.&lt;br /&gt;
&lt;br /&gt;
This will give your news items an orange-red colour.&lt;br /&gt;
&lt;br /&gt;
===Multiple News Items===&lt;br /&gt;
In its current form, this code is only capable of showing one news item at a time.&lt;br /&gt;
However, with a few modifications we can show multiple news items at once, one after another.&lt;br /&gt;
&lt;br /&gt;
To begin with, we need to make sure we have a 'newItems' table defined at the very start of our script,&lt;br /&gt;
as well as a 'distance' variable that will control the pixel distance between each news item:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
local newsItems = {}&lt;br /&gt;
local distance = 30&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
So put these lines at the top of the file.&lt;br /&gt;
&lt;br /&gt;
Next, we will not know how many items we have (and consequently, how many labels we need) until we have loaded the file.&lt;br /&gt;
With that in mind, we will move around some of the code in our 'createNewsFeed' function to support this:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
function createNewsFeed()&lt;br /&gt;
	-- get the screen width and height&lt;br /&gt;
	local sWidth, sHeight = guiGetScreenSize()&lt;br /&gt;
 &lt;br /&gt;
	-- create the gridlist, using some maths to find the bottom-centre of the screen&lt;br /&gt;
	local Width,Height = 800,45&lt;br /&gt;
	local X = (sWidth/2) - (Width/2)&lt;br /&gt;
	local Y = sHeight - (Height/2)&lt;br /&gt;
	&lt;br /&gt;
	-- the gridlist will act as the background to our news reel&lt;br /&gt;
	newsGridlist = guiCreateGridList(X,Y,Width,Height,false)&lt;br /&gt;
	&lt;br /&gt;
	guiSetAlpha(newsGridlist,0.8)&lt;br /&gt;
	&lt;br /&gt;
	-- call our function to read the news out of the xml file, before we create the labels&lt;br /&gt;
	loadNews()&lt;br /&gt;
		&lt;br /&gt;
	-- define a table to hold our labels&lt;br /&gt;
	newsLabel = {}&lt;br /&gt;
	&lt;br /&gt;
	-- now we can loop all our news items, and create a label for each one&lt;br /&gt;
	for index,item in ipairs(newsItems) do&lt;br /&gt;
	&lt;br /&gt;
		-- because we now have one label for every item, we can just set the text here and it wont need to be changed again.&lt;br /&gt;
		newsLabel[index] = guiCreateLabel(0,0,Width,Height/2,item,false,newsGridlist)&lt;br /&gt;
		&lt;br /&gt;
		guiSetFont(newsLabel[index],&amp;quot;default-bold-small&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
		guiLabelSetColor(newsLabel[index],255,70,0)		&lt;br /&gt;
&lt;br /&gt;
		-- modify the width of the label to fit the text&lt;br /&gt;
		local extent = guiLabelGetTextExtent(newsLabel[index])		&lt;br /&gt;
		guiSetSize(newsLabel[index],extent,Height/2,false)&lt;br /&gt;
		&lt;br /&gt;
		&lt;br /&gt;
		-- get the size of the gridlist&lt;br /&gt;
		local x,y = guiGetSize(newsGridlist,false)&lt;br /&gt;
		&lt;br /&gt;
		-- loop from 1 until index-1 in steps of 1&lt;br /&gt;
		-- this allows us to loop every label before the label we are currently on&lt;br /&gt;
		for i=1, index-1, 1 do&lt;br /&gt;
			-- tally up the sizes of all labels before our current one and store them in x&lt;br /&gt;
			local width = guiGetSize(newsLabel[i],false)&lt;br /&gt;
			x = x + width&lt;br /&gt;
		end&lt;br /&gt;
		&lt;br /&gt;
		-- put a 'distance' pixel gap between each news item&lt;br /&gt;
		x = x + (distance*(index-1))&lt;br /&gt;
		&lt;br /&gt;
		-- set the positon to the far right side of the gridlist, ready to scroll on to the left&lt;br /&gt;
		guiSetPosition(newsLabel[index],x,0,false)	&lt;br /&gt;
	end	&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Now we need to update our 'updateNewsItem' function to account for having multiple labels:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
function updateNewsItem(newIndex)&lt;br /&gt;
	-- find the index of the news item directly infront (in the looping order) of the newIndex item&lt;br /&gt;
	local index = newIndex - 1&lt;br /&gt;
	if index == 0 then index = #newsItems end&lt;br /&gt;
	&lt;br /&gt;
	-- find the position of the right-edge of the label directly infront of the newIndex label&lt;br /&gt;
	local x = guiGetPosition(newsLabel[index],false) &lt;br /&gt;
	local width = guiGetSize(newsLabel[index],false)&lt;br /&gt;
	x = x + width&lt;br /&gt;
&lt;br /&gt;
	-- add a 'distance' pixel gap in&lt;br /&gt;
	x = x + distance&lt;br /&gt;
&lt;br /&gt;
	-- check the new position isnt actually on the gridlist (ie: so it wont suddenly appear in the centre of the list)&lt;br /&gt;
	local gridlistWidth = guiGetSize(newsGridlist,false)&lt;br /&gt;
	&lt;br /&gt;
	if x &amp;lt; gridlistWidth then&lt;br /&gt;
		-- if it is, simple move it back to the edge&lt;br /&gt;
		x = gridlistWidth&lt;br /&gt;
	end&lt;br /&gt;
	&lt;br /&gt;
	-- set the new position&lt;br /&gt;
	guiSetPosition(newsLabel[newIndex],x,0,false)&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Finally, we need to make some small adjustments to our 'scrollNews' function:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
function scrollNews()&lt;br /&gt;
	if newsItems then&lt;br /&gt;
		-- loop every news item&lt;br /&gt;
		for index,item in ipairs(newsItems) do&lt;br /&gt;
			local x,y = guiGetPosition(newsLabel[index],false)&lt;br /&gt;
			&lt;br /&gt;
			local labelWidth, labelHeight = guiGetSize(newsLabel[index],false)&lt;br /&gt;
			&lt;br /&gt;
			-- if the far right position of the label (x + labelWidth) is greater than or equal to 0 (ie: still showing on the gridlist)&lt;br /&gt;
			if ((x-1) + labelWidth) &amp;gt;= 0 then&lt;br /&gt;
				-- compensate for a small off-by-one bug in MTA&lt;br /&gt;
				if x &amp;lt;= 0 then x = x - 1 end&lt;br /&gt;
			&lt;br /&gt;
				-- update the position as normal&lt;br /&gt;
				guiSetPosition(newsLabel[index],x-1,y,false)&lt;br /&gt;
				&lt;br /&gt;
			-- otherwise, we move on to the next item and reset the position&lt;br /&gt;
			else&lt;br /&gt;
				updateNewsItem(index)&lt;br /&gt;
			end&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
You should now have multiple news items scrolling along your news feed simultaneously.&lt;br /&gt;
&lt;br /&gt;
===Globally controlled scroll speed===&lt;br /&gt;
As with the 'distance' variable above, we can set a global variable for controlling the scroll speed of the news items as well.&lt;br /&gt;
Note that the speed will still be dependant on the players FPS (ie: lower FPS means slightly slower scrolling).&lt;br /&gt;
&lt;br /&gt;
To do this, we simply need to create the variable at the start of our code:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
local scrollSpeed = 1&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Put this line at the top of your file.&lt;br /&gt;
&lt;br /&gt;
Then, we just replace the instance of &amp;quot;x-1&amp;quot; in our 'scrollNews' function with &amp;quot;x-scrollSpeed&amp;quot;:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
function scrollNews()&lt;br /&gt;
		...&lt;br /&gt;
				-- update the position as normal&lt;br /&gt;
				guiSetPosition(newsLabel[index],x-scrollSpeed,y,false)&lt;br /&gt;
		...&lt;br /&gt;
	end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
That concludes this section of the tutorial.&lt;/div&gt;</summary>
		<author><name>R3mp</name></author>
	</entry>
	<entry>
		<id>https://wiki.multitheftauto.com/index.php?title=Scripting_the_GUI_-_Tutorial_2&amp;diff=22185</id>
		<title>Scripting the GUI - Tutorial 2</title>
		<link rel="alternate" type="text/html" href="https://wiki.multitheftauto.com/index.php?title=Scripting_the_GUI_-_Tutorial_2&amp;diff=22185"/>
		<updated>2010-01-05T21:19:12Z</updated>

		<summary type="html">&lt;p&gt;R3mp: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;'''Scripting the GUI - Tutorial 2 (Gates + Keypads)'''&lt;br /&gt;
&lt;br /&gt;
In this tutorial we will look at creating GUI keypads with combination codes for map-defined object gates.&lt;br /&gt;
We will be using serverside keycodes, with some client - server interaction to verify the codes and report the outcome.&lt;br /&gt;
&lt;br /&gt;
'''Note that this tutorial assumes you are familiar with all the content covered in the [[Introduction to Scripting GUI|GUI Scripting Introduction]].'''&lt;br /&gt;
&lt;br /&gt;
[[Image:Gui_keypad_tutorial.png|thumb|GUI Keypad]]&lt;br /&gt;
&lt;br /&gt;
==Setting up the Keypad==&lt;br /&gt;
To begin, open up a clientside lua file (if you have been following the [[Introduction to Scripting GUI|GUI Scripting Introduction]], this is gui.lua) to work with.&lt;br /&gt;
&lt;br /&gt;
===Creating the GUI===&lt;br /&gt;
By now, GUI creation should seem relatively straight forward, so we will not go over this in too much detail.&lt;br /&gt;
As in [[Scripting the GUI - Tutorial 1|Tutorial 1]] we will be using '''absolute''' values in this tutorial.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
function createKeypad()&lt;br /&gt;
	-- get the screen width and height&lt;br /&gt;
	local sWidth, sHeight = guiGetScreenSize()&lt;br /&gt;
&lt;br /&gt;
	-- create the window, using some maths to find the centre of the screen&lt;br /&gt;
	local Width,Height = 142,276&lt;br /&gt;
	local X = (sWidth/2) - (Width/2)&lt;br /&gt;
	local Y = (sHeight/2) - (Height/2)&lt;br /&gt;
	keypadWindow = guiCreateWindow(X,Y,Width,Height,&amp;quot;Keypad&amp;quot;,false)&lt;br /&gt;
	&lt;br /&gt;
	-- don't allow people to resize the keypad&lt;br /&gt;
	guiWindowSetSizable(keypadWindow,false)&lt;br /&gt;
&lt;br /&gt;
	-- create buttons labeled 0-9, &amp;quot;*&amp;quot;, &amp;quot;#&amp;quot;, &amp;quot;Enter&amp;quot; and &amp;quot;C&amp;quot; (clear)&lt;br /&gt;
	keypadButton1 = guiCreateButton(13,68,37,36,&amp;quot;1&amp;quot;,false,keypadWindow)&lt;br /&gt;
	keypadButton2 = guiCreateButton(53,68,37,36,&amp;quot;2&amp;quot;,false,keypadWindow)&lt;br /&gt;
	keypadButton3 = guiCreateButton(93,68,37,36,&amp;quot;3&amp;quot;,false,keypadWindow)&lt;br /&gt;
	keypadButton4 = guiCreateButton(13,108,37,36,&amp;quot;4&amp;quot;,false,keypadWindow)&lt;br /&gt;
	keypadButton5 = guiCreateButton(53,108,37,36,&amp;quot;5&amp;quot;,false,keypadWindow)&lt;br /&gt;
	keypadButton6 = guiCreateButton(93,108,37,36,&amp;quot;6&amp;quot;,false,keypadWindow)&lt;br /&gt;
	keypadButton7 = guiCreateButton(13,148,37,36,&amp;quot;7&amp;quot;,false,keypadWindow)&lt;br /&gt;
	keypadButton8 = guiCreateButton(53,148,37,36,&amp;quot;8&amp;quot;,false,keypadWindow)&lt;br /&gt;
	keypadButton9 = guiCreateButton(93,148,37,36,&amp;quot;9&amp;quot;,false,keypadWindow)&lt;br /&gt;
	keypadButtonAsterix = guiCreateButton(13,188,37,36,&amp;quot;*&amp;quot;,false,keypadWindow)&lt;br /&gt;
	keypadButton0 = guiCreateButton(53,188,37,36,&amp;quot;0&amp;quot;,false,keypadWindow)&lt;br /&gt;
	keypadButtonHash = guiCreateButton(93,188,37,36,&amp;quot;#&amp;quot;,false,keypadWindow)&lt;br /&gt;
	keypadButtonExit = guiCreateButton(13,228,37,36,&amp;quot;Exit&amp;quot;,false,keypadWindow)&lt;br /&gt;
	keypadButtonEnter = guiCreateButton(53,228,37,36,&amp;quot;Enter&amp;quot;,false,keypadWindow)&lt;br /&gt;
	keypadButtonClear = guiCreateButton(93,228,37,36,&amp;quot;Clear&amp;quot;,false,keypadWindow)&lt;br /&gt;
&lt;br /&gt;
	-- create a gridlist to act as a backdrop on the kaypad display&lt;br /&gt;
	keypadGridlistDisplay = guiCreateGridList(13,25,117,33,false,keypadWindow)&lt;br /&gt;
	guiGridListSetSelectionMode(keypadGridlistDisplay,2)&lt;br /&gt;
	guiSetAlpha(keypadGridlistDisplay,0.6)&lt;br /&gt;
	-- create a label so we can write text on the keypad display&lt;br /&gt;
	keypadLabelDisplay = guiCreateLabel(14,26,115,30,&amp;quot;Enter Keycode.&amp;quot;,false,keypadWindow)&lt;br /&gt;
	guiLabelSetColor(keypadLabelDisplay,255,000,000)&lt;br /&gt;
	guiLabelSetVerticalAlign(keypadLabelDisplay,&amp;quot;center&amp;quot;)&lt;br /&gt;
	guiLabelSetHorizontalAlign(keypadLabelDisplay,&amp;quot;center&amp;quot;,false)&lt;br /&gt;
	&lt;br /&gt;
	guiSetVisible(keypadWindow,false)&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
-- create the GUI when the resource starts&lt;br /&gt;
addEventHandler(&amp;quot;onClientResourceStart&amp;quot;,getResourceRootElement(getThisResource()),createKeypad)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
As you can see, the keypad consists of 10 numerical keys (0-9), two character keys (* and #), a clear key, an exit key and an enter key.&lt;br /&gt;
This means the codes used on the keypad can contain any of these characters (0123456789*#).&lt;br /&gt;
&lt;br /&gt;
===Managing the display===&lt;br /&gt;
We will begin by writing a small function to control the display on the keypad.&lt;br /&gt;
This is done by encapsulating several methods of changing the text into a single function,&lt;br /&gt;
which will enable us to easily add/remove text from the display later on.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
function updateDisplay(text)&lt;br /&gt;
	-- if we are passing some text&lt;br /&gt;
	if text then&lt;br /&gt;
		-- if its a digit or * or #, then append it to the end of the display&lt;br /&gt;
		if tonumber(text) or text == &amp;quot;*&amp;quot; or text == &amp;quot;#&amp;quot; then&lt;br /&gt;
			guiSetText(keypadLabelDisplay,guiGetText(keypadLabelDisplay) .. text)&lt;br /&gt;
		-- otherwise replace the display with the new text&lt;br /&gt;
		else&lt;br /&gt;
			guiSetText(keypadLabelDisplay,text)&lt;br /&gt;
		end	&lt;br /&gt;
	-- if we pass nil, clear the display entirely&lt;br /&gt;
	else&lt;br /&gt;
		guiSetText(keypadLabelDisplay,&amp;quot;&amp;quot;)&lt;br /&gt;
	end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
We can now simply call updateDisplay(our text) to change the text on the display, or updateDisplay(nil) to clear it.&lt;br /&gt;
&lt;br /&gt;
===Detecting the clicks===&lt;br /&gt;
With so many buttons that do very similar tasks on our keypad, there are two methods available to us for detecting when a player clicks on them.&lt;br /&gt;
&lt;br /&gt;
We could add [[onClientGUIClick]] events for every button individually, as we have done in previous tutorials; Or, alternatively, &lt;br /&gt;
we could add a single [[onClientGUIClick]] handle for the window (which is the parent of all our other keypad GUI elements), filter our results to include only the buttons we want and trigger our own custom event.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
For the purposes of this tutorial and in the interest of outlining multiple approaches, we will explore the second method, though either one is an acceptable solution.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
addEventHandler(&amp;quot;onClientGUIClick&amp;quot;,keypadWindow,processKeypadClicks,true)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
'''Notice the final argument is set to 'true'. This means that clicks on any other elements in the same branch of the tree will also trigger this event handle (eg. clicks on our buttons).'''&lt;br /&gt;
&lt;br /&gt;
Add this line of code into your createKeypad function, after your GUI has been created.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Now that we are detecting all clicks on our GUI, we need to filter out the ones we do not want (ie: clicks on the window or display) and trigger our custom event:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
function processKeypadClicks(button,state)&lt;br /&gt;
	if button == &amp;quot;left&amp;quot; and state == &amp;quot;up&amp;quot; then&lt;br /&gt;
		-- if the source of this event is a gui button&lt;br /&gt;
		if getElementType(source) == &amp;quot;gui-button&amp;quot; then&lt;br /&gt;
			-- trigger our custom event and send the keypad id of this keypad as an argument&lt;br /&gt;
			triggerEvent(&amp;quot;onKeypadButtonClicked&amp;quot;,source,getElementData(keypadWindow,&amp;quot;keypadID&amp;quot;))&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
As you can see, we are now triggering our custom event &amp;quot;onKeypadButtonClicked&amp;quot; whenever a button is clicked on the keypad.&lt;br /&gt;
Also note we use element data &amp;quot;keypadID&amp;quot; to differentiate between keypads. This data will need to be set whenever the player is shown a new keypad.&lt;br /&gt;
We will cover this in more detail later.&lt;br /&gt;
&lt;br /&gt;
===Handling the clicks===&lt;br /&gt;
Much like when using [[triggerServerEvent]] in previous tutorials, we now need to define the event, only this time it is purely clientside:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
addEvent(&amp;quot;onKeypadButtonClicked&amp;quot;,false)&lt;br /&gt;
addEventHandler(&amp;quot;onKeypadButtonClicked&amp;quot;,root,&lt;br /&gt;
	function(keypadID)&lt;br /&gt;
&lt;br /&gt;
	end&lt;br /&gt;
)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Note the second argument in [[addEvent]] is set to false, indicating that this event cannot be triggered from the server.&lt;br /&gt;
Also note, the function we are using in the [[addEventHandler]] does not have a name. If you contract it down and remove the spacing, you get:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
addEventHandler(&amp;quot;onKeypadButtonClicked&amp;quot;,root,function() ... end)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
This simply means instead of storing the pointer to the function in a variable, we are passing it directly as an argument.&lt;br /&gt;
Doing it this way cleans up the code and will often make it easier to follow.&lt;br /&gt;
&lt;br /&gt;
Now that the event has been created, we can fill in the code logic that will control our button presses.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
addEvent(&amp;quot;onKeypadButtonClicked&amp;quot;,false)&lt;br /&gt;
addEventHandler(&amp;quot;onKeypadButtonClicked&amp;quot;,root,&lt;br /&gt;
	function(keypadID)&lt;br /&gt;
		-- clear the display if this is the first time its being used&lt;br /&gt;
		if guiGetText(keypadLabelDisplay) == &amp;quot;Enter Keycode.&amp;quot; or guiGetText(keypadLabelDisplay) == &amp;quot;Invalid Keycode.&amp;quot; then&lt;br /&gt;
			updateDisplay()&lt;br /&gt;
		end&lt;br /&gt;
	&lt;br /&gt;
	&lt;br /&gt;
		-- if its the clear button&lt;br /&gt;
		if guiGetText(source) == &amp;quot;Clear&amp;quot; then&lt;br /&gt;
			-- clear the display&lt;br /&gt;
			updateDisplay()&lt;br /&gt;
		&lt;br /&gt;
		-- if its the enter button&lt;br /&gt;
		elseif guiGetText(source) == &amp;quot;Enter&amp;quot; then&lt;br /&gt;
			-- get the currently entered code from the display&lt;br /&gt;
			local code = guiGetText(keypadLabelDisplay)&lt;br /&gt;
			&lt;br /&gt;
			-- if they have entered a code&lt;br /&gt;
			if code then&lt;br /&gt;
				-- trigger the server so we can verify their code&lt;br /&gt;
				triggerServerEvent(&amp;quot;verifyKeypadCode&amp;quot;,getLocalPlayer(),code,keypadID)&lt;br /&gt;
			end&lt;br /&gt;
		&lt;br /&gt;
		-- if its the exit button&lt;br /&gt;
		elseif guiGetText(source) == &amp;quot;Exit&amp;quot; then&lt;br /&gt;
			-- hide the keypad and reset the display text ready for next time&lt;br /&gt;
			guiSetVisible(keypadWindow,false)&lt;br /&gt;
			updateDisplay(&amp;quot;Enter Keycode.&amp;quot;)&lt;br /&gt;
			showCursor(false,false)&lt;br /&gt;
			&lt;br /&gt;
		-- otherwise, it must be a character button&lt;br /&gt;
		else&lt;br /&gt;
			updateDisplay(guiGetText(source))	&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Serverside Verification==&lt;br /&gt;
For this part of the tutorial, you will need to open up a serverside lua file from your resource to work with.&lt;br /&gt;
&lt;br /&gt;
===Defining the keycode===&lt;br /&gt;
Now that we have completed the keypad clicking logic, we need to move on to verifying the code entered into the keypad.&lt;br /&gt;
To do this, we need to have the correct code stored somewhere on the server, which we can check the players code against.&lt;br /&gt;
&lt;br /&gt;
For the purposes of this tutorial we will simply store the code in a serverside table, however it can be done any number of ways (such as serverside xml files or MySQL databases).&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
local keypadCodes = {&lt;br /&gt;
	[&amp;quot;a51MainGateKeypadCode&amp;quot;] = &amp;quot;4455*#&amp;quot;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
This table stores an entry called &amp;quot;a51MainGateKeypadCode&amp;quot; with the code 4455*#&lt;br /&gt;
&lt;br /&gt;
'''This is the keycode that you will use to open the gate later on in this tutorial.'''&lt;br /&gt;
&lt;br /&gt;
===Verifying the code===&lt;br /&gt;
Now that we have a keycode to verify against, we can write our serverside event:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
addEvent(&amp;quot;verifyKeypadCode&amp;quot;,true)&lt;br /&gt;
addEventHandler(&amp;quot;verifyKeypadCode&amp;quot;,root,function(code,keypadID)&lt;br /&gt;
	if code then&lt;br /&gt;
		-- using the table we created earlier, check if the code supplied is the same as the code for this gate&lt;br /&gt;
		if code == keypadCodes[keypadID] then&lt;br /&gt;
			-- if it is, tell the client that it was successful&lt;br /&gt;
			triggerClientEvent(client,&amp;quot;onKeypadVerificationSuccessful&amp;quot;,client,keypadID)&lt;br /&gt;
		else&lt;br /&gt;
			-- if it is not, tell the client that it was not successful&lt;br /&gt;
			triggerClientEvent(client,&amp;quot;onKeypadVerificationFailed&amp;quot;,client,keypadID)&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
end)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Here we use our table and the keypadID supplied by the player to check if the codes match.&lt;br /&gt;
&lt;br /&gt;
If you are not using a table to store the codes, then you will need to replace 'keypadCodes[keypadID]' with your own storage method.&lt;br /&gt;
Once it is verified (or not), we can trigger the client so the appropriate information can be shown on the keypad display.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Receiving the result==&lt;br /&gt;
We have now finished the serverside section of the tutorial, so you will need to open up the clientside lua file from your resource &lt;br /&gt;
that you were previously working on.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Once our code has been verified, the server will send back the response to the client.&lt;br /&gt;
In just the same way as client -&amp;gt; server interaction, we now need to add the event that the server is going to trigger on the client.&lt;br /&gt;
&lt;br /&gt;
===Catching and processing the result===&lt;br /&gt;
First we will add the event for when the verification is successful:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
addEvent(&amp;quot;onKeypadVerificationSuccessful&amp;quot;,true)&lt;br /&gt;
addEventHandler(&amp;quot;onKeypadVerificationSuccessful&amp;quot;,root,&lt;br /&gt;
	function()&lt;br /&gt;
		-- hide the keypad and reset the display text ready for next time&lt;br /&gt;
		guiSetVisible(keypadWindow,false)&lt;br /&gt;
		updateDisplay(&amp;quot;Enter Keycode.&amp;quot;)&lt;br /&gt;
		showCursor(false,false)&lt;br /&gt;
	end&lt;br /&gt;
)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Finally we can add the event for when the verification is unsuccessful:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
addEvent(&amp;quot;onKeypadVerificationFailed&amp;quot;,true)&lt;br /&gt;
addEventHandler(&amp;quot;onKeypadVerificationFailed&amp;quot;,root,&lt;br /&gt;
	function()&lt;br /&gt;
		-- update the display text to show the code was invalid&lt;br /&gt;
		updateDisplay(&amp;quot;Invalid Keycode.&amp;quot;)&lt;br /&gt;
	end&lt;br /&gt;
)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This completes the keypad section of the tutorial.&lt;br /&gt;
&lt;br /&gt;
For an example of how to implement this into a working gate system, carry on reading the next section.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Applying the Keypad==&lt;br /&gt;
For the keypad to have any use, we need something to use it on.&lt;br /&gt;
For this tutorial we will be using gates, and as mentioned earlier we will create a main gate into A51.&lt;br /&gt;
&lt;br /&gt;
===Creating the gate===&lt;br /&gt;
First of all, we need to create the gate object.&lt;br /&gt;
For the purposes of this example, we will be using a map file to store the object. &lt;br /&gt;
While this is the recommended method for defining objects, it is not the only way to approach it.&lt;br /&gt;
&lt;br /&gt;
Navigate to your resource folder and make a new file called gate.map, then add your new map file to your meta.xml using:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;map src=&amp;quot;gate.map&amp;quot;/&amp;gt;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
''If you are unsure of map file syntax, please see the [[Writing_Gamemodes| Writing Gamemodes Tutorial]] or check the [[Object]] page for help.''&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;map&amp;gt;&lt;br /&gt;
    &amp;lt;object id=&amp;quot;a51MainGateKeypadCode&amp;quot; model=&amp;quot;971&amp;quot; posX=&amp;quot;96.736&amp;quot; posY=&amp;quot;1918.352&amp;quot; posZ=&amp;quot;20.694&amp;quot; rotX=&amp;quot;0&amp;quot; rotY=&amp;quot;0&amp;quot; rotZ=&amp;quot;270.40&amp;quot; newPosX=&amp;quot;96.751&amp;quot; newPosY=&amp;quot;1914.474&amp;quot; newPosZ=&amp;quot;20.694&amp;quot; /&amp;gt;&lt;br /&gt;
&amp;lt;/map&amp;gt;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
This will create a gate object across the A51 entrance. The object will have position and rotation data, as well as its newPosX,newPosY and newPosZ information that we need to be able to move it.&lt;br /&gt;
&lt;br /&gt;
'''Note that the object id is the same as the table entry we created earlier to hold the access code.'''&lt;br /&gt;
This is one possible method that could be accessed to link this gate with that particular keycode.&lt;br /&gt;
&lt;br /&gt;
===Opening the keypad===&lt;br /&gt;
Back in the clientside lua file again, we can now work on linking the gate and the keypad.&lt;br /&gt;
&lt;br /&gt;
Now that we have our gate, we need a way of accessing the keypad to open it.&lt;br /&gt;
For the purposes of this tutorial we will use a simple command, however you could just as easily use a colshape or button press.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
addCommandHandler(&amp;quot;a51gate&amp;quot;,function()&lt;br /&gt;
	guiSetVisible(keypadWindow,true)&lt;br /&gt;
	showCursor(true,true)&lt;br /&gt;
	setElementData(keypadWindow,&amp;quot;keypadID&amp;quot;,&amp;quot;a51MainGateKeypadCode&amp;quot;)&lt;br /&gt;
end)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Note that we set the element data &amp;quot;keypadID&amp;quot;.&lt;br /&gt;
This is very important because it allows us to keep track of which gate we are trying to open (in this case, the &amp;quot;a51MainGateKeypadCode&amp;quot; gate).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Opening the gate===&lt;br /&gt;
With our gate created and our keypad ready, all thats left now is to open the gate.&lt;br /&gt;
Having created custom events earlier for successfully and unsuccessfully verifying the code, this now becomes very easy to do.&lt;br /&gt;
All we do is add an event handler for our custom &amp;quot;success&amp;quot; event, and using the keypadID we defined earlier we can move the gate inside it:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
addEventHandler(&amp;quot;onKeypadVerificationSuccessful&amp;quot;,root,&lt;br /&gt;
	-- keypadID is sent back from the server&lt;br /&gt;
	function(keypadID)&lt;br /&gt;
		-- get the gate object (this is where the id=&amp;quot;a51MainGateKeypadCode&amp;quot; tag in the map file becomes useful)&lt;br /&gt;
		local gate = getElementByID(keypadID)&lt;br /&gt;
&lt;br /&gt;
		-- if we found the object&lt;br /&gt;
		if gate then&lt;br /&gt;
			-- get the new position (as we defined in the map file)&lt;br /&gt;
			local x = tonumber(getElementData(gate,&amp;quot;newPosX&amp;quot;))&lt;br /&gt;
			local y = tonumber(getElementData(gate,&amp;quot;newPosY&amp;quot;))&lt;br /&gt;
			local z = tonumber(getElementData(gate,&amp;quot;newPosZ&amp;quot;))&lt;br /&gt;
&lt;br /&gt;
			-- move the gate&lt;br /&gt;
			moveObject(gate,1500,x,y,z)&lt;br /&gt;
			&lt;br /&gt;
			-- get the original position&lt;br /&gt;
			x = tonumber(getElementData(gate,&amp;quot;posX&amp;quot;))&lt;br /&gt;
			y = tonumber(getElementData(gate,&amp;quot;posY&amp;quot;))&lt;br /&gt;
			z = tonumber(getElementData(gate,&amp;quot;posZ&amp;quot;))	&lt;br /&gt;
			&lt;br /&gt;
			-- set a timer to close the gate in 5 seconds&lt;br /&gt;
			setTimer(moveObject,5000,1,gate,1500,x,y,z)&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Note how by using the keypadID sent back from the server, we can use if statements and checks against the id to control any number of gates from the same function.&lt;br /&gt;
&lt;br /&gt;
You should now have a working example of a GUI Keypad controlling an A51 Gate.&lt;br /&gt;
&lt;br /&gt;
For further GUI tutorials, see [[Scripting the GUI - Tutorial 3|Tutorial 3 (Scrolling News Feed)]]&lt;/div&gt;</summary>
		<author><name>R3mp</name></author>
	</entry>
	<entry>
		<id>https://wiki.multitheftauto.com/index.php?title=Scripting_the_GUI_-_Tutorial_3&amp;diff=22184</id>
		<title>Scripting the GUI - Tutorial 3</title>
		<link rel="alternate" type="text/html" href="https://wiki.multitheftauto.com/index.php?title=Scripting_the_GUI_-_Tutorial_3&amp;diff=22184"/>
		<updated>2010-01-05T21:14:10Z</updated>

		<summary type="html">&lt;p&gt;R3mp: Created page with ''''Scripting the GUI - Tutorial 3 (Scrolling News GUI)'''  In this tutorial we will explore how to create a simple scrolling news feed GUI,  allowing you to quickly and easily sh…'&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;'''Scripting the GUI - Tutorial 3 (Scrolling News GUI)'''&lt;br /&gt;
&lt;br /&gt;
In this tutorial we will explore how to create a simple scrolling news feed GUI, &lt;br /&gt;
allowing you to quickly and easily show server updates and other server information to your players.&lt;br /&gt;
We will store all news items in a clientside xml file and use some simple xml reading to load them into the game.&lt;br /&gt;
&lt;br /&gt;
We will then animate the news item to scroll along the bottom of the screen, updating the news text once it has scrolled beyond the edge of the screen.&lt;br /&gt;
&lt;br /&gt;
'''Note that this tutorial assumes you are familiar with all the content covered in the [[Introduction to Scripting GUI|GUI Scripting Introduction]].'''&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Setting up the News Feed==&lt;br /&gt;
To begin, open up a clientside lua file (if you have been following the [[Introduction to Scripting GUI|GUI Scripting Introduction]], this is gui.lua) to work with.&lt;br /&gt;
&lt;br /&gt;
===Creating the GUI===&lt;br /&gt;
As with the previous tutorial, you should be suitably familiar with GUI creation already so we will not go into too much detail here. &lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
function createNewsFeed()&lt;br /&gt;
	-- get the screen width and height&lt;br /&gt;
	local sWidth, sHeight = guiGetScreenSize()&lt;br /&gt;
 &lt;br /&gt;
	-- create the gridlist, using some maths to find the bottom-centre of the screen&lt;br /&gt;
	local Width,Height = 800,45&lt;br /&gt;
	local X = (sWidth/2) - (Width/2)&lt;br /&gt;
	local Y = sHeight - (Height/2)&lt;br /&gt;
	&lt;br /&gt;
	-- the gridlist will act as the background to our news reel&lt;br /&gt;
	newsGridlist = guiCreateGridList(X,Y,Width,Height,false)&lt;br /&gt;
	&lt;br /&gt;
	-- create the label in the same place, but as a child of the gridlist&lt;br /&gt;
	-- also make it half the height of the gridlist, as half of the gridlist is off the bottom of the screen&lt;br /&gt;
	newsLabel = guiCreateLabel(X,Y,Width,Height/2,&amp;quot;Test text&amp;quot;,false,newsGridlist)&lt;br /&gt;
	&lt;br /&gt;
	-- call our function to read the news out of the xml file&lt;br /&gt;
	loadNews()&lt;br /&gt;
	&lt;br /&gt;
	-- load the first news item in the table&lt;br /&gt;
	updateNewsItem(1)&lt;br /&gt;
	&lt;br /&gt;
	-- define a global variable called 'currentItem' with the value 1&lt;br /&gt;
	currentItem = 1&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
addEventHandler(&amp;quot;onClientResourceStart&amp;quot;,resourceRoot,createNewsFeed)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Note that the label is created as a child of the gridlist. &lt;br /&gt;
Not only is this good practice in general, but it means that we can freely move parts of the label beyond the edge of the gridlist without them showing, which is critical to the visual effect of this tutorial.&lt;br /&gt;
&lt;br /&gt;
Also notice the use of the 'resourceRoot' variable. This is an MTA variable that holds the root value of the resource you are using it in.&lt;br /&gt;
&lt;br /&gt;
The 'currentItem' variable is what we will use to keep track of which news item we are currently showing&lt;br /&gt;
&lt;br /&gt;
===Writing the News===&lt;br /&gt;
Now that we have our GUI created, we need some news to fill it with.&lt;br /&gt;
To do this, we will read our news items out of a clientside xml file.&lt;br /&gt;
&lt;br /&gt;
So, navigate to your resource directory and create a new xml file called newsfeed.xml (don't forget to add it to your meta.xml with the appropriate client tag).&lt;br /&gt;
&lt;br /&gt;
Inside this file enter the following information:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;root&amp;gt;&lt;br /&gt;
	&amp;lt;news&amp;gt;This is an example news item.&amp;lt;/news&amp;gt;&lt;br /&gt;
	&amp;lt;news&amp;gt;From the 'Scripting the GUI' tutorial.&amp;lt;/news&amp;gt;&lt;br /&gt;
	&amp;lt;news&amp;gt;Showing scrolling news text.&amp;lt;/news&amp;gt;&lt;br /&gt;
	&amp;lt;news&amp;gt;Written on a GUI news feed.&amp;lt;/news&amp;gt;&lt;br /&gt;
&amp;lt;/root&amp;gt;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
As you can see, each news item is defined as a &amp;lt;news&amp;gt; node with the value being the news text you want to display.&lt;br /&gt;
There is no limit on how many news items you can add.&lt;br /&gt;
&lt;br /&gt;
===Collecting the News===&lt;br /&gt;
Once we have written all our news items, we will need to collect them all and store them in a table on the client.&lt;br /&gt;
We will do this when the resource starts, saving us from having to repeatedly access the xml for new news items.&lt;br /&gt;
&lt;br /&gt;
First, we need to define a table to store the items in:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
local newsItems = {}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Add this line to the top of your script.&lt;br /&gt;
Make sure it is not inside a function otherwise it will not exist outside of that function (as denoted by the prefix &amp;quot;local&amp;quot;).&lt;br /&gt;
When defined in the main body of the script it will exist in all functions.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Next, we will need to load the xml file:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
function loadNews()&lt;br /&gt;
	-- load our &amp;quot;newsfeed.xml&amp;quot; file&lt;br /&gt;
	local newsfile = xmlLoadFile(&amp;quot;newsfeed.xml&amp;quot;)&lt;br /&gt;
	&lt;br /&gt;
	-- if it was successfully loaded&lt;br /&gt;
	if newsfile then&lt;br /&gt;
	&lt;br /&gt;
		-- always remember to unload files once you are finished&lt;br /&gt;
		xmlUnloadFile(newsfile)&lt;br /&gt;
	end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
'''Always remember to unload files once you are finished using them.'''&lt;br /&gt;
&lt;br /&gt;
Finally, we can add some more code to our loadNews function to read the news items into our newsItems table:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
function loadNews()&lt;br /&gt;
	local newsfile = xmlLoadFile(&amp;quot;newsfeed.xml&amp;quot;)&lt;br /&gt;
	&lt;br /&gt;
	if newsfile then&lt;br /&gt;
		-- loop through all the children of the root node (the &amp;quot;news&amp;quot; nodes)&lt;br /&gt;
		for index,itemNode in ipairs(xmlNodeGetChildren(newsfile)) do&lt;br /&gt;
			-- get the text (the news item) from the node&lt;br /&gt;
			local item = xmlNodeGetValue(itemNode)&lt;br /&gt;
			&lt;br /&gt;
			-- insert it into our newsItems table&lt;br /&gt;
			table.insert(newsItems,item)&lt;br /&gt;
		end&lt;br /&gt;
	&lt;br /&gt;
		xmlUnloadFile(newsfile)&lt;br /&gt;
	end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
We now have a table called 'newsItems' holding all of our news text from the xml file.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Updating the News==&lt;br /&gt;
Now that we have our GUI created and our news items ready, we need to write some code to update the news item being shown to players.&lt;br /&gt;
As stated earlier, our news items will be shown on our 'newsLabel' GUI label.&lt;br /&gt;
&lt;br /&gt;
To do this, we will write a simple function to get the next news item from our 'newsItems' table and display it in our label.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
-- define our function with a newIndex parameter, so that we can pass which news item we want to show&lt;br /&gt;
function updateNewsItem(newIndex)&lt;br /&gt;
	-- get the new news item from the table&lt;br /&gt;
	local item = newsItems[newIndex]&lt;br /&gt;
	&lt;br /&gt;
	-- update the label text&lt;br /&gt;
	guiSetText(newsLabel,item)&lt;br /&gt;
	&lt;br /&gt;
	-- update the 'currentItem' global variable&lt;br /&gt;
	currentItem = newIndex&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Sizing the Label===&lt;br /&gt;
To make our news scrolling as accurate as possible, we need to be able to make the GUI label the same size as the news item text it is showing.&lt;br /&gt;
&lt;br /&gt;
While this may seem like a tricky thing to do, it is made very easy with the function [[guiLabelGetTextExtent]].&lt;br /&gt;
This will tell us the extent, or width, of the text currently shown in our label.&lt;br /&gt;
So with a few modifications to our 'updateNewsItems' function, we get:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
function updateNewsItem(newIndex)&lt;br /&gt;
	local item = newsItems[newIndex]&lt;br /&gt;
	&lt;br /&gt;
	guiSetText(newsLabel,item)&lt;br /&gt;
	&lt;br /&gt;
	currentItem = newIndex&lt;br /&gt;
	&lt;br /&gt;
	-- get the current dimensions of the gui label&lt;br /&gt;
	local width,height = guiGetSize(newsLabel,false)&lt;br /&gt;
	&lt;br /&gt;
	-- get the text width of the label&lt;br /&gt;
	local extent = guiLabelGetTextExtent(newsLabel)&lt;br /&gt;
	&lt;br /&gt;
	-- update the size of the label with the new width (we do not change the height)&lt;br /&gt;
	guiSetSize(newsLabel,extent,height,false)&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Positioning the Label===&lt;br /&gt;
Now that our GUI label is the correct width, we need to move it to a position where it is ready to scroll onto the screen.&lt;br /&gt;
&lt;br /&gt;
Again, we can do this with a small modification to our 'updateNewsItems' function:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
function updateNewsItem(newIndex)&lt;br /&gt;
	local item = newsItems[newIndex]&lt;br /&gt;
	&lt;br /&gt;
	guiSetText(newsLabel,item)&lt;br /&gt;
	&lt;br /&gt;
	currentItem = newIndex&lt;br /&gt;
	&lt;br /&gt;
	local width,height = guiGetSize(newsLabel,false)&lt;br /&gt;
	&lt;br /&gt;
	local extent = guiLabelGetTextExtent(newsLabel)&lt;br /&gt;
	&lt;br /&gt;
	guiSetSize(newsLabel,extent,height,false)&lt;br /&gt;
	&lt;br /&gt;
	-- set the positon to the far right side of the gridlist, ready to scroll on to the left&lt;br /&gt;
	guiSetPosition(newsLabel,1,0,true)&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Scrolling the News==&lt;br /&gt;
The next step is to animate our news feed.&lt;br /&gt;
&lt;br /&gt;
===Looking at Frames===&lt;br /&gt;
To do this, we will introduce a new event: [[onClientRender]].&lt;br /&gt;
As stated on the [[onClientRender]] wiki page, this event is called every time GTA renders a new frame (ie: very often).&lt;br /&gt;
&lt;br /&gt;
As usual, to use this event we will need to create an event handler for it:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
addEventHandler(&amp;quot;onClientRender&amp;quot;,root,scrollNews)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
This will call our scrollNews function every frame, which we will then use to update the position of our news item.&lt;br /&gt;
&lt;br /&gt;
'''Make sure you add this handler after you have defined your scrollNews function.'''&lt;br /&gt;
&lt;br /&gt;
For our purposes, [[onClientRender]] has one main advantage over, for example, [[setTimer]].&lt;br /&gt;
As it is called every frame (and therefore is dependant on the players FPS), the movement of the news item will always appear to be completely smooth,&lt;br /&gt;
unlike using a timer which would often appear to lag.&lt;br /&gt;
&lt;br /&gt;
===Moving the News===&lt;br /&gt;
In our 'updateNewsItem' function, we position the 'newsLabel' to the far right, so we will scroll in from the right to the left.&lt;br /&gt;
&lt;br /&gt;
For this we will simply move the X position by -1 every frame:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
function scrollNews()&lt;br /&gt;
	-- if the newsLabel exists&lt;br /&gt;
	if newsLabel then&lt;br /&gt;
		-- get the current position of the label&lt;br /&gt;
		local x,y = guiGetPosition(newsLabel,false)&lt;br /&gt;
		&lt;br /&gt;
		-- set the new x position of the label as the old position -1&lt;br /&gt;
		guiSetPosition(newsLabel,x-1,y,false)&lt;br /&gt;
	end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Looping around===&lt;br /&gt;
Now that our news scrolls across the screen, we need to be able to check when it has scrolled too far to the left&lt;br /&gt;
so we can start scrolling from the far-right side again.&lt;br /&gt;
&lt;br /&gt;
We will also need to update the news item, so we should check the next item exists, and if it doesn't, go back to the first.&lt;br /&gt;
&lt;br /&gt;
For this we will use some simple maths in a modification to our 'scrollNews' function:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
function scrollNews()&lt;br /&gt;
	local x,y = guiGetPosition(newsLabel,false)&lt;br /&gt;
	&lt;br /&gt;
	local labelWidth, labelHeight = guiGetSize(newsLabel,false)&lt;br /&gt;
	&lt;br /&gt;
	-- if the far right position of the label (x + labelWidth) is greater than or equal to 0 (ie: still showing on the gridlist)&lt;br /&gt;
	if ((x-1) + labelWidth) &amp;gt;= 0 then&lt;br /&gt;
		-- compensate for a small off-by-one bug in MTA&lt;br /&gt;
		if x &amp;lt;= 0 then x = x - 1 end&lt;br /&gt;
		&lt;br /&gt;
		-- update the position as normal&lt;br /&gt;
		guiSetPosition(newsLabel,x-1,y,false)&lt;br /&gt;
		&lt;br /&gt;
	-- otherwise, we move on to the next item and reset the position&lt;br /&gt;
	else&lt;br /&gt;
		-- get the total number of items in the 'newsItems' table&lt;br /&gt;
		local totalItems = #newsItems&lt;br /&gt;
		&lt;br /&gt;
		-- if the next item on our list does not exist in our table&lt;br /&gt;
		if (currentItem + 1) &amp;gt; totalItems then&lt;br /&gt;
			-- loop back to the first item in the list&lt;br /&gt;
			updateNewsItem(1)&lt;br /&gt;
		else&lt;br /&gt;
			-- otherwise move onto the next item in the list&lt;br /&gt;
			updateNewsItem(currentItem + 1)&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Notice the use of the '#' symbol to get the size of the 'newsItems' table. &lt;br /&gt;
This is the Lua length operator, but it only works on tables that have numerical indexes (like an array or a list).&lt;br /&gt;
It also works on strings, eg: #&amp;quot;hello&amp;quot; would return 5.&lt;br /&gt;
&lt;br /&gt;
That completes this section of the tutorial.&lt;br /&gt;
For ideas on how to further improve and advance this code, continue reading the next section.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Improving the code==&lt;br /&gt;
This section will detail several ways to improve upon the code you now have.&lt;br /&gt;
&lt;br /&gt;
===GUI Customisation===&lt;br /&gt;
To give your GUI a more unique feel, you have the ability to customise some aspects of your GUI elements.&lt;br /&gt;
&lt;br /&gt;
For ideas on what is possible, browse the [[Client_Scripting_Functions#GUI_functions|MTA GUI functions]].&lt;br /&gt;
&lt;br /&gt;
For the purposes of this tutorial, we will be using Font, Colour and Alpha.&lt;br /&gt;
&lt;br /&gt;
To start, we will change the alpha of the background gridlist GUI element we are using.&lt;br /&gt;
To set the alpha, use [[guiSetAlpha]] and pass a value between 1 and 0; 1 being fully opaque and 0 being fully transparent.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
guiSetAlpha(newsGridlist,0.8)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Place this line of code in your 'createNewsFeed' function, after your gridlist has been created.&lt;br /&gt;
&lt;br /&gt;
I find an alpha level of 0.8 looks best, however this is personal preference and you can experiment to suit your needs.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Next, we will look at the font of the label text.&lt;br /&gt;
To set the font, use [[guiSetFont]] and pass the string name of the font you want to use (available to see on the [[GUI Fonts]] page).&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
guiSetFont(newsLabel,&amp;quot;default-bold-small&amp;quot;)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Place this line of code in your 'createNewsFeed' function, after your label has been created.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Finally, we will look at setting the colour of the label text.&lt;br /&gt;
To set the colour, use [[guiLabelSetColor]] and pass the individual red,green and blue values.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
guiLabelSetColor(newsLabel,255,70,0)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Place this line of code in your 'createNewsFeed' function, after your label has been created.&lt;br /&gt;
&lt;br /&gt;
This will give your news items an orange-red colour.&lt;br /&gt;
&lt;br /&gt;
===Multiple News Items===&lt;br /&gt;
In its current form, this code is only capable of showing one news item at a time.&lt;br /&gt;
However, with a few modifications we can show multiple news items at once, one after another.&lt;br /&gt;
&lt;br /&gt;
To begin with, we need to make sure we have a 'newItems' table defined at the very start of our script,&lt;br /&gt;
as well as a 'distance' variable that will control the pixel distance between each news item:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
local newsItems = {}&lt;br /&gt;
local distance = 30&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
So put these lines at the top of the file.&lt;br /&gt;
&lt;br /&gt;
Next, we will not know how many items we have (and consequently, how many labels we need) until we have loaded the file.&lt;br /&gt;
With that in mind, we will move around some of the code in our 'createNewsFeed' function to support this:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
function createNewsFeed()&lt;br /&gt;
	-- get the screen width and height&lt;br /&gt;
	local sWidth, sHeight = guiGetScreenSize()&lt;br /&gt;
 &lt;br /&gt;
	-- create the gridlist, using some maths to find the bottom-centre of the screen&lt;br /&gt;
	local Width,Height = 800,45&lt;br /&gt;
	local X = (sWidth/2) - (Width/2)&lt;br /&gt;
	local Y = sHeight - (Height/2)&lt;br /&gt;
	&lt;br /&gt;
	-- the gridlist will act as the background to our news reel&lt;br /&gt;
	newsGridlist = guiCreateGridList(X,Y,Width,Height,false)&lt;br /&gt;
	&lt;br /&gt;
	guiSetAlpha(newsGridlist,0.8)&lt;br /&gt;
	&lt;br /&gt;
	-- call our function to read the news out of the xml file, before we create the labels&lt;br /&gt;
	loadNews()&lt;br /&gt;
		&lt;br /&gt;
	-- define a table to hold our labels&lt;br /&gt;
	newsLabel = {}&lt;br /&gt;
	&lt;br /&gt;
	-- now we can loop all our news items, and create a label for each one&lt;br /&gt;
	for index,item in ipairs(newsItems) do&lt;br /&gt;
	&lt;br /&gt;
		-- because we now have one label for every item, we can just set the text here and it wont need to be changed again.&lt;br /&gt;
		newsLabel[index] = guiCreateLabel(0,0,Width,Height/2,item,false,newsGridlist)&lt;br /&gt;
		&lt;br /&gt;
		guiSetFont(newsLabel[index],&amp;quot;default-bold-small&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
		guiLabelSetColor(newsLabel[index],255,70,0)		&lt;br /&gt;
&lt;br /&gt;
		-- modify the width of the label to fit the text&lt;br /&gt;
		local extent = guiLabelGetTextExtent(newsLabel[index])		&lt;br /&gt;
		guiSetSize(newsLabel[index],extent,Height/2,false)&lt;br /&gt;
		&lt;br /&gt;
		&lt;br /&gt;
		-- get the size of the gridlist&lt;br /&gt;
		local x,y = guiGetSize(newsGridlist,false)&lt;br /&gt;
		&lt;br /&gt;
		-- loop from 1 until index-1 in steps of 1&lt;br /&gt;
		-- this allows us to loop every label before the label we are currently on&lt;br /&gt;
		for i=1, index-1, 1 do&lt;br /&gt;
			-- tally up the sizes of all labels before our current one and store them in x&lt;br /&gt;
			local width = guiGetSize(newsLabel[i],false)&lt;br /&gt;
			x = x + width&lt;br /&gt;
		end&lt;br /&gt;
		&lt;br /&gt;
		-- put a 'distance' pixel gap between each news item&lt;br /&gt;
		x = x + (distance*(index-1))&lt;br /&gt;
		&lt;br /&gt;
		-- set the positon to the far right side of the gridlist, ready to scroll on to the left&lt;br /&gt;
		guiSetPosition(newsLabel[index],x,0,false)	&lt;br /&gt;
	end	&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Now we need to update our 'updateNewsItem' function to account for having multiple labels:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
function updateNewsItem(newIndex)&lt;br /&gt;
	-- find the index of the news item directly infront (in the looping order) of the newIndex item&lt;br /&gt;
	local index = newIndex - 1&lt;br /&gt;
	if index == 0 then index = #newsItems end&lt;br /&gt;
	&lt;br /&gt;
	-- find the position of the right-edge of the label directly infront of the newIndex label&lt;br /&gt;
	local x = guiGetPosition(newsLabel[index],false) &lt;br /&gt;
	local width = guiGetSize(newsLabel[index],false)&lt;br /&gt;
	x = x + width&lt;br /&gt;
&lt;br /&gt;
	-- add a 'distance' pixel gap in&lt;br /&gt;
	x = x + distance&lt;br /&gt;
&lt;br /&gt;
	-- check the new position isnt actually on the gridlist (ie: so it wont suddenly appear in the centre of the list)&lt;br /&gt;
	local gridlistWidth = guiGetSize(newsGridlist,false)&lt;br /&gt;
	&lt;br /&gt;
	if x &amp;lt; gridlistWidth then&lt;br /&gt;
		-- if it is, simple move it back to the edge&lt;br /&gt;
		x = gridlistWidth&lt;br /&gt;
	end&lt;br /&gt;
	&lt;br /&gt;
	-- set the new position&lt;br /&gt;
	guiSetPosition(newsLabel[newIndex],x,0,false)&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Finally, we need to make some small adjustments to our 'scrollNews' function:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
function scrollNews()&lt;br /&gt;
	if newsItems then&lt;br /&gt;
		-- loop every news item&lt;br /&gt;
		for index,item in ipairs(newsItems) do&lt;br /&gt;
			local x,y = guiGetPosition(newsLabel[index],false)&lt;br /&gt;
			&lt;br /&gt;
			local labelWidth, labelHeight = guiGetSize(newsLabel[index],false)&lt;br /&gt;
			&lt;br /&gt;
			-- if the far right position of the label (x + labelWidth) is greater than or equal to 0 (ie: still showing on the gridlist)&lt;br /&gt;
			if ((x-1) + labelWidth) &amp;gt;= 0 then&lt;br /&gt;
				-- compensate for a small off-by-one bug in MTA&lt;br /&gt;
				if x &amp;lt;= 0 then x = x - 1 end&lt;br /&gt;
			&lt;br /&gt;
				-- update the position as normal&lt;br /&gt;
				guiSetPosition(newsLabel[index],x-1,y,false)&lt;br /&gt;
				&lt;br /&gt;
			-- otherwise, we move on to the next item and reset the position&lt;br /&gt;
			else&lt;br /&gt;
				updateNewsItem(index)&lt;br /&gt;
			end&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
You should now have multiple news items scrolling along your news feed simultaneously.&lt;br /&gt;
&lt;br /&gt;
===Globally controlled scroll speed===&lt;br /&gt;
As with the 'distance' variable above, we can set a global variable for controlling the scroll speed of the news items as well.&lt;br /&gt;
Note that the speed will still be dependant on the players FPS (ie: lower FPS means slightly slower scrolling).&lt;br /&gt;
&lt;br /&gt;
To do this, we simply need to create the variable at the start of our code:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
local scrollSpeed = 1&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Put this line at the top of your file.&lt;br /&gt;
&lt;br /&gt;
Then, we just replace the instance of &amp;quot;x-1&amp;quot; in our 'scrollNews' function with &amp;quot;x-scrollSpeed&amp;quot;:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
function scrollNews()&lt;br /&gt;
		...&lt;br /&gt;
				-- update the position as normal&lt;br /&gt;
				guiSetPosition(newsLabel[index],x-scrollSpeed,y,false)&lt;br /&gt;
		...&lt;br /&gt;
	end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
That concludes this section of the tutorial.&lt;/div&gt;</summary>
		<author><name>R3mp</name></author>
	</entry>
	<entry>
		<id>https://wiki.multitheftauto.com/index.php?title=SetPlayerMuted&amp;diff=22178</id>
		<title>SetPlayerMuted</title>
		<link rel="alternate" type="text/html" href="https://wiki.multitheftauto.com/index.php?title=SetPlayerMuted&amp;diff=22178"/>
		<updated>2010-01-03T22:08:08Z</updated>

		<summary type="html">&lt;p&gt;R3mp: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;__NOTOC__&lt;br /&gt;
{{Server function}}&lt;br /&gt;
Use this function to mute or unmute the player.&lt;br /&gt;
&lt;br /&gt;
==Syntax==&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;bool setPlayerMuted ( player thePlayer, bool state )&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Required Arguments===&lt;br /&gt;
*'''thePlayer:''' The [[player]] you are muting or unmuting.&lt;br /&gt;
*'''state:''' Use '''true''' to mute and '''false''' to unmute the player.&lt;br /&gt;
&lt;br /&gt;
===Returns===&lt;br /&gt;
Returns ''true'' if the player was successfully muted or unmuted, ''false'' otherwise.&lt;br /&gt;
&lt;br /&gt;
==Example==&lt;br /&gt;
This adds a /mute command that can be used to mute a player.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
-- create the function&lt;br /&gt;
function mutePlayer(player,command,victimName)&lt;br /&gt;
	-- if the player has specified a victim name to mute&lt;br /&gt;
	if victimName then&lt;br /&gt;
		-- get the victim player element from their name&lt;br /&gt;
		local victim = getPlayerFromNick(victimName)&lt;br /&gt;
		-- if the player exists&lt;br /&gt;
		if victim then&lt;br /&gt;
			-- if they arent already muted&lt;br /&gt;
			if ( not isPlayerMuted(victim) ) then&lt;br /&gt;
				-- mute them and output a message to the chat&lt;br /&gt;
				setPlayerMuted(victim, true)&lt;br /&gt;
				outputChatBox(&amp;quot;You have been muted.&amp;quot;,victim)&lt;br /&gt;
			end&lt;br /&gt;
		else&lt;br /&gt;
			outputChatBox(&amp;quot;Could not find player with name: &amp;quot;..tostring(victimName),player)&lt;br /&gt;
		end&lt;br /&gt;
	else&lt;br /&gt;
		outputChatBox(&amp;quot;Usage: /mute &amp;lt;player name&amp;gt;&amp;quot;,player)&lt;br /&gt;
	end&lt;br /&gt;
end&lt;br /&gt;
-- add the /mute command&lt;br /&gt;
addCommandHandler(&amp;quot;mute&amp;quot;,mutePlayer)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==See Also==&lt;br /&gt;
{{Player functions}}&lt;/div&gt;</summary>
		<author><name>R3mp</name></author>
	</entry>
	<entry>
		<id>https://wiki.multitheftauto.com/index.php?title=Scripting_the_GUI_-_Tutorial_2&amp;diff=22163</id>
		<title>Scripting the GUI - Tutorial 2</title>
		<link rel="alternate" type="text/html" href="https://wiki.multitheftauto.com/index.php?title=Scripting_the_GUI_-_Tutorial_2&amp;diff=22163"/>
		<updated>2010-01-03T20:25:36Z</updated>

		<summary type="html">&lt;p&gt;R3mp: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;'''Scripting the GUI - Tutorial 2 (Gates + Keypads)'''&lt;br /&gt;
&lt;br /&gt;
In this tutorial we will look at creating GUI keypads with combination codes for map-defined object gates.&lt;br /&gt;
We will be using serverside keycodes, with some client - server interaction to verify the codes and report the outcome.&lt;br /&gt;
&lt;br /&gt;
'''Note that this tutorial assumes you are familiar with all the content covered in the [[Introduction to Scripting GUI|GUI Scripting Introduction]].'''&lt;br /&gt;
&lt;br /&gt;
[[Image:Gui_keypad_tutorial.png|thumb|GUI Keypad]]&lt;br /&gt;
&lt;br /&gt;
==Setting up the Keypad==&lt;br /&gt;
To begin, open up a clientside lua file (if you have been following the [[Introduction to Scripting GUI|GUI Scripting Introduction]], this is gui.lua) to work with.&lt;br /&gt;
&lt;br /&gt;
===Creating the GUI===&lt;br /&gt;
By now, GUI creation should seem relatively straight forward, so we will not go over this in too much detail.&lt;br /&gt;
As in [[Scripting the GUI - Tutorial 1|Tutorial 1]] we will be using '''absolute''' values in this tutorial.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
function createKeypad()&lt;br /&gt;
	-- get the screen width and height&lt;br /&gt;
	local sWidth, sHeight = guiGetScreenSize()&lt;br /&gt;
&lt;br /&gt;
	-- create the window, using some maths to find the centre of the screen&lt;br /&gt;
	local Width,Height = 142,276&lt;br /&gt;
	local X = (sWidth/2) - (Width/2)&lt;br /&gt;
	local Y = (sHeight/2) - (Height/2)&lt;br /&gt;
	keypadWindow = guiCreateWindow(X,Y,Width,Height,&amp;quot;Keypad&amp;quot;,false)&lt;br /&gt;
	&lt;br /&gt;
	-- don't allow people to resize the keypad&lt;br /&gt;
	guiWindowSetSizable(keypadWindow,false)&lt;br /&gt;
&lt;br /&gt;
	-- create buttons labeled 0-9, &amp;quot;*&amp;quot;, &amp;quot;#&amp;quot;, &amp;quot;Enter&amp;quot; and &amp;quot;C&amp;quot; (clear)&lt;br /&gt;
	keypadButton1 = guiCreateButton(13,68,37,36,&amp;quot;1&amp;quot;,false,keypadWindow)&lt;br /&gt;
	keypadButton2 = guiCreateButton(53,68,37,36,&amp;quot;2&amp;quot;,false,keypadWindow)&lt;br /&gt;
	keypadButton3 = guiCreateButton(93,68,37,36,&amp;quot;3&amp;quot;,false,keypadWindow)&lt;br /&gt;
	keypadButton4 = guiCreateButton(13,108,37,36,&amp;quot;4&amp;quot;,false,keypadWindow)&lt;br /&gt;
	keypadButton5 = guiCreateButton(53,108,37,36,&amp;quot;5&amp;quot;,false,keypadWindow)&lt;br /&gt;
	keypadButton6 = guiCreateButton(93,108,37,36,&amp;quot;6&amp;quot;,false,keypadWindow)&lt;br /&gt;
	keypadButton7 = guiCreateButton(13,148,37,36,&amp;quot;7&amp;quot;,false,keypadWindow)&lt;br /&gt;
	keypadButton8 = guiCreateButton(53,148,37,36,&amp;quot;8&amp;quot;,false,keypadWindow)&lt;br /&gt;
	keypadButton9 = guiCreateButton(93,148,37,36,&amp;quot;9&amp;quot;,false,keypadWindow)&lt;br /&gt;
	keypadButtonAsterix = guiCreateButton(13,188,37,36,&amp;quot;*&amp;quot;,false,keypadWindow)&lt;br /&gt;
	keypadButton0 = guiCreateButton(53,188,37,36,&amp;quot;0&amp;quot;,false,keypadWindow)&lt;br /&gt;
	keypadButtonHash = guiCreateButton(93,188,37,36,&amp;quot;#&amp;quot;,false,keypadWindow)&lt;br /&gt;
	keypadButtonExit = guiCreateButton(13,228,37,36,&amp;quot;Exit&amp;quot;,false,keypadWindow)&lt;br /&gt;
	keypadButtonEnter = guiCreateButton(53,228,37,36,&amp;quot;Enter&amp;quot;,false,keypadWindow)&lt;br /&gt;
	keypadButtonClear = guiCreateButton(93,228,37,36,&amp;quot;Clear&amp;quot;,false,keypadWindow)&lt;br /&gt;
&lt;br /&gt;
	-- create a gridlist to act as a backdrop on the kaypad display&lt;br /&gt;
	keypadGridlistDisplay = guiCreateGridList(13,25,117,33,false,keypadWindow)&lt;br /&gt;
	guiGridListSetSelectionMode(keypadGridlistDisplay,2)&lt;br /&gt;
	guiSetAlpha(keypadGridlistDisplay,0.6)&lt;br /&gt;
	-- create a label so we can write text on the keypad display&lt;br /&gt;
	keypadLabelDisplay = guiCreateLabel(14,26,115,30,&amp;quot;Enter Keycode.&amp;quot;,false,keypadWindow)&lt;br /&gt;
	guiLabelSetColor(keypadLabelDisplay,255,000,000)&lt;br /&gt;
	guiLabelSetVerticalAlign(keypadLabelDisplay,&amp;quot;center&amp;quot;)&lt;br /&gt;
	guiLabelSetHorizontalAlign(keypadLabelDisplay,&amp;quot;center&amp;quot;,false)&lt;br /&gt;
	&lt;br /&gt;
	guiSetVisible(keypadWindow,false)&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
-- create the GUI when the resource starts&lt;br /&gt;
addEventHandler(&amp;quot;onClientResourceStart&amp;quot;,getResourceRootElement(getThisResource()),createKeypad)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
As you can see, the keypad consists of 10 numerical keys (0-9), two character keys (* and #), a clear key, an exit key and an enter key.&lt;br /&gt;
This means the codes used on the keypad can contain any of these characters (0123456789*#).&lt;br /&gt;
&lt;br /&gt;
===Managing the display===&lt;br /&gt;
We will begin by writing a small function to control the display on the keypad.&lt;br /&gt;
This is done by encapsulating several methods of changing the text into a single function,&lt;br /&gt;
which will enable us to easily add/remove text from the display later on.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
function updateDisplay(text)&lt;br /&gt;
	-- if we are passing some text&lt;br /&gt;
	if text then&lt;br /&gt;
		-- if its a digit or * or #, then append it to the end of the display&lt;br /&gt;
		if tonumber(text) or text == &amp;quot;*&amp;quot; or text == &amp;quot;#&amp;quot; then&lt;br /&gt;
			guiSetText(keypadLabelDisplay,guiGetText(keypadLabelDisplay) .. text)&lt;br /&gt;
		-- otherwise replace the display with the new text&lt;br /&gt;
		else&lt;br /&gt;
			guiSetText(keypadLabelDisplay,text)&lt;br /&gt;
		end	&lt;br /&gt;
	-- if we pass nil, clear the display entirely&lt;br /&gt;
	else&lt;br /&gt;
		guiSetText(keypadLabelDisplay,&amp;quot;&amp;quot;)&lt;br /&gt;
	end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
We can now simply call updateDisplay(our text) to change the text on the display, or updateDisplay(nil) to clear it.&lt;br /&gt;
&lt;br /&gt;
===Detecting the clicks===&lt;br /&gt;
With so many buttons that do very similar tasks on our keypad, there are two methods available to us for detecting when a player clicks on them.&lt;br /&gt;
&lt;br /&gt;
We could add [[onClientGUIClick]] events for every button individually, as we have done in previous tutorials; Or, alternatively, &lt;br /&gt;
we could add a single [[onClientGUIClick]] handle for the window (which is the parent of all our other keypad GUI elements), filter our results to include only the buttons we want and trigger our own custom event.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
For the purposes of this tutorial and in the interest of outlining multiple approaches, we will explore the second method, though either one is an acceptable solution.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
addEventHandler(&amp;quot;onClientGUIClick&amp;quot;,keypadWindow,processKeypadClicks,true)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
'''Notice the final argument is set to 'true'. This means that clicks on any other elements in the same branch of the tree will also trigger this event handle (eg. clicks on our buttons).'''&lt;br /&gt;
&lt;br /&gt;
Add this line of code into your createKeypad function, after your GUI has been created.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Now that we are detecting all clicks on our GUI, we need to filter out the ones we do not want (ie: clicks on the window or display) and trigger our custom event:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
function processKeypadClicks(button,state)&lt;br /&gt;
	if button == &amp;quot;left&amp;quot; and state == &amp;quot;up&amp;quot; then&lt;br /&gt;
		-- if the source of this event is a gui button&lt;br /&gt;
		if getElementType(source) == &amp;quot;gui-button&amp;quot; then&lt;br /&gt;
			-- trigger our custom event and send the keypad id of this keypad as an argument&lt;br /&gt;
			triggerEvent(&amp;quot;onKeypadButtonClicked&amp;quot;,source,getElementData(keypadWindow,&amp;quot;keypadID&amp;quot;))&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
As you can see, we are now triggering our custom event &amp;quot;onKeypadButtonClicked&amp;quot; whenever a button is clicked on the keypad.&lt;br /&gt;
Also note we use element data &amp;quot;keypadID&amp;quot; to differentiate between keypads. This data will need to be set whenever the player is shown a new keypad.&lt;br /&gt;
We will cover this in more detail later.&lt;br /&gt;
&lt;br /&gt;
===Handling the clicks===&lt;br /&gt;
Much like when using [[triggerServerEvent]] in previous tutorials, we now need to define the event, only this time it is purely clientside:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
addEvent(&amp;quot;onKeypadButtonClicked&amp;quot;,false)&lt;br /&gt;
addEventHandler(&amp;quot;onKeypadButtonClicked&amp;quot;,root,&lt;br /&gt;
	function(keypadID)&lt;br /&gt;
&lt;br /&gt;
	end&lt;br /&gt;
)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Note the second argument in [[addEvent]] is set to false, indicating that this event cannot be triggered from the server.&lt;br /&gt;
Also note, the function we are using in the [[addEventHandler]] does not have a name. If you contract it down and remove the spacing, you get:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
addEventHandler(&amp;quot;onKeypadButtonClicked&amp;quot;,root,function() ... end)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
This simply means instead of storing the pointer to the function in a variable, we are passing it directly as an argument.&lt;br /&gt;
Doing it this way cleans up the code and will often make it easier to follow.&lt;br /&gt;
&lt;br /&gt;
Now that the event has been created, we can fill in the code logic that will control our button presses.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
addEvent(&amp;quot;onKeypadButtonClicked&amp;quot;,false)&lt;br /&gt;
addEventHandler(&amp;quot;onKeypadButtonClicked&amp;quot;,root,&lt;br /&gt;
	function(keypadID)&lt;br /&gt;
		-- clear the display if this is the first time its being used&lt;br /&gt;
		if guiGetText(keypadLabelDisplay) == &amp;quot;Enter Keycode.&amp;quot; or guiGetText(keypadLabelDisplay) == &amp;quot;Invalid Keycode.&amp;quot; then&lt;br /&gt;
			updateDisplay()&lt;br /&gt;
		end&lt;br /&gt;
	&lt;br /&gt;
	&lt;br /&gt;
		-- if its the clear button&lt;br /&gt;
		if guiGetText(source) == &amp;quot;Clear&amp;quot; then&lt;br /&gt;
			-- clear the display&lt;br /&gt;
			updateDisplay()&lt;br /&gt;
		&lt;br /&gt;
		-- if its the enter button&lt;br /&gt;
		elseif guiGetText(source) == &amp;quot;Enter&amp;quot; then&lt;br /&gt;
			-- get the currently entered code from the display&lt;br /&gt;
			local code = guiGetText(keypadLabelDisplay)&lt;br /&gt;
			&lt;br /&gt;
			-- if they have entered a code&lt;br /&gt;
			if code then&lt;br /&gt;
				-- trigger the server so we can verify their code&lt;br /&gt;
				triggerServerEvent(&amp;quot;verifyKeypadCode&amp;quot;,getLocalPlayer(),code,keypadID)&lt;br /&gt;
			end&lt;br /&gt;
		&lt;br /&gt;
		-- if its the exit button&lt;br /&gt;
		elseif guiGetText(source) == &amp;quot;Exit&amp;quot; then&lt;br /&gt;
			-- hide the keypad and reset the display text ready for next time&lt;br /&gt;
			guiSetVisible(keypadWindow,false)&lt;br /&gt;
			updateDisplay(&amp;quot;Enter Keycode.&amp;quot;)&lt;br /&gt;
			showCursor(false,false)&lt;br /&gt;
			&lt;br /&gt;
		-- otherwise, it must be a character button&lt;br /&gt;
		else&lt;br /&gt;
			updateDisplay(guiGetText(source))	&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Serverside Verification==&lt;br /&gt;
For this part of the tutorial, you will need to open up a serverside lua file from your resource to work with.&lt;br /&gt;
&lt;br /&gt;
===Defining the keycode===&lt;br /&gt;
Now that we have completed the keypad clicking logic, we need to move on to verifying the code entered into the keypad.&lt;br /&gt;
To do this, we need to have the correct code stored somewhere on the server, which we can check the players code against.&lt;br /&gt;
&lt;br /&gt;
For the purposes of this tutorial we will simply store the code in a serverside table, however it can be done any number of ways (such as serverside xml files or MySQL databases).&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
local keypadCodes = {&lt;br /&gt;
	[&amp;quot;a51MainGateKeypadCode&amp;quot;] = &amp;quot;4455*#&amp;quot;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
This table stores an entry called &amp;quot;a51MainGateKeypadCode&amp;quot; with the code 4455*#&lt;br /&gt;
&lt;br /&gt;
'''This is the keycode that you will use to open the gate later on in this tutorial.'''&lt;br /&gt;
&lt;br /&gt;
===Verifying the code===&lt;br /&gt;
Now that we have a keycode to verify against, we can write our serverside event:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
addEvent(&amp;quot;verifyKeypadCode&amp;quot;,true)&lt;br /&gt;
addEventHandler(&amp;quot;verifyKeypadCode&amp;quot;,root,function(code,keypadID)&lt;br /&gt;
	if code then&lt;br /&gt;
		-- using the table we created earlier, check if the code supplied is the same as the code for this gate&lt;br /&gt;
		if code == keypadCodes[keypadID] then&lt;br /&gt;
			-- if it is, tell the client that it was successful&lt;br /&gt;
			triggerClientEvent(client,&amp;quot;onKeypadVerificationSuccessful&amp;quot;,client,keypadID)&lt;br /&gt;
		else&lt;br /&gt;
			-- if it is not, tell the client that it was not successful&lt;br /&gt;
			triggerClientEvent(client,&amp;quot;onKeypadVerificationFailed&amp;quot;,client,keypadID)&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
end)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Here we use our table and the keypadID supplied by the player to check if the codes match.&lt;br /&gt;
&lt;br /&gt;
If you are not using a table to store the codes, then you will need to replace 'keypadCodes[keypadID]' with your own storage method.&lt;br /&gt;
Once it is verified (or not), we can trigger the client so the appropriate information can be shown on the keypad display.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Receiving the result==&lt;br /&gt;
We have now finished the serverside section of the tutorial, so you will need to open up the clientside lua file from your resource &lt;br /&gt;
that you were previously working on.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Once our code has been verified, the server will send back the response to the client.&lt;br /&gt;
In just the same way as client -&amp;gt; server interaction, we now need to add the event that the server is going to trigger on the client.&lt;br /&gt;
&lt;br /&gt;
===Catching and processing the result===&lt;br /&gt;
First we will add the event for when the verification is successful:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
addEvent(&amp;quot;onKeypadVerificationSuccessful&amp;quot;,true)&lt;br /&gt;
addEventHandler(&amp;quot;onKeypadVerificationSuccessful&amp;quot;,root,&lt;br /&gt;
	function()&lt;br /&gt;
		-- hide the keypad and reset the display text ready for next time&lt;br /&gt;
		guiSetVisible(keypadWindow,false)&lt;br /&gt;
		updateDisplay(&amp;quot;Enter Keycode.&amp;quot;)&lt;br /&gt;
		showCursor(false,false)&lt;br /&gt;
	end&lt;br /&gt;
)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Finally we can add the event for when the verification is unsuccessful:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
addEvent(&amp;quot;onKeypadVerificationFailed&amp;quot;,true)&lt;br /&gt;
addEventHandler(&amp;quot;onKeypadVerificationFailed&amp;quot;,root,&lt;br /&gt;
	function()&lt;br /&gt;
		-- update the display text to show the code was invalid&lt;br /&gt;
		updateDisplay(&amp;quot;Invalid Keycode.&amp;quot;)&lt;br /&gt;
	end&lt;br /&gt;
)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This completes the keypad section of the tutorial.&lt;br /&gt;
&lt;br /&gt;
For an example of how to implement this into a working gate system, carry on reading the next section.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Applying the Keypad==&lt;br /&gt;
For the keypad to have any use, we need something to use it on.&lt;br /&gt;
For this tutorial we will be using gates, and as mentioned earlier we will create a main gate into A51.&lt;br /&gt;
&lt;br /&gt;
===Creating the gate===&lt;br /&gt;
First of all, we need to create the gate object.&lt;br /&gt;
For the purposes of this example, we will be using a map file to store the object. &lt;br /&gt;
While this is the recommended method for defining objects, it is not the only way to approach it.&lt;br /&gt;
&lt;br /&gt;
Navigate to your resource folder and make a new file called gate.map, then add your new map file to your meta.xml using:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;map src=&amp;quot;gate.map&amp;quot;/&amp;gt;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
''If you are unsure of map file syntax, please see the [http://wiki.multitheftauto.com/wiki/Writing_Gamemodes| Writing Gamemodes Tutorial] or check the [[Object]] page for help.''&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;map&amp;gt;&lt;br /&gt;
    &amp;lt;object id=&amp;quot;a51MainGateKeypadCode&amp;quot; model=&amp;quot;971&amp;quot; posX=&amp;quot;96.736&amp;quot; posY=&amp;quot;1918.352&amp;quot; posZ=&amp;quot;20.694&amp;quot; rotX=&amp;quot;0&amp;quot; rotY=&amp;quot;0&amp;quot; rotZ=&amp;quot;270.40&amp;quot; newPosX=&amp;quot;96.751&amp;quot; newPosY=&amp;quot;1914.474&amp;quot; newPosZ=&amp;quot;20.694&amp;quot; /&amp;gt;&lt;br /&gt;
&amp;lt;/map&amp;gt;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
This will create a gate object across the A51 entrance. The object will have position and rotation data, as well as its newPosX,newPosY and newPosZ information that we need to be able to move it.&lt;br /&gt;
&lt;br /&gt;
'''Note that the object id is the same as the table entry we created earlier to hold the access code.'''&lt;br /&gt;
This is one possible method that could be accessed to link this gate with that particular keycode.&lt;br /&gt;
&lt;br /&gt;
===Opening the keypad===&lt;br /&gt;
Back in the clientside lua file again, we can now work on linking the gate and the keypad.&lt;br /&gt;
&lt;br /&gt;
Now that we have our gate, we need a way of accessing the keypad to open it.&lt;br /&gt;
For the purposes of this tutorial we will use a simple command, however you could just as easily use a colshape or button press.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
addCommandHandler(&amp;quot;a51gate&amp;quot;,function()&lt;br /&gt;
	guiSetVisible(keypadWindow,true)&lt;br /&gt;
	showCursor(true,true)&lt;br /&gt;
	setElementData(keypadWindow,&amp;quot;keypadID&amp;quot;,&amp;quot;a51MainGateKeypadCode&amp;quot;)&lt;br /&gt;
end)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Note that we set the element data &amp;quot;keypadID&amp;quot;.&lt;br /&gt;
This is very important because it allows us to keep track of which gate we are trying to open (in this case, the &amp;quot;a51MainGateKeypadCode&amp;quot; gate).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Opening the gate===&lt;br /&gt;
With our gate created and our keypad ready, all thats left now is to open the gate.&lt;br /&gt;
Having created custom events earlier for successfully and unsuccessfully verifying the code, this now becomes very easy to do.&lt;br /&gt;
All we do is add an event handler for our custom &amp;quot;success&amp;quot; event, and using the keypadID we defined earlier we can move the gate inside it:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
addEventHandler(&amp;quot;onKeypadVerificationSuccessful&amp;quot;,root,&lt;br /&gt;
	-- keypadID is sent back from the server&lt;br /&gt;
	function(keypadID)&lt;br /&gt;
		-- get the gate object (this is where the id=&amp;quot;a51MainGateKeypadCode&amp;quot; tag in the map file becomes useful)&lt;br /&gt;
		local gate = getElementByID(keypadID)&lt;br /&gt;
&lt;br /&gt;
		-- if we found the object&lt;br /&gt;
		if gate then&lt;br /&gt;
			-- get the new position (as we defined in the map file)&lt;br /&gt;
			local x = tonumber(getElementData(gate,&amp;quot;newPosX&amp;quot;))&lt;br /&gt;
			local y = tonumber(getElementData(gate,&amp;quot;newPosY&amp;quot;))&lt;br /&gt;
			local z = tonumber(getElementData(gate,&amp;quot;newPosZ&amp;quot;))&lt;br /&gt;
&lt;br /&gt;
			-- move the gate&lt;br /&gt;
			moveObject(gate,1500,x,y,z)&lt;br /&gt;
			&lt;br /&gt;
			-- get the original position&lt;br /&gt;
			x = tonumber(getElementData(gate,&amp;quot;posX&amp;quot;))&lt;br /&gt;
			y = tonumber(getElementData(gate,&amp;quot;posY&amp;quot;))&lt;br /&gt;
			z = tonumber(getElementData(gate,&amp;quot;posZ&amp;quot;))	&lt;br /&gt;
			&lt;br /&gt;
			-- set a timer to close the gate in 5 seconds&lt;br /&gt;
			setTimer(moveObject,5000,1,gate,1500,x,y,z)&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Note how by using the keypadID sent back from the server, we can use if statements and checks against the id to control any number of gates from the same function.&lt;br /&gt;
&lt;br /&gt;
You should now have a working example of a GUI Keypad controlling an A51 Gate.&lt;/div&gt;</summary>
		<author><name>R3mp</name></author>
	</entry>
	<entry>
		<id>https://wiki.multitheftauto.com/index.php?title=File:Gui_keypad_tutorial.png&amp;diff=22162</id>
		<title>File:Gui keypad tutorial.png</title>
		<link rel="alternate" type="text/html" href="https://wiki.multitheftauto.com/index.php?title=File:Gui_keypad_tutorial.png&amp;diff=22162"/>
		<updated>2010-01-03T20:24:48Z</updated>

		<summary type="html">&lt;p&gt;R3mp: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;/div&gt;</summary>
		<author><name>R3mp</name></author>
	</entry>
	<entry>
		<id>https://wiki.multitheftauto.com/index.php?title=Scripting_the_GUI_-_Tutorial_1&amp;diff=22161</id>
		<title>Scripting the GUI - Tutorial 1</title>
		<link rel="alternate" type="text/html" href="https://wiki.multitheftauto.com/index.php?title=Scripting_the_GUI_-_Tutorial_1&amp;diff=22161"/>
		<updated>2010-01-03T20:22:42Z</updated>

		<summary type="html">&lt;p&gt;R3mp: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;'''Scripting the Gui - Tutorial 1 (Gridlists)'''&lt;br /&gt;
&lt;br /&gt;
In this tutorial we will explore the use of gridlists in creating a vehicle selection screen, with optional clientside vehicle xml data reading.&lt;br /&gt;
'''Note that this tutorial assumes you are familiar with all the content covered in the [[Introduction to Scripting GUI|Previous tutorial]].'''&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Setting up the Vehicle Selection==&lt;br /&gt;
&lt;br /&gt;
===Creating the GUI===&lt;br /&gt;
To begin, open up a clientside lua file (if you have been following the [[Scripting Introduction]], this is gui.lua) to work with.&lt;br /&gt;
&lt;br /&gt;
In this file, we will start writing our function for creating the GUI.&lt;br /&gt;
As covered in the [[Introduction to Scripting GUI|Previous tutorial]], there are 2 value type options available when creating gui: '''relative''' and '''absolute'''.&lt;br /&gt;
&lt;br /&gt;
For the purposes of this tutorial, we will be using '''absolute''' values.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
This will create a simple GUI with a window, gridlist and button:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
function createVehicleSelection()&lt;br /&gt;
	-- get the screen width and height&lt;br /&gt;
	local sWidth, sHeight = guiGetScreenSize()&lt;br /&gt;
	&lt;br /&gt;
	-- use some simple maths to position the window in the centre of the screen&lt;br /&gt;
	local Width,Height = 376,259&lt;br /&gt;
	local X = (sWidth/2) - (Width/2)&lt;br /&gt;
	local Y = (sHeight/2) - (Height/2)&lt;br /&gt;
	windowVehicleSelection = guiCreateWindow(X,Y,Width,Height,&amp;quot;Vehicle Selection Window&amp;quot;,false)&lt;br /&gt;
	&lt;br /&gt;
	gridlistVehicleSelection = guiCreateGridList(10,26,357,192,false,windowVehicleSelection)&lt;br /&gt;
	-- add a &amp;quot;Vehicle&amp;quot; and a &amp;quot;Type&amp;quot; collumn to the gridlist&lt;br /&gt;
	guiGridListAddColumn(gridlistVehicleSelection,&amp;quot;Vehicle&amp;quot;,0.2)&lt;br /&gt;
	guiGridListAddColumn(gridlistVehicleSelection,&amp;quot;Type&amp;quot;,0.2)&lt;br /&gt;
	&lt;br /&gt;
	-- set the default width of the columns to roughly half the size of the gridlist (each)&lt;br /&gt;
	guiGridListSetColumnWidth(gridlistVehicleSelection,1,0.4,true)&lt;br /&gt;
	guiGridListSetColumnWidth(gridlistVehicleSelection,2,0.5,true)&lt;br /&gt;
	&lt;br /&gt;
	buttonCreate = guiCreateButton(121,227,120,20,&amp;quot;Create&amp;quot;,false,windowVehicleSelection)&lt;br /&gt;
	&lt;br /&gt;
	-- add the event handler for when the button is clicked&lt;br /&gt;
	addEventHandler(&amp;quot;onClientGUIClick&amp;quot;,buttonCreate,createVehicleHandler,false)&lt;br /&gt;
	&lt;br /&gt;
	-- hide the GUI&lt;br /&gt;
	guiSetVisible(windowVehicleSelection,false)&lt;br /&gt;
	&lt;br /&gt;
	-- this will add all the vehicle options onto the gridlist, it is explained later in this tutorial&lt;br /&gt;
	populateGridlist()&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
We now also need to call this function somewhere, otherwise the GUI will never be created.&lt;br /&gt;
As in previous tutorials, to do this we can use [[onClientResourceStart]].&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
-- when the resource is started, create the GUI and hide it&lt;br /&gt;
addEventHandler(&amp;quot;onClientResourceStart&amp;quot;,getResourceRootElement(getThisResource()),&lt;br /&gt;
	function()&lt;br /&gt;
		createVehicleSelection()&lt;br /&gt;
	end&lt;br /&gt;
)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Showing the GUI===&lt;br /&gt;
Unlike in previous tutorials, we want players to be able to open this window whenever they chose, not when the resource starts. &lt;br /&gt;
So, we can add a [[addCommandHandler|Command]] to do this.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
-- create the function that will show the window&lt;br /&gt;
function showVehicleSelection()&lt;br /&gt;
	-- if the window isnt visible, show it&lt;br /&gt;
	if not guiGetVisible(windowVehicleSelection) then&lt;br /&gt;
		guiSetVisible(windowVehicleSelection,true)&lt;br /&gt;
		&lt;br /&gt;
		showCursor(true,true)&lt;br /&gt;
	end&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
-- add the command /vehicleselection and set it to call the showVehicleSelection function&lt;br /&gt;
addCommandHandler(&amp;quot;vehicleselection&amp;quot;,showVehicleSelection)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Populating the Gridlist from a table===&lt;br /&gt;
Now that we have our basic GUI created, we need to fill the gridlist with all of our vehicles.&lt;br /&gt;
&lt;br /&gt;
To begin with, we will do this using a simple clientside table. &lt;br /&gt;
Later in the tutorial, we will explore expanding this method to use .xml files for storing information.&lt;br /&gt;
To begin, we must create a small table containing a selection of vehicles that we can spawn.&lt;br /&gt;
&lt;br /&gt;
The table contains vehicles in the format [&amp;quot;description&amp;quot;] = vehicle_id :&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
-- create the table and fill it with a selection of vehicle ids and names&lt;br /&gt;
local vehicleSelectionTable = {&lt;br /&gt;
	[&amp;quot;Sparrow&amp;quot;] = 469,&lt;br /&gt;
	[&amp;quot;Stuntplane&amp;quot;] = 513,&lt;br /&gt;
	[&amp;quot;BF-400&amp;quot;] = 581,&lt;br /&gt;
	[&amp;quot;Freeway&amp;quot;] = 463,&lt;br /&gt;
	[&amp;quot;Speeder&amp;quot;] = 452,&lt;br /&gt;
	[&amp;quot;Jester&amp;quot;] = 559,&lt;br /&gt;
	[&amp;quot;Sabre&amp;quot;] = 475,&lt;br /&gt;
	[&amp;quot;Police Ranger&amp;quot;] = 599,&lt;br /&gt;
	[&amp;quot;Utility Van&amp;quot;] = 552,&lt;br /&gt;
	[&amp;quot;Tug&amp;quot;] = 583&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Place this code at the very top of your file (it does not need to be inside a function).&lt;br /&gt;
&lt;br /&gt;
Next, we can write our &amp;quot;populateGridlist&amp;quot; function which will fill the Gridlist with all the vehicles in the table.&lt;br /&gt;
To do this we simply need to loop through all the values in the table, adding each one to the gridlist as we go.&lt;br /&gt;
We will also set hidden data using [[guiGridListSetItemData]] to store the vehicle id:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
function populateGridlist()&lt;br /&gt;
	-- loop through the table&lt;br /&gt;
	for name,vehicle in pairs(vehicleSelectionTable) do&lt;br /&gt;
		-- add a new row to the gridlist&lt;br /&gt;
		local row = guiGridListAddRow(gridlistVehicleSelection)&lt;br /&gt;
&lt;br /&gt;
		-- set the text in the first column to the vehicle name&lt;br /&gt;
		guiGridListSetItemText(gridlistVehicleSelection,row,1,name,false,false)&lt;br /&gt;
		-- set the text in the second column to the vehicle type&lt;br /&gt;
		guiGridListSetItemText(gridlistVehicleSelection,row,2,getVehicleType(vehicle),false,false)&lt;br /&gt;
		&lt;br /&gt;
		-- set the data for gridlist slot as the vehicle id&lt;br /&gt;
		guiGridListSetItemData(gridlistVehicleSelection,row,1,tostring(vehicle))&lt;br /&gt;
	end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt; &lt;br /&gt;
&lt;br /&gt;
===Managing the click===&lt;br /&gt;
Now that we have our GUI completed, we need to be able to catch any clicks made on the &amp;quot;create&amp;quot; button.&lt;br /&gt;
We have attached the [[onClientGUIClick]] event to buttonCreate already, so now we need to write the function that it calls.&lt;br /&gt;
In this function we do some basic error checking, such as making sure a vehicle has been selected in the list. &lt;br /&gt;
We can then use some maths to find a position infront of the player and send the server this information to spawn the vehicle (using [[triggerServerEvent]]) &lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
function createVehicleHandler(button,state)&lt;br /&gt;
	if button == &amp;quot;left&amp;quot; and state == &amp;quot;up&amp;quot; then&lt;br /&gt;
		-- get the selected item in the gridlist&lt;br /&gt;
		local row,col = guiGridListGetSelectedItem(gridlistVehicleSelection)&lt;br /&gt;
		&lt;br /&gt;
		-- if something is selected&lt;br /&gt;
		if row and col and row ~= -1 and col ~= -1 then&lt;br /&gt;
			-- get the vehicle id data from the gridlist that is selected&lt;br /&gt;
			local selected = guiGridListGetItemData(gridlistVehicleSelection,row,col)&lt;br /&gt;
			&lt;br /&gt;
			-- make sure the vehicle id is a number not a string&lt;br /&gt;
			selected = tonumber(selected)&lt;br /&gt;
						&lt;br /&gt;
			-- get the players position and rotation&lt;br /&gt;
			local rotz = getPedRotation(getLocalPlayer())&lt;br /&gt;
			local x,y,z = getElementPosition(getLocalPlayer())&lt;br /&gt;
			-- find the position directly infront of the player&lt;br /&gt;
			x = x + ( math.cos ( math.rad ( rotz+90 ) ) * 3)&lt;br /&gt;
			y = y + ( math.sin ( math.rad ( rotz+90 ) ) * 3)&lt;br /&gt;
			&lt;br /&gt;
			if selected and x and y and z then&lt;br /&gt;
				-- trigger the server&lt;br /&gt;
				triggerServerEvent(&amp;quot;createVehicleFromGUI&amp;quot;,getRootElement(),selected,x,y,z)&lt;br /&gt;
				&lt;br /&gt;
				-- hide the gui and the cursor&lt;br /&gt;
				guiSetVisible(windowVehicleSelection,false)&lt;br /&gt;
				showCursor(false,false)&lt;br /&gt;
			else&lt;br /&gt;
				outputChatBox(&amp;quot;Invalid arguments.&amp;quot;)&lt;br /&gt;
			end&lt;br /&gt;
		else&lt;br /&gt;
			-- otherwise, output a message to the player&lt;br /&gt;
			outputChatBox(&amp;quot;Please select a vehicle.&amp;quot;)&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Creating the Vehicle===&lt;br /&gt;
At this point we now have all the code needed on the client side, so open up a serverside .lua file to work with. &lt;br /&gt;
&lt;br /&gt;
On the server side, we will first of all need to define the custom event that we triggered before from the client. This can be done using [[addEvent]] and [[addEventHandler]].&lt;br /&gt;
Finally we will need a small function for creating the vehicle:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
function createMyVehicle(vehicleid,x,y,z)&lt;br /&gt;
	-- check all the arguments exist&lt;br /&gt;
	if vehicleid and x and y and z then&lt;br /&gt;
		createVehicle(vehicleid,x,y,z)&lt;br /&gt;
	end&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
addEvent(&amp;quot;createVehicleFromGUI&amp;quot;,true)&lt;br /&gt;
addEventHandler(&amp;quot;createVehicleFromGUI&amp;quot;,root,createMyVehicle)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Note the use of the &amp;quot;root&amp;quot; variable. This is an MTA variable containing the root element; every resource has one.&lt;br /&gt;
&lt;br /&gt;
This completes the first section of the tutorial. You should now have a basic, working vehicle spawn script.&lt;br /&gt;
&lt;br /&gt;
In the second section, we will cover collapsible gridlist data and clientside xml file reading.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Expanding the code==&lt;br /&gt;
This section will detail several ways to improve upon the code you now have.&lt;br /&gt;
&lt;br /&gt;
===Importing Data===&lt;br /&gt;
One big improvement over the previously mentioned method is to use external files to store the vehicle information, allowing us to much more quickly and easily manage large amounts of data.&lt;br /&gt;
For this tutorial, we will use a clientside xml file to hold the information.&lt;br /&gt;
&lt;br /&gt;
First of all you will need to create your xml file, so navigate to your resources directory and create a new file named vehicles.xml:&lt;br /&gt;
&lt;br /&gt;
''For the purpose of this example, we will include only a small fraction of the total vehicles, however the file can easily be expanded to include them all.''&lt;br /&gt;
&lt;br /&gt;
If you are unsure of xml data structures, you can browse the [http://wiki.multitheftauto.com/wiki/Server_Scripting_Functions#XML_functions| MTA xml functions] for help.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;root&amp;gt;&lt;br /&gt;
	&amp;lt;group type=&amp;quot;Bikes&amp;quot;&amp;gt;&lt;br /&gt;
		&amp;lt;vehicle id=&amp;quot;581&amp;quot; name=&amp;quot;BF-400&amp;quot;/&amp;gt;&lt;br /&gt;
		&amp;lt;vehicle id=&amp;quot;463&amp;quot; name=&amp;quot;Freeway&amp;quot;/&amp;gt;&lt;br /&gt;
		&amp;lt;vehicle id=&amp;quot;481&amp;quot; name=&amp;quot;BMX&amp;quot;/&amp;gt;&lt;br /&gt;
	&amp;lt;/group&amp;gt;&lt;br /&gt;
	&amp;lt;group type=&amp;quot;Boats&amp;quot;&amp;gt;&lt;br /&gt;
		&amp;lt;vehicle id=&amp;quot;472&amp;quot; name=&amp;quot;Coastguard&amp;quot;/&amp;gt;&lt;br /&gt;
		&amp;lt;vehicle id=&amp;quot;452&amp;quot; name=&amp;quot;Speeder&amp;quot;/&amp;gt;&lt;br /&gt;
	&amp;lt;/group&amp;gt;&lt;br /&gt;
	&amp;lt;group type=&amp;quot;Helicopters&amp;quot;&amp;gt;&lt;br /&gt;
		&amp;lt;vehicle id=&amp;quot;487&amp;quot; name=&amp;quot;Maverick&amp;quot;/&amp;gt;&lt;br /&gt;
		&amp;lt;vehicle id=&amp;quot;469&amp;quot; name=&amp;quot;Sparrow&amp;quot;/&amp;gt;	&lt;br /&gt;
	&amp;lt;/group&amp;gt;&lt;br /&gt;
	&amp;lt;group type=&amp;quot;Planes&amp;quot;&amp;gt;&lt;br /&gt;
		&amp;lt;vehicle id=&amp;quot;593&amp;quot; name=&amp;quot;Dodo&amp;quot;/&amp;gt;&lt;br /&gt;
		&amp;lt;vehicle id=&amp;quot;513&amp;quot; name=&amp;quot;Stuntplane&amp;quot;/&amp;gt;	&lt;br /&gt;
	&amp;lt;/group&amp;gt;&lt;br /&gt;
	&amp;lt;group type=&amp;quot;Sports Cars&amp;quot;&amp;gt;&lt;br /&gt;
		&amp;lt;vehicle id=&amp;quot;565&amp;quot; name=&amp;quot;Flash&amp;quot;/&amp;gt;&lt;br /&gt;
		&amp;lt;vehicle id=&amp;quot;559&amp;quot; name=&amp;quot;Jester&amp;quot;/&amp;gt;&lt;br /&gt;
		&amp;lt;vehicle id=&amp;quot;477&amp;quot; name=&amp;quot;ZR-350&amp;quot;/&amp;gt;	&lt;br /&gt;
	&amp;lt;/group&amp;gt;&lt;br /&gt;
	&amp;lt;group type=&amp;quot;2-Door&amp;quot;&amp;gt;&lt;br /&gt;
		&amp;lt;vehicle id=&amp;quot;474&amp;quot; name=&amp;quot;Hermes&amp;quot;/&amp;gt;&lt;br /&gt;
		&amp;lt;vehicle id=&amp;quot;475&amp;quot; name=&amp;quot;Sabre&amp;quot;/&amp;gt;&lt;br /&gt;
	&amp;lt;/group&amp;gt;&lt;br /&gt;
	&amp;lt;group type=&amp;quot;Emergency&amp;quot;&amp;gt;&lt;br /&gt;
		&amp;lt;vehicle id=&amp;quot;416&amp;quot; name=&amp;quot;Ambulance&amp;quot;/&amp;gt;&lt;br /&gt;
		&amp;lt;vehicle id=&amp;quot;599&amp;quot; name=&amp;quot;Police ranger&amp;quot;/&amp;gt;&lt;br /&gt;
	&amp;lt;/group&amp;gt;&lt;br /&gt;
	&amp;lt;group type=&amp;quot;Industrial&amp;quot;&amp;gt;&lt;br /&gt;
		&amp;lt;vehicle id=&amp;quot;573&amp;quot; name=&amp;quot;Dune&amp;quot;/&amp;gt;&lt;br /&gt;
		&amp;lt;vehicle id=&amp;quot;552&amp;quot; name=&amp;quot;Utility van&amp;quot;/&amp;gt;	&lt;br /&gt;
	&amp;lt;/group&amp;gt;&lt;br /&gt;
	&amp;lt;group type=&amp;quot;Misc&amp;quot;&amp;gt;&lt;br /&gt;
		&amp;lt;vehicle id=&amp;quot;457&amp;quot; name=&amp;quot;Caddy&amp;quot;/&amp;gt;&lt;br /&gt;
		&amp;lt;vehicle id=&amp;quot;583&amp;quot; name=&amp;quot;Tug&amp;quot;/&amp;gt;&lt;br /&gt;
	&amp;lt;/group&amp;gt;&lt;br /&gt;
&amp;lt;/root&amp;gt;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Once you have created your file, do not forget to add it to the meta.xml of your resource with the appropriate client tag.&lt;br /&gt;
&lt;br /&gt;
Note the group &amp;quot;type&amp;quot; tag. This is an arbitrary description of the vehicles contained within the group and can be renamed or added as any text.&lt;br /&gt;
Similarly, the vehicle &amp;quot;name&amp;quot; tag is also just a textual description of the vehicle and does not need to be the exact vehicle name.&lt;br /&gt;
&lt;br /&gt;
Now that we have the data, we can import it into the game and display it in the GUI.&lt;br /&gt;
'''If you are following on from the first section of this tutorial, this new code will replace what is inside your existing 'populateGridlist' function.'''&lt;br /&gt;
First, we need to load the file:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
function populateGridlist()&lt;br /&gt;
	-- load the file and save the root node value it returns&lt;br /&gt;
	local rootnode = xmlLoadFile(&amp;quot;vehicles.xml&amp;quot;)&lt;br /&gt;
	&lt;br /&gt;
	-- check that the file exists and has been correctly loaded&lt;br /&gt;
	if rootnode then		&lt;br /&gt;
		-- unload the xml file&lt;br /&gt;
		xmlUnloadFile(rootnode)&lt;br /&gt;
	end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Always make sure you unload any files once you are finished using them.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
We can now start collecting the data from the file and entering it into our gridlist.&lt;br /&gt;
We can do this by looping through the xml data (in a similar manner to looping through the vehicle table earlier in this tutorial) and adding each entry into the list.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
function populateGridlist()&lt;br /&gt;
	local rootnode = xmlLoadFile(&amp;quot;vehicles.xml&amp;quot;)&lt;br /&gt;
	&lt;br /&gt;
	if rootnode then		&lt;br /&gt;
		-- first, we find every &amp;quot;group&amp;quot; node (they are direct children of the root)&lt;br /&gt;
		for _,group in ipairs(xmlNodeGetChildren(rootnode)) do&lt;br /&gt;
			-- add a new row to the gridlist&lt;br /&gt;
			local row = guiGridListAddRow(gridlistVehicleSelection)&lt;br /&gt;
&lt;br /&gt;
			-- get the group name&lt;br /&gt;
			local name = xmlNodeGetAttribute(group,&amp;quot;type&amp;quot;)&lt;br /&gt;
			&lt;br /&gt;
			-- set the text in the first column to the group type and indicate it is a section ('true')&lt;br /&gt;
			-- (sections on gridlists show up in bold and cannot be clicked)&lt;br /&gt;
			guiGridListSetItemText(gridlistVehicleSelection,row,1,name,true,false)			&lt;br /&gt;
		&lt;br /&gt;
			-- then, for every group that we find, loop all of its children (the vehicle nodes)&lt;br /&gt;
			-- and add them into the gridlist&lt;br /&gt;
			for _,vehicle in ipairs(xmlNodeGetChildren(group)) do&lt;br /&gt;
				-- add a new row to the gridlist&lt;br /&gt;
				row = guiGridListAddRow(gridlistVehicleSelection)&lt;br /&gt;
&lt;br /&gt;
				-- get the vehicle name and id&lt;br /&gt;
				name = xmlNodeGetAttribute(vehicle,&amp;quot;name&amp;quot;)&lt;br /&gt;
				local id = xmlNodeGetAttribute(vehicle,&amp;quot;id&amp;quot;)&lt;br /&gt;
				&lt;br /&gt;
				-- set the text in the first column to the vehicle name&lt;br /&gt;
				guiGridListSetItemText(gridlistVehicleSelection,row,1,name,false,false)&lt;br /&gt;
				-- set the text in the second column to the vehicle type&lt;br /&gt;
				guiGridListSetItemText(gridlistVehicleSelection,row,2,getVehicleType(tonumber(id)),false,false)		&lt;br /&gt;
				&lt;br /&gt;
				-- finally, set the vehicle id as data so we can access it later&lt;br /&gt;
				guiGridListSetItemData(gridlistVehicleSelection,row,1,tostring(id))&lt;br /&gt;
			end&lt;br /&gt;
		end	&lt;br /&gt;
	&lt;br /&gt;
		-- unload the xml file now that we are finished&lt;br /&gt;
		xmlUnloadFile(rootnode)&lt;br /&gt;
	end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Note the use of for loops in the code with [[xmlNodeGetChildren]]. This saves us a lot of time and effort as we do not have to manually code each group and vehicle into the list.&lt;br /&gt;
&lt;br /&gt;
You should now have a fully working vehicle selection menu, reading all of its data from a clientside xml file.&lt;br /&gt;
Next, we will examine how to generate the appearance of collapsing and expanding sections in a gridlist.&lt;br /&gt;
&lt;br /&gt;
===Collapsing/Expanding the Gridlist===&lt;br /&gt;
Allowing sections of the gridlist to be collapsed or expanded gives much more control over the visible content to the user.&lt;br /&gt;
This frees up space on the screen and makes the whole menu much more comfortable to use.&lt;br /&gt;
&lt;br /&gt;
===Loading the data===&lt;br /&gt;
To be able to achieve this effect (as it is not a natural feature of gridlists) we will need to load the vehicle information into a table (from the xml file), rather than directly including it all in the gridlist.&lt;br /&gt;
'''If you are following on from a previous section of this tutorial, this new code will replace what is inside your existing 'populateGridlist' function.'''&lt;br /&gt;
&lt;br /&gt;
This works in much the same way the previous xml loading example does, only this time instead of saving the data into the gridlist, we save it into a table entry instead.&lt;br /&gt;
We also set the custom data &amp;quot;header&amp;quot; on the gridlist slots to denote which gridlist entries are our &amp;quot;group&amp;quot; entries and which are vehicles.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
function populateGridlist()&lt;br /&gt;
	local rootnode = xmlLoadFile(&amp;quot;vehicles.xml&amp;quot;)&lt;br /&gt;
	&lt;br /&gt;
	-- create a blank global table to store our imported data&lt;br /&gt;
	vehicleTable = {}&lt;br /&gt;
	&lt;br /&gt;
	if rootnode then		&lt;br /&gt;
		for _,group in ipairs(xmlNodeGetChildren(rootnode)) do&lt;br /&gt;
			-- create an entry in the gridlist for every vehicle &amp;quot;group&amp;quot;&lt;br /&gt;
			local row = guiGridListAddRow(gridlistVehicleSelection)&lt;br /&gt;
&lt;br /&gt;
			local name = xmlNodeGetAttribute(group,&amp;quot;type&amp;quot;)&lt;br /&gt;
			&lt;br /&gt;
			guiGridListSetItemText(gridlistVehicleSelection,row,1,name,false,false)	&lt;br /&gt;
&lt;br /&gt;
			-- add an entry containing the group name into the table&lt;br /&gt;
			vehicleTable[name] = {}&lt;br /&gt;
			&lt;br /&gt;
			-- we will use the custom data &amp;quot;header&amp;quot; to indicate that this entry can be expanded/collapsed&lt;br /&gt;
			guiGridListSetItemData(gridlistVehicleSelection,row,1,&amp;quot;header&amp;quot;)	&lt;br /&gt;
		&lt;br /&gt;
			-- then, for every group that we find, loop all of its children (the vehicle nodes) and store them in a table&lt;br /&gt;
			for _,vehicle in ipairs(xmlNodeGetChildren(group)) do&lt;br /&gt;
				local vname = xmlNodeGetAttribute(vehicle,&amp;quot;name&amp;quot;)&lt;br /&gt;
				local id = xmlNodeGetAttribute(vehicle,&amp;quot;id&amp;quot;)			&lt;br /&gt;
			&lt;br /&gt;
				-- insert both the vehicle id and the vehicle description into the table&lt;br /&gt;
				table.insert(vehicleTable[name],{id,vname})&lt;br /&gt;
			end&lt;br /&gt;
		end	&lt;br /&gt;
	&lt;br /&gt;
		-- set element data on the gridlist so we know which group is currently showing&lt;br /&gt;
		setElementData(gridlistVehicleSelection,&amp;quot;expanded&amp;quot;,&amp;quot;none&amp;quot;)&lt;br /&gt;
	&lt;br /&gt;
		-- unload the xml file now that we are finished&lt;br /&gt;
		xmlUnloadFile(rootnode)&lt;br /&gt;
	end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Now that we have all the data stored, we can quickly manipulate it when neccessary.&lt;br /&gt;
&lt;br /&gt;
===Managing the double click===&lt;br /&gt;
To enable the player to simply double click on a group name to expand/collapse it we need to use the [[onClientGUIDoubleClick]] event.&lt;br /&gt;
If we attach it to the gridlist, we can then catch any double clicks on the group names in it:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
-- attach the onClientGUIDoubleClick event to the gridlist and set it to call processDoubleClick&lt;br /&gt;
addEventHandler(&amp;quot;onClientGUIDoubleClick&amp;quot;,gridlistVehicleSelection,processDoubleClick,false)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Add this line of code in your createVehicleSelection, after the gridlist has been created.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
As the gridlist items are not separate GUI elements, we must capture all clicks from anywhere on the gridlist then process them to filter out the ones we do not want.&lt;br /&gt;
This can be done by checking if an item is selected, then checking if the item is one of our &amp;quot;group&amp;quot; values (using our previously mentioned &amp;quot;header&amp;quot; data):&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
function processDoubleClick(button,state)&lt;br /&gt;
	if button == &amp;quot;left&amp;quot; and state == &amp;quot;up&amp;quot; then&lt;br /&gt;
		local row,col = guiGridListGetSelectedItem(gridlistVehicleSelection)&lt;br /&gt;
		&lt;br /&gt;
		-- if something in the gridlist has been selected&lt;br /&gt;
		if row and col and row ~= -1 and col ~= -1 then		&lt;br /&gt;
			-- if it is a header&lt;br /&gt;
			if guiGridListGetItemData(gridlistVehicleSelection,row,col) == &amp;quot;header&amp;quot; then&lt;br /&gt;
				local selected = guiGridListGetItemText(gridlistVehicleSelection,row,col)&lt;br /&gt;
				&lt;br /&gt;
				-- call the function to collapse or expand the menu and pass which section it is as an argument&lt;br /&gt;
				changeGridlistState(selected)&lt;br /&gt;
			end&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Once we have narrowed down the double clicks to only those done on our group headers, we can expand/collapse them appropriately.&lt;br /&gt;
This can be done by simply setting new text values in the gridlist according to the newly expanded/collapsed group, which creates the convincing illusion of collapsable menus.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Note that much of the following code is reused from previous areas of this tutorial. While it is generally bad practice to clone sections of code in this way, for the purposes of this example it is far easier to understand.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
function changeGridlistState(group)&lt;br /&gt;
	if group then&lt;br /&gt;
		-- if the group is already expanded, we want to collapse it&lt;br /&gt;
		if getElementData(gridlistVehicleSelection,&amp;quot;expanded&amp;quot;) == group then&lt;br /&gt;
			-- first, we clear all previous data from the gridlist&lt;br /&gt;
			guiGridListClear(gridlistVehicleSelection)&lt;br /&gt;
			&lt;br /&gt;
			-- now, loop all the group entries in the vehicle table that we created earlier&lt;br /&gt;
			for group,_ in pairs(vehicleTable) do&lt;br /&gt;
				-- add each group to the list and mark them with &amp;quot;header&amp;quot;			&lt;br /&gt;
				local row = guiGridListAddRow(gridlistVehicleSelection)&lt;br /&gt;
				&lt;br /&gt;
				guiGridListSetItemText(gridlistVehicleSelection,row,1,group,false,false)	&lt;br /&gt;
				guiGridListSetItemData(gridlistVehicleSelection,row,1,&amp;quot;header&amp;quot;)	&lt;br /&gt;
			end&lt;br /&gt;
			&lt;br /&gt;
			-- update the data to indicate that no groups are currently expanded&lt;br /&gt;
			setElementData(gridlistVehicleSelection,&amp;quot;expanded&amp;quot;,&amp;quot;none&amp;quot;)&lt;br /&gt;
			&lt;br /&gt;
		-- otherwise, we want to expand it&lt;br /&gt;
		else&lt;br /&gt;
			guiGridListClear(gridlistVehicleSelection)&lt;br /&gt;
			&lt;br /&gt;
			local row = guiGridListAddRow(gridlistVehicleSelection)&lt;br /&gt;
			&lt;br /&gt;
			guiGridListSetItemText(gridlistVehicleSelection,row,1,group,false,false)	&lt;br /&gt;
			guiGridListSetItemData(gridlistVehicleSelection,row,1,&amp;quot;header&amp;quot;)				&lt;br /&gt;
			&lt;br /&gt;
			-- loop every vehicle in the specified groups table&lt;br /&gt;
			for _,vehicle in ipairs(vehicleTable[group]) do&lt;br /&gt;
				-- add them to the gridlist and set the vehicle id as data&lt;br /&gt;
				row = guiGridListAddRow(gridlistVehicleSelection)&lt;br /&gt;
			&lt;br /&gt;
				-- format a &amp;quot;-&amp;quot; into the string to make it visually easier to distinguish between groups and vehicles&lt;br /&gt;
				guiGridListSetItemText(gridlistVehicleSelection,row,1,&amp;quot;- &amp;quot;..vehicle[2],false,false)	&lt;br /&gt;
				guiGridListSetItemText(gridlistVehicleSelection,row,2,getVehicleType(tonumber(vehicle[1])),false,false)	&lt;br /&gt;
											&lt;br /&gt;
				guiGridListSetItemData(gridlistVehicleSelection,row,1,tostring(vehicle[1]))&lt;br /&gt;
			end	&lt;br /&gt;
&lt;br /&gt;
			-- update the data to indicate which group is currently expanded&lt;br /&gt;
			setElementData(gridlistVehicleSelection,&amp;quot;expanded&amp;quot;,group)			&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This comletes the second section of the tutorial.&lt;br /&gt;
&lt;br /&gt;
For further GUI tutorials, see [[Scripting the GUI - Tutorial 2|Tutorial 2 (Gates and Keypads)]]&lt;/div&gt;</summary>
		<author><name>R3mp</name></author>
	</entry>
	<entry>
		<id>https://wiki.multitheftauto.com/index.php?title=Scripting_the_GUI_-_Tutorial_2&amp;diff=22160</id>
		<title>Scripting the GUI - Tutorial 2</title>
		<link rel="alternate" type="text/html" href="https://wiki.multitheftauto.com/index.php?title=Scripting_the_GUI_-_Tutorial_2&amp;diff=22160"/>
		<updated>2010-01-03T20:21:20Z</updated>

		<summary type="html">&lt;p&gt;R3mp: Created page with ''''Scripting the GUI - Tutorial 2 (Gates + Keypads)'''  In this tutorial we will look at creating GUI keypads with combination codes for map-defined object gates. We will be usin…'&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;'''Scripting the GUI - Tutorial 2 (Gates + Keypads)'''&lt;br /&gt;
&lt;br /&gt;
In this tutorial we will look at creating GUI keypads with combination codes for map-defined object gates.&lt;br /&gt;
We will be using serverside keycodes, with some client - server interaction to verify the codes and report the outcome.&lt;br /&gt;
&lt;br /&gt;
'''Note that this tutorial assumes you are familiar with all the content covered in the [[Introduction to Scripting GUI|GUI Scripting Introduction]].'''&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Setting up the Keypad==&lt;br /&gt;
To begin, open up a clientside lua file (if you have been following the [[Introduction to Scripting GUI|GUI Scripting Introduction]], this is gui.lua) to work with.&lt;br /&gt;
&lt;br /&gt;
===Creating the GUI===&lt;br /&gt;
By now, GUI creation should seem relatively straight forward, so we will not go over this in too much detail.&lt;br /&gt;
As in [[Scripting the GUI - Tutorial 1|Tutorial 1]] we will be using '''absolute''' values in this tutorial.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
function createKeypad()&lt;br /&gt;
	-- get the screen width and height&lt;br /&gt;
	local sWidth, sHeight = guiGetScreenSize()&lt;br /&gt;
&lt;br /&gt;
	-- create the window, using some maths to find the centre of the screen&lt;br /&gt;
	local Width,Height = 142,276&lt;br /&gt;
	local X = (sWidth/2) - (Width/2)&lt;br /&gt;
	local Y = (sHeight/2) - (Height/2)&lt;br /&gt;
	keypadWindow = guiCreateWindow(X,Y,Width,Height,&amp;quot;Keypad&amp;quot;,false)&lt;br /&gt;
	&lt;br /&gt;
	-- don't allow people to resize the keypad&lt;br /&gt;
	guiWindowSetSizable(keypadWindow,false)&lt;br /&gt;
&lt;br /&gt;
	-- create buttons labeled 0-9, &amp;quot;*&amp;quot;, &amp;quot;#&amp;quot;, &amp;quot;Enter&amp;quot; and &amp;quot;C&amp;quot; (clear)&lt;br /&gt;
	keypadButton1 = guiCreateButton(13,68,37,36,&amp;quot;1&amp;quot;,false,keypadWindow)&lt;br /&gt;
	keypadButton2 = guiCreateButton(53,68,37,36,&amp;quot;2&amp;quot;,false,keypadWindow)&lt;br /&gt;
	keypadButton3 = guiCreateButton(93,68,37,36,&amp;quot;3&amp;quot;,false,keypadWindow)&lt;br /&gt;
	keypadButton4 = guiCreateButton(13,108,37,36,&amp;quot;4&amp;quot;,false,keypadWindow)&lt;br /&gt;
	keypadButton5 = guiCreateButton(53,108,37,36,&amp;quot;5&amp;quot;,false,keypadWindow)&lt;br /&gt;
	keypadButton6 = guiCreateButton(93,108,37,36,&amp;quot;6&amp;quot;,false,keypadWindow)&lt;br /&gt;
	keypadButton7 = guiCreateButton(13,148,37,36,&amp;quot;7&amp;quot;,false,keypadWindow)&lt;br /&gt;
	keypadButton8 = guiCreateButton(53,148,37,36,&amp;quot;8&amp;quot;,false,keypadWindow)&lt;br /&gt;
	keypadButton9 = guiCreateButton(93,148,37,36,&amp;quot;9&amp;quot;,false,keypadWindow)&lt;br /&gt;
	keypadButtonAsterix = guiCreateButton(13,188,37,36,&amp;quot;*&amp;quot;,false,keypadWindow)&lt;br /&gt;
	keypadButton0 = guiCreateButton(53,188,37,36,&amp;quot;0&amp;quot;,false,keypadWindow)&lt;br /&gt;
	keypadButtonHash = guiCreateButton(93,188,37,36,&amp;quot;#&amp;quot;,false,keypadWindow)&lt;br /&gt;
	keypadButtonExit = guiCreateButton(13,228,37,36,&amp;quot;Exit&amp;quot;,false,keypadWindow)&lt;br /&gt;
	keypadButtonEnter = guiCreateButton(53,228,37,36,&amp;quot;Enter&amp;quot;,false,keypadWindow)&lt;br /&gt;
	keypadButtonClear = guiCreateButton(93,228,37,36,&amp;quot;Clear&amp;quot;,false,keypadWindow)&lt;br /&gt;
&lt;br /&gt;
	-- create a gridlist to act as a backdrop on the kaypad display&lt;br /&gt;
	keypadGridlistDisplay = guiCreateGridList(13,25,117,33,false,keypadWindow)&lt;br /&gt;
	guiGridListSetSelectionMode(keypadGridlistDisplay,2)&lt;br /&gt;
	guiSetAlpha(keypadGridlistDisplay,0.6)&lt;br /&gt;
	-- create a label so we can write text on the keypad display&lt;br /&gt;
	keypadLabelDisplay = guiCreateLabel(14,26,115,30,&amp;quot;Enter Keycode.&amp;quot;,false,keypadWindow)&lt;br /&gt;
	guiLabelSetColor(keypadLabelDisplay,255,000,000)&lt;br /&gt;
	guiLabelSetVerticalAlign(keypadLabelDisplay,&amp;quot;center&amp;quot;)&lt;br /&gt;
	guiLabelSetHorizontalAlign(keypadLabelDisplay,&amp;quot;center&amp;quot;,false)&lt;br /&gt;
	&lt;br /&gt;
	guiSetVisible(keypadWindow,false)&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
-- create the GUI when the resource starts&lt;br /&gt;
addEventHandler(&amp;quot;onClientResourceStart&amp;quot;,getResourceRootElement(getThisResource()),createKeypad)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
As you can see, the keypad consists of 10 numerical keys (0-9), two character keys (* and #), a clear key, an exit key and an enter key.&lt;br /&gt;
This means the codes used on the keypad can contain any of these characters (0123456789*#).&lt;br /&gt;
&lt;br /&gt;
===Managing the display===&lt;br /&gt;
We will begin by writing a small function to control the display on the keypad.&lt;br /&gt;
This is done by encapsulating several methods of changing the text into a single function,&lt;br /&gt;
which will enable us to easily add/remove text from the display later on.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
function updateDisplay(text)&lt;br /&gt;
	-- if we are passing some text&lt;br /&gt;
	if text then&lt;br /&gt;
		-- if its a digit or * or #, then append it to the end of the display&lt;br /&gt;
		if tonumber(text) or text == &amp;quot;*&amp;quot; or text == &amp;quot;#&amp;quot; then&lt;br /&gt;
			guiSetText(keypadLabelDisplay,guiGetText(keypadLabelDisplay) .. text)&lt;br /&gt;
		-- otherwise replace the display with the new text&lt;br /&gt;
		else&lt;br /&gt;
			guiSetText(keypadLabelDisplay,text)&lt;br /&gt;
		end	&lt;br /&gt;
	-- if we pass nil, clear the display entirely&lt;br /&gt;
	else&lt;br /&gt;
		guiSetText(keypadLabelDisplay,&amp;quot;&amp;quot;)&lt;br /&gt;
	end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
We can now simply call updateDisplay(our text) to change the text on the display, or updateDisplay(nil) to clear it.&lt;br /&gt;
&lt;br /&gt;
===Detecting the clicks===&lt;br /&gt;
With so many buttons that do very similar tasks on our keypad, there are two methods available to us for detecting when a player clicks on them.&lt;br /&gt;
&lt;br /&gt;
We could add [[onClientGUIClick]] events for every button individually, as we have done in previous tutorials; Or, alternatively, &lt;br /&gt;
we could add a single [[onClientGUIClick]] handle for the window (which is the parent of all our other keypad GUI elements), filter our results to include only the buttons we want and trigger our own custom event.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
For the purposes of this tutorial and in the interest of outlining multiple approaches, we will explore the second method, though either one is an acceptable solution.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
addEventHandler(&amp;quot;onClientGUIClick&amp;quot;,keypadWindow,processKeypadClicks,true)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
'''Notice the final argument is set to 'true'. This means that clicks on any other elements in the same branch of the tree will also trigger this event handle (eg. clicks on our buttons).'''&lt;br /&gt;
&lt;br /&gt;
Add this line of code into your createKeypad function, after your GUI has been created.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Now that we are detecting all clicks on our GUI, we need to filter out the ones we do not want (ie: clicks on the window or display) and trigger our custom event:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
function processKeypadClicks(button,state)&lt;br /&gt;
	if button == &amp;quot;left&amp;quot; and state == &amp;quot;up&amp;quot; then&lt;br /&gt;
		-- if the source of this event is a gui button&lt;br /&gt;
		if getElementType(source) == &amp;quot;gui-button&amp;quot; then&lt;br /&gt;
			-- trigger our custom event and send the keypad id of this keypad as an argument&lt;br /&gt;
			triggerEvent(&amp;quot;onKeypadButtonClicked&amp;quot;,source,getElementData(keypadWindow,&amp;quot;keypadID&amp;quot;))&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
As you can see, we are now triggering our custom event &amp;quot;onKeypadButtonClicked&amp;quot; whenever a button is clicked on the keypad.&lt;br /&gt;
Also note we use element data &amp;quot;keypadID&amp;quot; to differentiate between keypads. This data will need to be set whenever the player is shown a new keypad.&lt;br /&gt;
We will cover this in more detail later.&lt;br /&gt;
&lt;br /&gt;
===Handling the clicks===&lt;br /&gt;
Much like when using [[triggerServerEvent]] in previous tutorials, we now need to define the event, only this time it is purely clientside:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
addEvent(&amp;quot;onKeypadButtonClicked&amp;quot;,false)&lt;br /&gt;
addEventHandler(&amp;quot;onKeypadButtonClicked&amp;quot;,root,&lt;br /&gt;
	function(keypadID)&lt;br /&gt;
&lt;br /&gt;
	end&lt;br /&gt;
)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Note the second argument in [[addEvent]] is set to false, indicating that this event cannot be triggered from the server.&lt;br /&gt;
Also note, the function we are using in the [[addEventHandler]] does not have a name. If you contract it down and remove the spacing, you get:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
addEventHandler(&amp;quot;onKeypadButtonClicked&amp;quot;,root,function() ... end)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
This simply means instead of storing the pointer to the function in a variable, we are passing it directly as an argument.&lt;br /&gt;
Doing it this way cleans up the code and will often make it easier to follow.&lt;br /&gt;
&lt;br /&gt;
Now that the event has been created, we can fill in the code logic that will control our button presses.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
addEvent(&amp;quot;onKeypadButtonClicked&amp;quot;,false)&lt;br /&gt;
addEventHandler(&amp;quot;onKeypadButtonClicked&amp;quot;,root,&lt;br /&gt;
	function(keypadID)&lt;br /&gt;
		-- clear the display if this is the first time its being used&lt;br /&gt;
		if guiGetText(keypadLabelDisplay) == &amp;quot;Enter Keycode.&amp;quot; or guiGetText(keypadLabelDisplay) == &amp;quot;Invalid Keycode.&amp;quot; then&lt;br /&gt;
			updateDisplay()&lt;br /&gt;
		end&lt;br /&gt;
	&lt;br /&gt;
	&lt;br /&gt;
		-- if its the clear button&lt;br /&gt;
		if guiGetText(source) == &amp;quot;Clear&amp;quot; then&lt;br /&gt;
			-- clear the display&lt;br /&gt;
			updateDisplay()&lt;br /&gt;
		&lt;br /&gt;
		-- if its the enter button&lt;br /&gt;
		elseif guiGetText(source) == &amp;quot;Enter&amp;quot; then&lt;br /&gt;
			-- get the currently entered code from the display&lt;br /&gt;
			local code = guiGetText(keypadLabelDisplay)&lt;br /&gt;
			&lt;br /&gt;
			-- if they have entered a code&lt;br /&gt;
			if code then&lt;br /&gt;
				-- trigger the server so we can verify their code&lt;br /&gt;
				triggerServerEvent(&amp;quot;verifyKeypadCode&amp;quot;,getLocalPlayer(),code,keypadID)&lt;br /&gt;
			end&lt;br /&gt;
		&lt;br /&gt;
		-- if its the exit button&lt;br /&gt;
		elseif guiGetText(source) == &amp;quot;Exit&amp;quot; then&lt;br /&gt;
			-- hide the keypad and reset the display text ready for next time&lt;br /&gt;
			guiSetVisible(keypadWindow,false)&lt;br /&gt;
			updateDisplay(&amp;quot;Enter Keycode.&amp;quot;)&lt;br /&gt;
			showCursor(false,false)&lt;br /&gt;
			&lt;br /&gt;
		-- otherwise, it must be a character button&lt;br /&gt;
		else&lt;br /&gt;
			updateDisplay(guiGetText(source))	&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Serverside Verification==&lt;br /&gt;
For this part of the tutorial, you will need to open up a serverside lua file from your resource to work with.&lt;br /&gt;
&lt;br /&gt;
===Defining the keycode===&lt;br /&gt;
Now that we have completed the keypad clicking logic, we need to move on to verifying the code entered into the keypad.&lt;br /&gt;
To do this, we need to have the correct code stored somewhere on the server, which we can check the players code against.&lt;br /&gt;
&lt;br /&gt;
For the purposes of this tutorial we will simply store the code in a serverside table, however it can be done any number of ways (such as serverside xml files or MySQL databases).&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
local keypadCodes = {&lt;br /&gt;
	[&amp;quot;a51MainGateKeypadCode&amp;quot;] = &amp;quot;4455*#&amp;quot;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
This table stores an entry called &amp;quot;a51MainGateKeypadCode&amp;quot; with the code 4455*#&lt;br /&gt;
&lt;br /&gt;
'''This is the keycode that you will use to open the gate later on in this tutorial.'''&lt;br /&gt;
&lt;br /&gt;
===Verifying the code===&lt;br /&gt;
Now that we have a keycode to verify against, we can write our serverside event:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
addEvent(&amp;quot;verifyKeypadCode&amp;quot;,true)&lt;br /&gt;
addEventHandler(&amp;quot;verifyKeypadCode&amp;quot;,root,function(code,keypadID)&lt;br /&gt;
	if code then&lt;br /&gt;
		-- using the table we created earlier, check if the code supplied is the same as the code for this gate&lt;br /&gt;
		if code == keypadCodes[keypadID] then&lt;br /&gt;
			-- if it is, tell the client that it was successful&lt;br /&gt;
			triggerClientEvent(client,&amp;quot;onKeypadVerificationSuccessful&amp;quot;,client,keypadID)&lt;br /&gt;
		else&lt;br /&gt;
			-- if it is not, tell the client that it was not successful&lt;br /&gt;
			triggerClientEvent(client,&amp;quot;onKeypadVerificationFailed&amp;quot;,client,keypadID)&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
end)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Here we use our table and the keypadID supplied by the player to check if the codes match.&lt;br /&gt;
&lt;br /&gt;
If you are not using a table to store the codes, then you will need to replace 'keypadCodes[keypadID]' with your own storage method.&lt;br /&gt;
Once it is verified (or not), we can trigger the client so the appropriate information can be shown on the keypad display.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Receiving the result==&lt;br /&gt;
We have now finished the serverside section of the tutorial, so you will need to open up the clientside lua file from your resource &lt;br /&gt;
that you were previously working on.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Once our code has been verified, the server will send back the response to the client.&lt;br /&gt;
In just the same way as client -&amp;gt; server interaction, we now need to add the event that the server is going to trigger on the client.&lt;br /&gt;
&lt;br /&gt;
===Catching and processing the result===&lt;br /&gt;
First we will add the event for when the verification is successful:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
addEvent(&amp;quot;onKeypadVerificationSuccessful&amp;quot;,true)&lt;br /&gt;
addEventHandler(&amp;quot;onKeypadVerificationSuccessful&amp;quot;,root,&lt;br /&gt;
	function()&lt;br /&gt;
		-- hide the keypad and reset the display text ready for next time&lt;br /&gt;
		guiSetVisible(keypadWindow,false)&lt;br /&gt;
		updateDisplay(&amp;quot;Enter Keycode.&amp;quot;)&lt;br /&gt;
		showCursor(false,false)&lt;br /&gt;
	end&lt;br /&gt;
)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Finally we can add the event for when the verification is unsuccessful:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
addEvent(&amp;quot;onKeypadVerificationFailed&amp;quot;,true)&lt;br /&gt;
addEventHandler(&amp;quot;onKeypadVerificationFailed&amp;quot;,root,&lt;br /&gt;
	function()&lt;br /&gt;
		-- update the display text to show the code was invalid&lt;br /&gt;
		updateDisplay(&amp;quot;Invalid Keycode.&amp;quot;)&lt;br /&gt;
	end&lt;br /&gt;
)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This completes the keypad section of the tutorial.&lt;br /&gt;
&lt;br /&gt;
For an example of how to implement this into a working gate system, carry on reading the next section.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Applying the Keypad==&lt;br /&gt;
For the keypad to have any use, we need something to use it on.&lt;br /&gt;
For this tutorial we will be using gates, and as mentioned earlier we will create a main gate into A51.&lt;br /&gt;
&lt;br /&gt;
===Creating the gate===&lt;br /&gt;
First of all, we need to create the gate object.&lt;br /&gt;
For the purposes of this example, we will be using a map file to store the object. &lt;br /&gt;
While this is the recommended method for defining objects, it is not the only way to approach it.&lt;br /&gt;
&lt;br /&gt;
Navigate to your resource folder and make a new file called gate.map, then add your new map file to your meta.xml using:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;map src=&amp;quot;gate.map&amp;quot;/&amp;gt;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
''If you are unsure of map file syntax, please see the [http://wiki.multitheftauto.com/wiki/Writing_Gamemodes| Writing Gamemodes Tutorial] or check the [[Object]] page for help.''&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;map&amp;gt;&lt;br /&gt;
    &amp;lt;object id=&amp;quot;a51MainGateKeypadCode&amp;quot; model=&amp;quot;971&amp;quot; posX=&amp;quot;96.736&amp;quot; posY=&amp;quot;1918.352&amp;quot; posZ=&amp;quot;20.694&amp;quot; rotX=&amp;quot;0&amp;quot; rotY=&amp;quot;0&amp;quot; rotZ=&amp;quot;270.40&amp;quot; newPosX=&amp;quot;96.751&amp;quot; newPosY=&amp;quot;1914.474&amp;quot; newPosZ=&amp;quot;20.694&amp;quot; /&amp;gt;&lt;br /&gt;
&amp;lt;/map&amp;gt;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
This will create a gate object across the A51 entrance. The object will have position and rotation data, as well as its newPosX,newPosY and newPosZ information that we need to be able to move it.&lt;br /&gt;
&lt;br /&gt;
'''Note that the object id is the same as the table entry we created earlier to hold the access code.'''&lt;br /&gt;
This is one possible method that could be accessed to link this gate with that particular keycode.&lt;br /&gt;
&lt;br /&gt;
===Opening the keypad===&lt;br /&gt;
Back in the clientside lua file again, we can now work on linking the gate and the keypad.&lt;br /&gt;
&lt;br /&gt;
Now that we have our gate, we need a way of accessing the keypad to open it.&lt;br /&gt;
For the purposes of this tutorial we will use a simple command, however you could just as easily use a colshape or button press.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
addCommandHandler(&amp;quot;a51gate&amp;quot;,function()&lt;br /&gt;
	guiSetVisible(keypadWindow,true)&lt;br /&gt;
	showCursor(true,true)&lt;br /&gt;
	setElementData(keypadWindow,&amp;quot;keypadID&amp;quot;,&amp;quot;a51MainGateKeypadCode&amp;quot;)&lt;br /&gt;
end)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Note that we set the element data &amp;quot;keypadID&amp;quot;.&lt;br /&gt;
This is very important because it allows us to keep track of which gate we are trying to open (in this case, the &amp;quot;a51MainGateKeypadCode&amp;quot; gate).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Opening the gate===&lt;br /&gt;
With our gate created and our keypad ready, all thats left now is to open the gate.&lt;br /&gt;
Having created custom events earlier for successfully and unsuccessfully verifying the code, this now becomes very easy to do.&lt;br /&gt;
All we do is add an event handler for our custom &amp;quot;success&amp;quot; event, and using the keypadID we defined earlier we can move the gate inside it:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
addEventHandler(&amp;quot;onKeypadVerificationSuccessful&amp;quot;,root,&lt;br /&gt;
	-- keypadID is sent back from the server&lt;br /&gt;
	function(keypadID)&lt;br /&gt;
		-- get the gate object (this is where the id=&amp;quot;a51MainGateKeypadCode&amp;quot; tag in the map file becomes useful)&lt;br /&gt;
		local gate = getElementByID(keypadID)&lt;br /&gt;
&lt;br /&gt;
		-- if we found the object&lt;br /&gt;
		if gate then&lt;br /&gt;
			-- get the new position (as we defined in the map file)&lt;br /&gt;
			local x = tonumber(getElementData(gate,&amp;quot;newPosX&amp;quot;))&lt;br /&gt;
			local y = tonumber(getElementData(gate,&amp;quot;newPosY&amp;quot;))&lt;br /&gt;
			local z = tonumber(getElementData(gate,&amp;quot;newPosZ&amp;quot;))&lt;br /&gt;
&lt;br /&gt;
			-- move the gate&lt;br /&gt;
			moveObject(gate,1500,x,y,z)&lt;br /&gt;
			&lt;br /&gt;
			-- get the original position&lt;br /&gt;
			x = tonumber(getElementData(gate,&amp;quot;posX&amp;quot;))&lt;br /&gt;
			y = tonumber(getElementData(gate,&amp;quot;posY&amp;quot;))&lt;br /&gt;
			z = tonumber(getElementData(gate,&amp;quot;posZ&amp;quot;))	&lt;br /&gt;
			&lt;br /&gt;
			-- set a timer to close the gate in 5 seconds&lt;br /&gt;
			setTimer(moveObject,5000,1,gate,1500,x,y,z)&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Note how by using the keypadID sent back from the server, we can use if statements and checks against the id to control any number of gates from the same function.&lt;br /&gt;
&lt;br /&gt;
You should now have a working example of a GUI Keypad controlling an A51 Gate.&lt;/div&gt;</summary>
		<author><name>R3mp</name></author>
	</entry>
	<entry>
		<id>https://wiki.multitheftauto.com/index.php?title=Introduction_to_Scripting_the_GUI&amp;diff=22156</id>
		<title>Introduction to Scripting the GUI</title>
		<link rel="alternate" type="text/html" href="https://wiki.multitheftauto.com/index.php?title=Introduction_to_Scripting_the_GUI&amp;diff=22156"/>
		<updated>2010-01-03T02:10:24Z</updated>

		<summary type="html">&lt;p&gt;R3mp: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;!-- place holder --&amp;gt;&lt;br /&gt;
One important feature in MTA:SA is the ability to script customized GUI (Graphic User Interface). The GUI consists of windows, button, edit boxes, check boxes... Almost every standard form components in graphical environments. They can be displayed while the user is in game, and used for inputs and outputs in place of traditional commands. &lt;br /&gt;
&lt;br /&gt;
[[Image:AdminGUI.png|thumb|Admin Console GUI]]&lt;br /&gt;
&lt;br /&gt;
==A tutorial to make a login window==&lt;br /&gt;
In this tutorial we'll make a simple login window, with two input boxes and a button. The window appears when the player joins the game, and once the button is clicked, the player is spawned. The tutorial will continue the gamemode we made in [[Scripting Introduction|Introduction to Scripting]] ''(If you have used the [[Scripting Introduction|Introduction to Scripting]], you will need to remove or comment the [[spawnPlayer]] line in the &amp;quot;joinHandler&amp;quot; function in your code, as we will be replacing it with a gui alternative in this tutorial)''. We'll also take a look at client-side scripting. &lt;br /&gt;
&lt;br /&gt;
===Draw the window===&lt;br /&gt;
All the GUI must be made client side. It is also a good practice to keep all the client scripts in a separate folder. Browse to /Your MTA Server/mods/deathmatch/resources/myserver/ directory, and create a folder named &amp;quot;client&amp;quot;. Under /client/ directory, create a text file and name it &amp;quot;gui.lua&amp;quot;, and in this file we will write a funtion that draws the window:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
function createLoginWindow()&lt;br /&gt;
	-- define the X and Y positions of the window&lt;br /&gt;
	local X = 0.375&lt;br /&gt;
	local Y = 0.375&lt;br /&gt;
	-- define the width and height of the window&lt;br /&gt;
	local Width = 0.25&lt;br /&gt;
	local Height = 0.25&lt;br /&gt;
	-- create the window and save its element value into the variable 'wdwLogin'&lt;br /&gt;
	-- click on the function's name to read its documentation&lt;br /&gt;
	wdwLogin = guiCreateWindow(X, Y, Width, Height, &amp;quot;Please Log In&amp;quot;, true)&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Relative and Absolute===&lt;br /&gt;
Note that the final argument passed to guiCreateWindow in the above example is ''true''. This indicates that the coordinates and dimensions of the window are '''relative''', meaning they are a ''percentage'' of the total screen size. This means that if the far left side of the screen is 0, and the far right is 1, an X position of 0.5 would represent the centre point of the screen. Similarly, if the top of the screen is 0 and the bottom is 1, a Y position of 0.2 would be 20% of the way down the screen. The same principles apply to both Width and Height as well (with a Width value of 0.5 meaning the window will be half as wide as the screen).&lt;br /&gt;
&lt;br /&gt;
The alternative to using relative values is using '''absolute''' (by passing ''false'' instead of true to guiCreateWindow). Absolute values are calculated as the total number of pixels from the top-left corner of the parent (if no gui element parent is specified, the parent is the screen itself). If we assume a screen resolution of 1920x1200, the far left side of the screen being 0 pixels and the far right being 1920 pixels, an X position of 960 will represent the centre point of the screen. Similarly, if the top of the screen is 0 pixels and the bottom is 1200, a Y position of 20 would be 20 pixels down from the top of the screen. The same principles apple to both Width and Height as well (with a Width value of 50 meaning the window will be 50 pixels wide). ''You can use [[guiGetScreenSize]] and a little maths to calculate certain absolute positions.''&lt;br /&gt;
&lt;br /&gt;
The differences between using relative and absolute values is quite simple; gui created using absolute values will always remain exactly the same pixel size and position, while gui created using relative values will always be a percentage of its parent's size.&lt;br /&gt;
&lt;br /&gt;
Absolute is generally easier to maintain when editing code by hand, however your choice of type depends on the situation you are using it for.&lt;br /&gt;
&lt;br /&gt;
For the purposes of this introduction we will be using relative values.&lt;br /&gt;
&lt;br /&gt;
===Adding the components===&lt;br /&gt;
Next, we'll add the text labels (saying &amp;quot;username:&amp;quot; and &amp;quot;password:&amp;quot;), edit boxes (for entering your data) and a button to log in: &lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
function createLoginWindow()&lt;br /&gt;
	local X = 0.375&lt;br /&gt;
	local Y = 0.375&lt;br /&gt;
	local Width = 0.25&lt;br /&gt;
	local Height = 0.25&lt;br /&gt;
	wdwLogin = guiCreateWindow(X, Y, Width, Height, &amp;quot;Please Log In&amp;quot;, true)&lt;br /&gt;
	&lt;br /&gt;
	-- define new X and Y positions for the first label&lt;br /&gt;
	X = 0.0825&lt;br /&gt;
	Y = 0.2&lt;br /&gt;
	-- define new Width and Height values for the first label&lt;br /&gt;
	Width = 0.25&lt;br /&gt;
	Height = 0.25&lt;br /&gt;
	-- create the first label, note the final argument passed is 'wdwLogin' meaning the window&lt;br /&gt;
	-- we created above is the parent of this label (so all the position and size values are now relative to the position of that window)&lt;br /&gt;
	guiCreateLabel(X, Y, Width, Height, &amp;quot;Username&amp;quot;, true, wdwLogin)&lt;br /&gt;
	-- alter the Y value, so the second label is slightly below the first&lt;br /&gt;
	Y = 0.5&lt;br /&gt;
	guiCreateLabel(X, Y, Width, Height, &amp;quot;Password&amp;quot;, true, wdwLogin)&lt;br /&gt;
	&lt;br /&gt;
&lt;br /&gt;
	X = 0.415&lt;br /&gt;
	Y = 0.2&lt;br /&gt;
	Width = 0.5&lt;br /&gt;
	Height = 0.15&lt;br /&gt;
	edtUser = guiCreateEdit(X, Y, Width, Height, &amp;quot;&amp;quot;, true, wdwLogin)&lt;br /&gt;
	Y = 0.5&lt;br /&gt;
	edtPass = guiCreateEdit(X, Y, Width, Height, &amp;quot;&amp;quot;, true, wdwLogin)&lt;br /&gt;
	-- set the maximum character length for the username and password fields to 50&lt;br /&gt;
	guiEditSetMaxLength(edtUser, 50)&lt;br /&gt;
	guiEditSetMaxLength(edtPass, 50)&lt;br /&gt;
	&lt;br /&gt;
	X = 0.415&lt;br /&gt;
	Y = 0.7&lt;br /&gt;
	Width = 0.25&lt;br /&gt;
	Height = 0.2&lt;br /&gt;
	btnLogin = guiCreateButton(X, Y, Width, Height, &amp;quot;Log In&amp;quot;, true, wdwLogin)&lt;br /&gt;
	&lt;br /&gt;
	-- make the window invisible&lt;br /&gt;
	guiSetVisible(wdwLogin, false)&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Note that every GUI component created is a child of the window, this is done by specifying the parent element (wdwLogin, in this case) when creating the component. &lt;br /&gt;
&lt;br /&gt;
This is very useful because not only does it mean that all the components are attached to the window and will move with it, but also that any changes done to the parent window will be applied down the tree to these child components. For example, we can now hide all of the GUI we just created by simply hiding the window:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
guiSetVisible(wdwLogin, false) --hides all the GUI we made so we can show them to the player at the appropriate moment. &lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Using the function we wrote===&lt;br /&gt;
The createLoginWindow function is now complete, but it won't do anything until we call it. It is recommended to create all GUI when the client resource starts, hide them, and show them to the player later when needed. Therefore, we'll write an event handler for &amp;quot;[[onClientResourceStart]]&amp;quot; to create the window:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
-- attach the event handler to the root element of the resource&lt;br /&gt;
-- this means it will only trigger when its own resource is started&lt;br /&gt;
addEventHandler(&amp;quot;onClientResourceStart&amp;quot;, getResourceRootElement(getThisResource()), &lt;br /&gt;
	function ()&lt;br /&gt;
		createLoginWindow()&lt;br /&gt;
	end&lt;br /&gt;
)	&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
As this is a log in window, we now need to show the window when the player joins the game. &lt;br /&gt;
This can be done using the same event, &amp;quot;[[onClientResourceStart]]&amp;quot;, so we can modify the above code to include showing the window:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
addEventHandler(&amp;quot;onClientResourceStart&amp;quot;, getResourceRootElement(getThisResource()), &lt;br /&gt;
	function ()&lt;br /&gt;
		-- create the log in window and its components&lt;br /&gt;
		createLoginWindow()&lt;br /&gt;
&lt;br /&gt;
		-- output a brief welcome message to the player&lt;br /&gt;
                outputChatBox(&amp;quot;Welcome to My MTA:SA Server, please log in.&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
		-- if the GUI was successfully created, then show the GUI to the player&lt;br /&gt;
	        if (wdwLogin ~= nil) then&lt;br /&gt;
			guiSetVisible(wdwLogin, true)&lt;br /&gt;
		else&lt;br /&gt;
			-- if the GUI hasnt been properly created, tell the player&lt;br /&gt;
			outputChatBox(&amp;quot;An unexpected error has occurred and the log in GUI has not been created.&amp;quot;)&lt;br /&gt;
	        end &lt;br /&gt;
&lt;br /&gt;
		-- enable the players cursor (so they can select and click on the components)&lt;br /&gt;
	        showCursor(true)&lt;br /&gt;
		-- set the input focus onto the GUI, allowing players (for example) to press 'T' without the chatbox opening&lt;br /&gt;
	        guiSetInputEnabled(true)&lt;br /&gt;
	end&lt;br /&gt;
)	&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Note that we have a simple security check before making the window visible, so in the unlikely event that the window has not been created, meaning wdwLogin is not a valid element, we don't get an error and just inform the player what has happened. &lt;br /&gt;
In the next step, we will create the button functionality for the log in button.&lt;br /&gt;
&lt;br /&gt;
==Scripting the button==&lt;br /&gt;
Now that we have created our GUI and shown it to the player, we need to make it work. &lt;br /&gt;
&lt;br /&gt;
===Detecting the click===&lt;br /&gt;
When the player clicks on any part of the GUI, the event &amp;quot;[[onClientGUIClick]]&amp;quot; will be triggered for the GUI component you clicked on. This allows us to easily detect any clicks on the GUI elements we want to use.&lt;br /&gt;
For example, we can attach the event to the btnLogin button to catch any clicks on it:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
-- attach the event onClientGUIClick to btnLogin and set it to trigger the 'clientSubmitLogin' function&lt;br /&gt;
addEventHandler(&amp;quot;onClientGUIClick&amp;quot;, btnLogin, clientSubmitLogin, false)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
'''Note the final argument passed is &amp;quot;false&amp;quot;. This indicates that the event will only trigger directly on btnLogin, not if the event has propagated up or down the tree. Setting this to &amp;quot;true&amp;quot; while attaching to gui elements will mean that clicking on any element in the same branch will trigger this event.'''&lt;br /&gt;
&lt;br /&gt;
This line of code can now be added inside the createLoginWindow function. It is a common mistake to try and attach events to non-existant GUI elements, so make sure you always attach your events '''after''' the gui element (in this case, the button) has been created:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
function createLoginWindow()&lt;br /&gt;
	-- create all our GUI elements&lt;br /&gt;
	...&lt;br /&gt;
&lt;br /&gt;
	-- now add our onClientGUIClick event to the button we just created&lt;br /&gt;
	addEventHandler(&amp;quot;onClientGUIClick&amp;quot;, btnLogin, clientSubmitLogin, false)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Managing the click===&lt;br /&gt;
Now that we can detect when the player clicks on the button, we need to write code to manage what happens when they do.&lt;br /&gt;
In our [[onClientGUIClick]] event handle, we told it to call the function clientSubmitLogin whenever btnLogin is clicked.&lt;br /&gt;
Therefore, we can now use the function clientSubmitLogin to control what happens when the button is clicked:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
-- create the function and define the 'button' and 'state' parameters&lt;br /&gt;
-- (these are passed automatically by onClientGUIClick)&lt;br /&gt;
function clientSubmitLogin(button,state)&lt;br /&gt;
	-- if our login button was clicked with the left mouse button, and the state of the mouse button is up&lt;br /&gt;
	if button == &amp;quot;left&amp;quot; and state == &amp;quot;up&amp;quot; then&lt;br /&gt;
		-- move the input focus back onto the game (allowing players to move around, open the chatbox, etc)&lt;br /&gt;
		guiSetInputEnabled(false)&lt;br /&gt;
		-- hide the window and all the components&lt;br /&gt;
		guiSetVisible(wdwLogin, false)&lt;br /&gt;
		-- hide the mouse cursor&lt;br /&gt;
		showCursor(false)&lt;br /&gt;
	end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Now, when the button is clicked, the window will be hidden and all controls will be returned to the player. Next, we will tell the server to allow the player to spawn.&lt;br /&gt;
&lt;br /&gt;
===Triggering the server===&lt;br /&gt;
Triggering the server can be done using [[triggerServerEvent]]. This allows you to trigger a specified event on the server from the client. The same can be done in reverse using [[triggerClientEvent]].&lt;br /&gt;
Here, we use the [[triggerServerEvent]] function to call our own custom event on the server, named &amp;quot;submitLogin&amp;quot;, which will then control the spawning of the player serverside.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
function clientSubmitLogin(button,state)&lt;br /&gt;
	if button == &amp;quot;left&amp;quot; and state == &amp;quot;up&amp;quot; then&lt;br /&gt;
		-- get the text entered in the 'username' field&lt;br /&gt;
		local username = guiGetText(edtUser)&lt;br /&gt;
		-- get the text entered in the 'password' field&lt;br /&gt;
		local password = guiGetText(edtPass)&lt;br /&gt;
&lt;br /&gt;
		-- if the username and password both exist&lt;br /&gt;
		if username and password then&lt;br /&gt;
			-- trigger the server event 'submitLogin' and pass the username and password to it&lt;br /&gt;
			triggerServerEvent(&amp;quot;submitLogin&amp;quot;, getRootElement(), username, password)&lt;br /&gt;
&lt;br /&gt;
			-- hide the gui, hide the cursor and return control to the player&lt;br /&gt;
			guiSetInputEnabled(false)&lt;br /&gt;
			guiSetVisible(wdwLogin, false)&lt;br /&gt;
			showCursor(false)&lt;br /&gt;
		else&lt;br /&gt;
			-- otherwise, output a message to the player, do not trigger the server&lt;br /&gt;
			-- and do not hide the gui&lt;br /&gt;
			outputChatBox(&amp;quot;Please enter a username and password.&amp;quot;)&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Creating the serverside event===&lt;br /&gt;
At this point we now have all the code needed on the client side, so open up your serverside 'script.lua' file (from the [[Scripting Introduction|Introduction to Scripting]]) or another suitable serverside file to work with.&lt;br /&gt;
&lt;br /&gt;
On the server side, recall that we are spawning the player as soon as they login.&lt;br /&gt;
So, first of all, we will need to define the custom event that we used before on the client. This can be done using [[addEvent]] and [[addEventHandler]].&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
-- create our loginHandler function, with username and password parameters (passed from the client gui)&lt;br /&gt;
function loginHandler(username,password)&lt;br /&gt;
&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
-- define our custom event, and allow it to be triggered from the client ('true')&lt;br /&gt;
addEvent(&amp;quot;submitLogin&amp;quot;,true)&lt;br /&gt;
-- add an event handler so that when submitLogin is triggered, the function loginHandler is called&lt;br /&gt;
addEventHandler(&amp;quot;submitLogin&amp;quot;,root,loginHandler)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Logging in===&lt;br /&gt;
Now we have a function that is called through the custom event 'submitLogin', we can start to work on logging in and spawning the player, using our 'loginHandler' function:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
function loginHandler(username,password)&lt;br /&gt;
	-- check that the username and password are correct&lt;br /&gt;
	if username == &amp;quot;user&amp;quot; and password == &amp;quot;apple&amp;quot; then&lt;br /&gt;
		-- the player has successfully logged in, so spawn them&lt;br /&gt;
		if (client) then&lt;br /&gt;
			spawnPlayer(client, 1959.55, -1714.46, 10)&lt;br /&gt;
			fadeCamera(client, true)&lt;br /&gt;
			outputChatBox(&amp;quot;Welcome to My Server.&amp;quot;, client)&lt;br /&gt;
		end&lt;br /&gt;
	else&lt;br /&gt;
		-- if the username or password are not correct, output a message to the player&lt;br /&gt;
		outputChatBox(&amp;quot;Invalid username and password. Please re-connect and try again.&amp;quot;,client)&lt;br /&gt;
        end			&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
addEvent(&amp;quot;submitLogin&amp;quot;,true)&lt;br /&gt;
addEventHandler(&amp;quot;submitLogin&amp;quot;,root,loginHandler)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
'''For the purposes of this tutorial, a very basic username and password system is shown. For a more comprehensive alternative, you can use the Account System or a MySQL database.'''&lt;br /&gt;
&lt;br /&gt;
Also note the use of the variable &amp;quot;client&amp;quot;, it's an internal variable used by MTA to identify the player who triggered the event. &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Finally, do not forget to include the new gui.lua file in the meta.xml of the main resource, and label it as a client script:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;xml&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;script src=&amp;quot;client/gui.lua&amp;quot; type=&amp;quot;client&amp;quot; /&amp;gt;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
At this point, we now have a basic login window that checks the player's username and password when the login button is clicked. If they are correct, the player is automatically spawned.&lt;br /&gt;
&lt;br /&gt;
For further GUI tutorials, see [[Scripting the GUI - Tutorial 1|Scripting the GUI - Tutorial 1 (Gridlists)]]&lt;br /&gt;
&lt;br /&gt;
[[it:Introduzione_allo_scripting_della_GUI]]&lt;br /&gt;
[[ru:Introduction to Scripting the GUI]]&lt;/div&gt;</summary>
		<author><name>R3mp</name></author>
	</entry>
	<entry>
		<id>https://wiki.multitheftauto.com/index.php?title=Scripting_the_GUI_-_Tutorial_1&amp;diff=22155</id>
		<title>Scripting the GUI - Tutorial 1</title>
		<link rel="alternate" type="text/html" href="https://wiki.multitheftauto.com/index.php?title=Scripting_the_GUI_-_Tutorial_1&amp;diff=22155"/>
		<updated>2010-01-03T02:06:05Z</updated>

		<summary type="html">&lt;p&gt;R3mp: Created page with ''''Scripting the Gui - Tutorial 1 (Gridlists)'''  In this tutorial we will explore the use of gridlists in creating a vehicle selection screen, with optional clientside vehicle x…'&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;'''Scripting the Gui - Tutorial 1 (Gridlists)'''&lt;br /&gt;
&lt;br /&gt;
In this tutorial we will explore the use of gridlists in creating a vehicle selection screen, with optional clientside vehicle xml data reading.&lt;br /&gt;
'''Note that this tutorial assumes you are familiar with all the content covered in the [[Introduction to Scripting GUI|Previous tutorial]].'''&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Setting up the Vehicle Selection==&lt;br /&gt;
&lt;br /&gt;
===Creating the GUI===&lt;br /&gt;
To begin, open up a clientside lua file (if you have been following the [[Scripting Introduction]], this is gui.lua) to work with.&lt;br /&gt;
&lt;br /&gt;
In this file, we will start writing our function for creating the GUI.&lt;br /&gt;
As covered in the [[Introduction to Scripting GUI|Previous tutorial]], there are 2 value type options available when creating gui: '''relative''' and '''absolute'''.&lt;br /&gt;
&lt;br /&gt;
For the purposes of this tutorial, we will be using '''absolute''' values.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
This will create a simple GUI with a window, gridlist and button:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
function createVehicleSelection()&lt;br /&gt;
	-- get the screen width and height&lt;br /&gt;
	local sWidth, sHeight = guiGetScreenSize()&lt;br /&gt;
	&lt;br /&gt;
	-- use some simple maths to position the window in the centre of the screen&lt;br /&gt;
	local Width,Height = 376,259&lt;br /&gt;
	local X = (sWidth/2) - (Width/2)&lt;br /&gt;
	local Y = (sHeight/2) - (Height/2)&lt;br /&gt;
	windowVehicleSelection = guiCreateWindow(X,Y,Width,Height,&amp;quot;Vehicle Selection Window&amp;quot;,false)&lt;br /&gt;
	&lt;br /&gt;
	gridlistVehicleSelection = guiCreateGridList(10,26,357,192,false,windowVehicleSelection)&lt;br /&gt;
	-- add a &amp;quot;Vehicle&amp;quot; and a &amp;quot;Type&amp;quot; collumn to the gridlist&lt;br /&gt;
	guiGridListAddColumn(gridlistVehicleSelection,&amp;quot;Vehicle&amp;quot;,0.2)&lt;br /&gt;
	guiGridListAddColumn(gridlistVehicleSelection,&amp;quot;Type&amp;quot;,0.2)&lt;br /&gt;
	&lt;br /&gt;
	-- set the default width of the columns to roughly half the size of the gridlist (each)&lt;br /&gt;
	guiGridListSetColumnWidth(gridlistVehicleSelection,1,0.4,true)&lt;br /&gt;
	guiGridListSetColumnWidth(gridlistVehicleSelection,2,0.5,true)&lt;br /&gt;
	&lt;br /&gt;
	buttonCreate = guiCreateButton(121,227,120,20,&amp;quot;Create&amp;quot;,false,windowVehicleSelection)&lt;br /&gt;
	&lt;br /&gt;
	-- add the event handler for when the button is clicked&lt;br /&gt;
	addEventHandler(&amp;quot;onClientGUIClick&amp;quot;,buttonCreate,createVehicleHandler,false)&lt;br /&gt;
	&lt;br /&gt;
	-- hide the GUI&lt;br /&gt;
	guiSetVisible(windowVehicleSelection,false)&lt;br /&gt;
	&lt;br /&gt;
	-- this will add all the vehicle options onto the gridlist, it is explained later in this tutorial&lt;br /&gt;
	populateGridlist()&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
We now also need to call this function somewhere, otherwise the GUI will never be created.&lt;br /&gt;
As in previous tutorials, to do this we can use [[onClientResourceStart]].&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
-- when the resource is started, create the GUI and hide it&lt;br /&gt;
addEventHandler(&amp;quot;onClientResourceStart&amp;quot;,getResourceRootElement(getThisResource()),&lt;br /&gt;
	function()&lt;br /&gt;
		createVehicleSelection()&lt;br /&gt;
	end&lt;br /&gt;
)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Showing the GUI===&lt;br /&gt;
Unlike in previous tutorials, we want players to be able to open this window whenever they chose, not when the resource starts. &lt;br /&gt;
So, we can add a [[addCommandHandler|Command]] to do this.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
-- create the function that will show the window&lt;br /&gt;
function showVehicleSelection()&lt;br /&gt;
	-- if the window isnt visible, show it&lt;br /&gt;
	if not guiGetVisible(windowVehicleSelection) then&lt;br /&gt;
		guiSetVisible(windowVehicleSelection,true)&lt;br /&gt;
		&lt;br /&gt;
		showCursor(true,true)&lt;br /&gt;
	end&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
-- add the command /vehicleselection and set it to call the showVehicleSelection function&lt;br /&gt;
addCommandHandler(&amp;quot;vehicleselection&amp;quot;,showVehicleSelection)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Populating the Gridlist from a table===&lt;br /&gt;
Now that we have our basic GUI created, we need to fill the gridlist with all of our vehicles.&lt;br /&gt;
&lt;br /&gt;
To begin with, we will do this using a simple clientside table. &lt;br /&gt;
Later in the tutorial, we will explore expanding this method to use .xml files for storing information.&lt;br /&gt;
To begin, we must create a small table containing a selection of vehicles that we can spawn.&lt;br /&gt;
&lt;br /&gt;
The table contains vehicles in the format [&amp;quot;description&amp;quot;] = vehicle_id :&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
-- create the table and fill it with a selection of vehicle ids and names&lt;br /&gt;
local vehicleSelectionTable = {&lt;br /&gt;
	[&amp;quot;Sparrow&amp;quot;] = 469,&lt;br /&gt;
	[&amp;quot;Stuntplane&amp;quot;] = 513,&lt;br /&gt;
	[&amp;quot;BF-400&amp;quot;] = 581,&lt;br /&gt;
	[&amp;quot;Freeway&amp;quot;] = 463,&lt;br /&gt;
	[&amp;quot;Speeder&amp;quot;] = 452,&lt;br /&gt;
	[&amp;quot;Jester&amp;quot;] = 559,&lt;br /&gt;
	[&amp;quot;Sabre&amp;quot;] = 475,&lt;br /&gt;
	[&amp;quot;Police Ranger&amp;quot;] = 599,&lt;br /&gt;
	[&amp;quot;Utility Van&amp;quot;] = 552,&lt;br /&gt;
	[&amp;quot;Tug&amp;quot;] = 583&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Place this code at the very top of your file (it does not need to be inside a function).&lt;br /&gt;
&lt;br /&gt;
Next, we can write our &amp;quot;populateGridlist&amp;quot; function which will fill the Gridlist with all the vehicles in the table.&lt;br /&gt;
To do this we simply need to loop through all the values in the table, adding each one to the gridlist as we go.&lt;br /&gt;
We will also set hidden data using [[guiGridListSetItemData]] to store the vehicle id:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
function populateGridlist()&lt;br /&gt;
	-- loop through the table&lt;br /&gt;
	for name,vehicle in pairs(vehicleSelectionTable) do&lt;br /&gt;
		-- add a new row to the gridlist&lt;br /&gt;
		local row = guiGridListAddRow(gridlistVehicleSelection)&lt;br /&gt;
&lt;br /&gt;
		-- set the text in the first column to the vehicle name&lt;br /&gt;
		guiGridListSetItemText(gridlistVehicleSelection,row,1,name,false,false)&lt;br /&gt;
		-- set the text in the second column to the vehicle type&lt;br /&gt;
		guiGridListSetItemText(gridlistVehicleSelection,row,2,getVehicleType(vehicle),false,false)&lt;br /&gt;
		&lt;br /&gt;
		-- set the data for gridlist slot as the vehicle id&lt;br /&gt;
		guiGridListSetItemData(gridlistVehicleSelection,row,1,tostring(vehicle))&lt;br /&gt;
	end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt; &lt;br /&gt;
&lt;br /&gt;
===Managing the click===&lt;br /&gt;
Now that we have our GUI completed, we need to be able to catch any clicks made on the &amp;quot;create&amp;quot; button.&lt;br /&gt;
We have attached the [[onClientGUIClick]] event to buttonCreate already, so now we need to write the function that it calls.&lt;br /&gt;
In this function we do some basic error checking, such as making sure a vehicle has been selected in the list. &lt;br /&gt;
We can then use some maths to find a position infront of the player and send the server this information to spawn the vehicle (using [[triggerServerEvent]]) &lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
function createVehicleHandler(button,state)&lt;br /&gt;
	if button == &amp;quot;left&amp;quot; and state == &amp;quot;up&amp;quot; then&lt;br /&gt;
		-- get the selected item in the gridlist&lt;br /&gt;
		local row,col = guiGridListGetSelectedItem(gridlistVehicleSelection)&lt;br /&gt;
		&lt;br /&gt;
		-- if something is selected&lt;br /&gt;
		if row and col and row ~= -1 and col ~= -1 then&lt;br /&gt;
			-- get the vehicle id data from the gridlist that is selected&lt;br /&gt;
			local selected = guiGridListGetItemData(gridlistVehicleSelection,row,col)&lt;br /&gt;
			&lt;br /&gt;
			-- make sure the vehicle id is a number not a string&lt;br /&gt;
			selected = tonumber(selected)&lt;br /&gt;
						&lt;br /&gt;
			-- get the players position and rotation&lt;br /&gt;
			local rotz = getPedRotation(getLocalPlayer())&lt;br /&gt;
			local x,y,z = getElementPosition(getLocalPlayer())&lt;br /&gt;
			-- find the position directly infront of the player&lt;br /&gt;
			x = x + ( math.cos ( math.rad ( rotz+90 ) ) * 3)&lt;br /&gt;
			y = y + ( math.sin ( math.rad ( rotz+90 ) ) * 3)&lt;br /&gt;
			&lt;br /&gt;
			if selected and x and y and z then&lt;br /&gt;
				-- trigger the server&lt;br /&gt;
				triggerServerEvent(&amp;quot;createVehicleFromGUI&amp;quot;,getRootElement(),selected,x,y,z)&lt;br /&gt;
				&lt;br /&gt;
				-- hide the gui and the cursor&lt;br /&gt;
				guiSetVisible(windowVehicleSelection,false)&lt;br /&gt;
				showCursor(false,false)&lt;br /&gt;
			else&lt;br /&gt;
				outputChatBox(&amp;quot;Invalid arguments.&amp;quot;)&lt;br /&gt;
			end&lt;br /&gt;
		else&lt;br /&gt;
			-- otherwise, output a message to the player&lt;br /&gt;
			outputChatBox(&amp;quot;Please select a vehicle.&amp;quot;)&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Creating the Vehicle===&lt;br /&gt;
At this point we now have all the code needed on the client side, so open up a serverside .lua file to work with. &lt;br /&gt;
&lt;br /&gt;
On the server side, we will first of all need to define the custom event that we triggered before from the client. This can be done using [[addEvent]] and [[addEventHandler]].&lt;br /&gt;
Finally we will need a small function for creating the vehicle:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
function createMyVehicle(vehicleid,x,y,z)&lt;br /&gt;
	-- check all the arguments exist&lt;br /&gt;
	if vehicleid and x and y and z then&lt;br /&gt;
		createVehicle(vehicleid,x,y,z)&lt;br /&gt;
	end&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
addEvent(&amp;quot;createVehicleFromGUI&amp;quot;,true)&lt;br /&gt;
addEventHandler(&amp;quot;createVehicleFromGUI&amp;quot;,root,createMyVehicle)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Note the use of the &amp;quot;root&amp;quot; variable. This is an MTA variable containing the root element; every resource has one.&lt;br /&gt;
&lt;br /&gt;
This completes the first section of the tutorial. You should now have a basic, working vehicle spawn script.&lt;br /&gt;
&lt;br /&gt;
In the second section, we will cover collapsible gridlist data and clientside xml file reading.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Expanding the code==&lt;br /&gt;
This section will detail several ways to improve upon the code you now have.&lt;br /&gt;
&lt;br /&gt;
===Importing Data===&lt;br /&gt;
One big improvement over the previously mentioned method is to use external files to store the vehicle information, allowing us to much more quickly and easily manage large amounts of data.&lt;br /&gt;
For this tutorial, we will use a clientside xml file to hold the information.&lt;br /&gt;
&lt;br /&gt;
First of all you will need to create your xml file, so navigate to your resources directory and create a new file named vehicles.xml:&lt;br /&gt;
&lt;br /&gt;
''For the purpose of this example, we will include only a small fraction of the total vehicles, however the file can easily be expanded to include them all.''&lt;br /&gt;
&lt;br /&gt;
If you are unsure of xml data structures, you can browse the [http://wiki.multitheftauto.com/wiki/Server_Scripting_Functions#XML_functions| MTA xml functions] for help.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;root&amp;gt;&lt;br /&gt;
	&amp;lt;group type=&amp;quot;Bikes&amp;quot;&amp;gt;&lt;br /&gt;
		&amp;lt;vehicle id=&amp;quot;581&amp;quot; name=&amp;quot;BF-400&amp;quot;/&amp;gt;&lt;br /&gt;
		&amp;lt;vehicle id=&amp;quot;463&amp;quot; name=&amp;quot;Freeway&amp;quot;/&amp;gt;&lt;br /&gt;
		&amp;lt;vehicle id=&amp;quot;481&amp;quot; name=&amp;quot;BMX&amp;quot;/&amp;gt;&lt;br /&gt;
	&amp;lt;/group&amp;gt;&lt;br /&gt;
	&amp;lt;group type=&amp;quot;Boats&amp;quot;&amp;gt;&lt;br /&gt;
		&amp;lt;vehicle id=&amp;quot;472&amp;quot; name=&amp;quot;Coastguard&amp;quot;/&amp;gt;&lt;br /&gt;
		&amp;lt;vehicle id=&amp;quot;452&amp;quot; name=&amp;quot;Speeder&amp;quot;/&amp;gt;&lt;br /&gt;
	&amp;lt;/group&amp;gt;&lt;br /&gt;
	&amp;lt;group type=&amp;quot;Helicopters&amp;quot;&amp;gt;&lt;br /&gt;
		&amp;lt;vehicle id=&amp;quot;487&amp;quot; name=&amp;quot;Maverick&amp;quot;/&amp;gt;&lt;br /&gt;
		&amp;lt;vehicle id=&amp;quot;469&amp;quot; name=&amp;quot;Sparrow&amp;quot;/&amp;gt;	&lt;br /&gt;
	&amp;lt;/group&amp;gt;&lt;br /&gt;
	&amp;lt;group type=&amp;quot;Planes&amp;quot;&amp;gt;&lt;br /&gt;
		&amp;lt;vehicle id=&amp;quot;593&amp;quot; name=&amp;quot;Dodo&amp;quot;/&amp;gt;&lt;br /&gt;
		&amp;lt;vehicle id=&amp;quot;513&amp;quot; name=&amp;quot;Stuntplane&amp;quot;/&amp;gt;	&lt;br /&gt;
	&amp;lt;/group&amp;gt;&lt;br /&gt;
	&amp;lt;group type=&amp;quot;Sports Cars&amp;quot;&amp;gt;&lt;br /&gt;
		&amp;lt;vehicle id=&amp;quot;565&amp;quot; name=&amp;quot;Flash&amp;quot;/&amp;gt;&lt;br /&gt;
		&amp;lt;vehicle id=&amp;quot;559&amp;quot; name=&amp;quot;Jester&amp;quot;/&amp;gt;&lt;br /&gt;
		&amp;lt;vehicle id=&amp;quot;477&amp;quot; name=&amp;quot;ZR-350&amp;quot;/&amp;gt;	&lt;br /&gt;
	&amp;lt;/group&amp;gt;&lt;br /&gt;
	&amp;lt;group type=&amp;quot;2-Door&amp;quot;&amp;gt;&lt;br /&gt;
		&amp;lt;vehicle id=&amp;quot;474&amp;quot; name=&amp;quot;Hermes&amp;quot;/&amp;gt;&lt;br /&gt;
		&amp;lt;vehicle id=&amp;quot;475&amp;quot; name=&amp;quot;Sabre&amp;quot;/&amp;gt;&lt;br /&gt;
	&amp;lt;/group&amp;gt;&lt;br /&gt;
	&amp;lt;group type=&amp;quot;Emergency&amp;quot;&amp;gt;&lt;br /&gt;
		&amp;lt;vehicle id=&amp;quot;416&amp;quot; name=&amp;quot;Ambulance&amp;quot;/&amp;gt;&lt;br /&gt;
		&amp;lt;vehicle id=&amp;quot;599&amp;quot; name=&amp;quot;Police ranger&amp;quot;/&amp;gt;&lt;br /&gt;
	&amp;lt;/group&amp;gt;&lt;br /&gt;
	&amp;lt;group type=&amp;quot;Industrial&amp;quot;&amp;gt;&lt;br /&gt;
		&amp;lt;vehicle id=&amp;quot;573&amp;quot; name=&amp;quot;Dune&amp;quot;/&amp;gt;&lt;br /&gt;
		&amp;lt;vehicle id=&amp;quot;552&amp;quot; name=&amp;quot;Utility van&amp;quot;/&amp;gt;	&lt;br /&gt;
	&amp;lt;/group&amp;gt;&lt;br /&gt;
	&amp;lt;group type=&amp;quot;Misc&amp;quot;&amp;gt;&lt;br /&gt;
		&amp;lt;vehicle id=&amp;quot;457&amp;quot; name=&amp;quot;Caddy&amp;quot;/&amp;gt;&lt;br /&gt;
		&amp;lt;vehicle id=&amp;quot;583&amp;quot; name=&amp;quot;Tug&amp;quot;/&amp;gt;&lt;br /&gt;
	&amp;lt;/group&amp;gt;&lt;br /&gt;
&amp;lt;/root&amp;gt;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Once you have created your file, do not forget to add it to the meta.xml of your resource with the appropriate client tag.&lt;br /&gt;
&lt;br /&gt;
Note the group &amp;quot;type&amp;quot; tag. This is an arbitrary description of the vehicles contained within the group and can be renamed or added as any text.&lt;br /&gt;
Similarly, the vehicle &amp;quot;name&amp;quot; tag is also just a textual description of the vehicle and does not need to be the exact vehicle name.&lt;br /&gt;
&lt;br /&gt;
Now that we have the data, we can import it into the game and display it in the GUI.&lt;br /&gt;
'''If you are following on from the first section of this tutorial, this new code will replace what is inside your existing 'populateGridlist' function.'''&lt;br /&gt;
First, we need to load the file:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
function populateGridlist()&lt;br /&gt;
	-- load the file and save the root node value it returns&lt;br /&gt;
	local rootnode = xmlLoadFile(&amp;quot;vehicles.xml&amp;quot;)&lt;br /&gt;
	&lt;br /&gt;
	-- check that the file exists and has been correctly loaded&lt;br /&gt;
	if rootnode then		&lt;br /&gt;
		-- unload the xml file&lt;br /&gt;
		xmlUnloadFile(rootnode)&lt;br /&gt;
	end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Always make sure you unload any files once you are finished using them.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
We can now start collecting the data from the file and entering it into our gridlist.&lt;br /&gt;
We can do this by looping through the xml data (in a similar manner to looping through the vehicle table earlier in this tutorial) and adding each entry into the list.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
function populateGridlist()&lt;br /&gt;
	local rootnode = xmlLoadFile(&amp;quot;vehicles.xml&amp;quot;)&lt;br /&gt;
	&lt;br /&gt;
	if rootnode then		&lt;br /&gt;
		-- first, we find every &amp;quot;group&amp;quot; node (they are direct children of the root)&lt;br /&gt;
		for _,group in ipairs(xmlNodeGetChildren(rootnode)) do&lt;br /&gt;
			-- add a new row to the gridlist&lt;br /&gt;
			local row = guiGridListAddRow(gridlistVehicleSelection)&lt;br /&gt;
&lt;br /&gt;
			-- get the group name&lt;br /&gt;
			local name = xmlNodeGetAttribute(group,&amp;quot;type&amp;quot;)&lt;br /&gt;
			&lt;br /&gt;
			-- set the text in the first column to the group type and indicate it is a section ('true')&lt;br /&gt;
			-- (sections on gridlists show up in bold and cannot be clicked)&lt;br /&gt;
			guiGridListSetItemText(gridlistVehicleSelection,row,1,name,true,false)			&lt;br /&gt;
		&lt;br /&gt;
			-- then, for every group that we find, loop all of its children (the vehicle nodes)&lt;br /&gt;
			-- and add them into the gridlist&lt;br /&gt;
			for _,vehicle in ipairs(xmlNodeGetChildren(group)) do&lt;br /&gt;
				-- add a new row to the gridlist&lt;br /&gt;
				row = guiGridListAddRow(gridlistVehicleSelection)&lt;br /&gt;
&lt;br /&gt;
				-- get the vehicle name and id&lt;br /&gt;
				name = xmlNodeGetAttribute(vehicle,&amp;quot;name&amp;quot;)&lt;br /&gt;
				local id = xmlNodeGetAttribute(vehicle,&amp;quot;id&amp;quot;)&lt;br /&gt;
				&lt;br /&gt;
				-- set the text in the first column to the vehicle name&lt;br /&gt;
				guiGridListSetItemText(gridlistVehicleSelection,row,1,name,false,false)&lt;br /&gt;
				-- set the text in the second column to the vehicle type&lt;br /&gt;
				guiGridListSetItemText(gridlistVehicleSelection,row,2,getVehicleType(tonumber(id)),false,false)		&lt;br /&gt;
				&lt;br /&gt;
				-- finally, set the vehicle id as data so we can access it later&lt;br /&gt;
				guiGridListSetItemData(gridlistVehicleSelection,row,1,tostring(id))&lt;br /&gt;
			end&lt;br /&gt;
		end	&lt;br /&gt;
	&lt;br /&gt;
		-- unload the xml file now that we are finished&lt;br /&gt;
		xmlUnloadFile(rootnode)&lt;br /&gt;
	end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Note the use of for loops in the code with [[xmlNodeGetChildren]]. This saves us a lot of time and effort as we do not have to manually code each group and vehicle into the list.&lt;br /&gt;
&lt;br /&gt;
You should now have a fully working vehicle selection menu, reading all of its data from a clientside xml file.&lt;br /&gt;
Next, we will examine how to generate the appearance of collapsing and expanding sections in a gridlist.&lt;br /&gt;
&lt;br /&gt;
===Collapsing/Expanding the Gridlist===&lt;br /&gt;
Allowing sections of the gridlist to be collapsed or expanded gives much more control over the visible content to the user.&lt;br /&gt;
This frees up space on the screen and makes the whole menu much more comfortable to use.&lt;br /&gt;
&lt;br /&gt;
===Loading the data===&lt;br /&gt;
To be able to achieve this effect (as it is not a natural feature of gridlists) we will need to load the vehicle information into a table (from the xml file), rather than directly including it all in the gridlist.&lt;br /&gt;
'''If you are following on from a previous section of this tutorial, this new code will replace what is inside your existing 'populateGridlist' function.'''&lt;br /&gt;
&lt;br /&gt;
This works in much the same way the previous xml loading example does, only this time instead of saving the data into the gridlist, we save it into a table entry instead.&lt;br /&gt;
We also set the custom data &amp;quot;header&amp;quot; on the gridlist slots to denote which gridlist entries are our &amp;quot;group&amp;quot; entries and which are vehicles.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
function populateGridlist()&lt;br /&gt;
	local rootnode = xmlLoadFile(&amp;quot;vehicles.xml&amp;quot;)&lt;br /&gt;
	&lt;br /&gt;
	-- create a blank global table to store our imported data&lt;br /&gt;
	vehicleTable = {}&lt;br /&gt;
	&lt;br /&gt;
	if rootnode then		&lt;br /&gt;
		for _,group in ipairs(xmlNodeGetChildren(rootnode)) do&lt;br /&gt;
			-- create an entry in the gridlist for every vehicle &amp;quot;group&amp;quot;&lt;br /&gt;
			local row = guiGridListAddRow(gridlistVehicleSelection)&lt;br /&gt;
&lt;br /&gt;
			local name = xmlNodeGetAttribute(group,&amp;quot;type&amp;quot;)&lt;br /&gt;
			&lt;br /&gt;
			guiGridListSetItemText(gridlistVehicleSelection,row,1,name,false,false)	&lt;br /&gt;
&lt;br /&gt;
			-- add an entry containing the group name into the table&lt;br /&gt;
			vehicleTable[name] = {}&lt;br /&gt;
			&lt;br /&gt;
			-- we will use the custom data &amp;quot;header&amp;quot; to indicate that this entry can be expanded/collapsed&lt;br /&gt;
			guiGridListSetItemData(gridlistVehicleSelection,row,1,&amp;quot;header&amp;quot;)	&lt;br /&gt;
		&lt;br /&gt;
			-- then, for every group that we find, loop all of its children (the vehicle nodes) and store them in a table&lt;br /&gt;
			for _,vehicle in ipairs(xmlNodeGetChildren(group)) do&lt;br /&gt;
				local vname = xmlNodeGetAttribute(vehicle,&amp;quot;name&amp;quot;)&lt;br /&gt;
				local id = xmlNodeGetAttribute(vehicle,&amp;quot;id&amp;quot;)			&lt;br /&gt;
			&lt;br /&gt;
				-- insert both the vehicle id and the vehicle description into the table&lt;br /&gt;
				table.insert(vehicleTable[name],{id,vname})&lt;br /&gt;
			end&lt;br /&gt;
		end	&lt;br /&gt;
	&lt;br /&gt;
		-- set element data on the gridlist so we know which group is currently showing&lt;br /&gt;
		setElementData(gridlistVehicleSelection,&amp;quot;expanded&amp;quot;,&amp;quot;none&amp;quot;)&lt;br /&gt;
	&lt;br /&gt;
		-- unload the xml file now that we are finished&lt;br /&gt;
		xmlUnloadFile(rootnode)&lt;br /&gt;
	end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Now that we have all the data stored, we can quickly manipulate it when neccessary.&lt;br /&gt;
&lt;br /&gt;
===Managing the double click===&lt;br /&gt;
To enable the player to simply double click on a group name to expand/collapse it we need to use the [[onClientGUIDoubleClick]] event.&lt;br /&gt;
If we attach it to the gridlist, we can then catch any double clicks on the group names in it:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
-- attach the onClientGUIDoubleClick event to the gridlist and set it to call processDoubleClick&lt;br /&gt;
addEventHandler(&amp;quot;onClientGUIDoubleClick&amp;quot;,gridlistVehicleSelection,processDoubleClick,false)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Add this line of code in your createVehicleSelection, after the gridlist has been created.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
As the gridlist items are not separate GUI elements, we must capture all clicks from anywhere on the gridlist then process them to filter out the ones we do not want.&lt;br /&gt;
This can be done by checking if an item is selected, then checking if the item is one of our &amp;quot;group&amp;quot; values (using our previously mentioned &amp;quot;header&amp;quot; data):&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
function processDoubleClick(button,state)&lt;br /&gt;
	if button == &amp;quot;left&amp;quot; and state == &amp;quot;up&amp;quot; then&lt;br /&gt;
		local row,col = guiGridListGetSelectedItem(gridlistVehicleSelection)&lt;br /&gt;
		&lt;br /&gt;
		-- if something in the gridlist has been selected&lt;br /&gt;
		if row and col and row ~= -1 and col ~= -1 then		&lt;br /&gt;
			-- if it is a header&lt;br /&gt;
			if guiGridListGetItemData(gridlistVehicleSelection,row,col) == &amp;quot;header&amp;quot; then&lt;br /&gt;
				local selected = guiGridListGetItemText(gridlistVehicleSelection,row,col)&lt;br /&gt;
				&lt;br /&gt;
				-- call the function to collapse or expand the menu and pass which section it is as an argument&lt;br /&gt;
				changeGridlistState(selected)&lt;br /&gt;
			end&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Once we have narrowed down the double clicks to only those done on our group headers, we can expand/collapse them appropriately.&lt;br /&gt;
This can be done by simply setting new text values in the gridlist according to the newly expanded/collapsed group, which creates the convincing illusion of collapsable menus.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Note that much of the following code is reused from previous areas of this tutorial. While it is generally bad practice to clone sections of code in this way, for the purposes of this example it is far easier to understand.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
function changeGridlistState(group)&lt;br /&gt;
	if group then&lt;br /&gt;
		-- if the group is already expanded, we want to collapse it&lt;br /&gt;
		if getElementData(gridlistVehicleSelection,&amp;quot;expanded&amp;quot;) == group then&lt;br /&gt;
			-- first, we clear all previous data from the gridlist&lt;br /&gt;
			guiGridListClear(gridlistVehicleSelection)&lt;br /&gt;
			&lt;br /&gt;
			-- now, loop all the group entries in the vehicle table that we created earlier&lt;br /&gt;
			for group,_ in pairs(vehicleTable) do&lt;br /&gt;
				-- add each group to the list and mark them with &amp;quot;header&amp;quot;			&lt;br /&gt;
				local row = guiGridListAddRow(gridlistVehicleSelection)&lt;br /&gt;
				&lt;br /&gt;
				guiGridListSetItemText(gridlistVehicleSelection,row,1,group,false,false)	&lt;br /&gt;
				guiGridListSetItemData(gridlistVehicleSelection,row,1,&amp;quot;header&amp;quot;)	&lt;br /&gt;
			end&lt;br /&gt;
			&lt;br /&gt;
			-- update the data to indicate that no groups are currently expanded&lt;br /&gt;
			setElementData(gridlistVehicleSelection,&amp;quot;expanded&amp;quot;,&amp;quot;none&amp;quot;)&lt;br /&gt;
			&lt;br /&gt;
		-- otherwise, we want to expand it&lt;br /&gt;
		else&lt;br /&gt;
			guiGridListClear(gridlistVehicleSelection)&lt;br /&gt;
			&lt;br /&gt;
			local row = guiGridListAddRow(gridlistVehicleSelection)&lt;br /&gt;
			&lt;br /&gt;
			guiGridListSetItemText(gridlistVehicleSelection,row,1,group,false,false)	&lt;br /&gt;
			guiGridListSetItemData(gridlistVehicleSelection,row,1,&amp;quot;header&amp;quot;)				&lt;br /&gt;
			&lt;br /&gt;
			-- loop every vehicle in the specified groups table&lt;br /&gt;
			for _,vehicle in ipairs(vehicleTable[group]) do&lt;br /&gt;
				-- add them to the gridlist and set the vehicle id as data&lt;br /&gt;
				row = guiGridListAddRow(gridlistVehicleSelection)&lt;br /&gt;
			&lt;br /&gt;
				-- format a &amp;quot;-&amp;quot; into the string to make it visually easier to distinguish between groups and vehicles&lt;br /&gt;
				guiGridListSetItemText(gridlistVehicleSelection,row,1,&amp;quot;- &amp;quot;..vehicle[2],false,false)	&lt;br /&gt;
				guiGridListSetItemText(gridlistVehicleSelection,row,2,getVehicleType(tonumber(vehicle[1])),false,false)	&lt;br /&gt;
											&lt;br /&gt;
				guiGridListSetItemData(gridlistVehicleSelection,row,1,tostring(vehicle[1]))&lt;br /&gt;
			end	&lt;br /&gt;
&lt;br /&gt;
			-- update the data to indicate which group is currently expanded&lt;br /&gt;
			setElementData(gridlistVehicleSelection,&amp;quot;expanded&amp;quot;,group)			&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This comletes the second section of the tutorial.&lt;/div&gt;</summary>
		<author><name>R3mp</name></author>
	</entry>
	<entry>
		<id>https://wiki.multitheftauto.com/index.php?title=Introduction_to_Scripting_the_GUI&amp;diff=22147</id>
		<title>Introduction to Scripting the GUI</title>
		<link rel="alternate" type="text/html" href="https://wiki.multitheftauto.com/index.php?title=Introduction_to_Scripting_the_GUI&amp;diff=22147"/>
		<updated>2010-01-02T18:15:41Z</updated>

		<summary type="html">&lt;p&gt;R3mp: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;!-- place holder --&amp;gt;&lt;br /&gt;
One important feature in MTA:SA is the ability to script customized GUI (Graphic User Interface). The GUI consists of windows, button, edit boxes, check boxes... Almost every standard form components in graphical environments. They can be displayed while the user is in game, and used for inputs and outputs in place of traditional commands. &lt;br /&gt;
&lt;br /&gt;
[[Image:AdminGUI.png|thumb|Admin Console GUI]]&lt;br /&gt;
&lt;br /&gt;
==A tutorial to make a login window==&lt;br /&gt;
In this tutorial we'll make a simple login window, with two input boxes and a button. The window appears when the player joins the game, and once the button is clicked, the player is spawned. The tutorial will continue the gamemode we made in [[Scripting Introduction|Introduction to Scripting]] ''(If you have used the [[Scripting Introduction|Introduction to Scripting]], you will need to remove or comment the [[spawnPlayer]] line in the &amp;quot;joinHandler&amp;quot; function in your code, as we will be replacing it with a gui alternative in this tutorial)''. We'll also take a look at client-side scripting. &lt;br /&gt;
&lt;br /&gt;
===Draw the window===&lt;br /&gt;
All the GUI must be made client side. It is also a good practice to keep all the client scripts in a separate folder. Browse to /Your MTA Server/mods/deathmatch/resources/myserver/ directory, and create a folder named &amp;quot;client&amp;quot;. Under /client/ directory, create a text file and name it &amp;quot;gui.lua&amp;quot;, and in this file we will write a funtion that draws the window:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
function createLoginWindow()&lt;br /&gt;
	-- define the X and Y positions of the window&lt;br /&gt;
	local X = 0.375&lt;br /&gt;
	local Y = 0.375&lt;br /&gt;
	-- define the width and height of the window&lt;br /&gt;
	local Width = 0.25&lt;br /&gt;
	local Height = 0.25&lt;br /&gt;
	-- create the window and save its element value into the variable 'wdwLogin'&lt;br /&gt;
	-- click on the function's name to read its documentation&lt;br /&gt;
	wdwLogin = guiCreateWindow(X, Y, Width, Height, &amp;quot;Please Log In&amp;quot;, true)&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Relative and Absolute===&lt;br /&gt;
Note that the final argument passed to guiCreateWindow in the above example is ''true''. This indicates that the coordinates and dimensions of the window are '''relative''', meaning they are a ''percentage'' of the total screen size. This means that if the far left side of the screen is 0, and the far right is 1, an X position of 0.5 would represent the centre point of the screen. Similarly, if the top of the screen is 0 and the bottom is 1, a Y position of 0.2 would be 20% of the way down the screen. The same principles apply to both Width and Height as well (with a Width value of 0.5 meaning the window will be half as wide as the screen).&lt;br /&gt;
&lt;br /&gt;
The alternative to using relative values is using '''absolute''' (by passing ''false'' instead of true to guiCreateWindow). Absolute values are calculated as the total number of pixels from the top-left corner of the parent (if no gui element parent is specified, the parent is the screen itself). If we assume a screen resolution of 1920x1200, the far left side of the screen being 0 pixels and the far right being 1920 pixels, an X position of 960 will represent the centre point of the screen. Similarly, if the top of the screen is 0 pixels and the bottom is 1200, a Y position of 20 would be 20 pixels down from the top of the screen. The same principles apple to both Width and Height as well (with a Width value of 50 meaning the window will be 50 pixels wide). ''You can use [[guiGetScreenSize]] and a little maths to calculate certain absolute positions.''&lt;br /&gt;
&lt;br /&gt;
The differences between using relative and absolute values is quite simple; gui created using absolute values will always remain exactly the same pixel size and position, while gui created using relative values will always be a percentage of its parent's size.&lt;br /&gt;
&lt;br /&gt;
Absolute is generally easier to maintain when editing code by hand, however your choice of type depends on the situation you are using it for.&lt;br /&gt;
&lt;br /&gt;
For the purposes of this introduction we will be using relative values.&lt;br /&gt;
&lt;br /&gt;
===Adding the components===&lt;br /&gt;
Next, we'll add the text labels (saying &amp;quot;username:&amp;quot; and &amp;quot;password:&amp;quot;), edit boxes (for entering your data) and a button to log in: &lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
function createLoginWindow()&lt;br /&gt;
	local X = 0.375&lt;br /&gt;
	local Y = 0.375&lt;br /&gt;
	local Width = 0.25&lt;br /&gt;
	local Height = 0.25&lt;br /&gt;
	wdwLogin = guiCreateWindow(X, Y, Width, Height, &amp;quot;Please Log In&amp;quot;, true)&lt;br /&gt;
	&lt;br /&gt;
	-- define new X and Y positions for the first label&lt;br /&gt;
	X = 0.0825&lt;br /&gt;
	Y = 0.2&lt;br /&gt;
	-- define new Width and Height values for the first label&lt;br /&gt;
	Width = 0.25&lt;br /&gt;
	Height = 0.25&lt;br /&gt;
	-- create the first label, note the final argument passed is 'wdwLogin' meaning the window&lt;br /&gt;
	-- we created above is the parent of this label (so all the position and size values are now relative to the position of that window)&lt;br /&gt;
	guiCreateLabel(X, Y, Width, Height, &amp;quot;Username&amp;quot;, true, wdwLogin)&lt;br /&gt;
	-- alter the Y value, so the second label is slightly below the first&lt;br /&gt;
	Y = 0.5&lt;br /&gt;
	guiCreateLabel(X, Y, Width, Height, &amp;quot;Password&amp;quot;, true, wdwLogin)&lt;br /&gt;
	&lt;br /&gt;
&lt;br /&gt;
	X = 0.415&lt;br /&gt;
	Y = 0.2&lt;br /&gt;
	Width = 0.5&lt;br /&gt;
	Height = 0.15&lt;br /&gt;
	edtUser = guiCreateEdit(X, Y, Width, Height, &amp;quot;&amp;quot;, true, wdwLogin)&lt;br /&gt;
	Y = 0.5&lt;br /&gt;
	edtPass = guiCreateEdit(X, Y, Width, Height, &amp;quot;&amp;quot;, true, wdwLogin)&lt;br /&gt;
	-- set the maximum character length for the username and password fields to 50&lt;br /&gt;
	guiEditSetMaxLength(edtUser, 50)&lt;br /&gt;
	guiEditSetMaxLength(edtPass, 50)&lt;br /&gt;
	&lt;br /&gt;
	X = 0.415&lt;br /&gt;
	Y = 0.7&lt;br /&gt;
	Width = 0.25&lt;br /&gt;
	Height = 0.2&lt;br /&gt;
	btnLogin = guiCreateButton(X, Y, Width, Height, &amp;quot;Log In&amp;quot;, true, wdwLogin)&lt;br /&gt;
	&lt;br /&gt;
	-- make the window invisible&lt;br /&gt;
	guiSetVisible(wdwLogin, false)&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Note that every GUI component created is a child of the window, this is done by specifying the parent element (wdwLogin, in this case) when creating the component. &lt;br /&gt;
&lt;br /&gt;
This is very useful because not only does it mean that all the components are attached to the window and will move with it, but also that any changes done to the parent window will be applied down the tree to these child components. For example, we can now hide all of the GUI we just created by simply hiding the window:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
guiSetVisible(wdwLogin, false) --hides all the GUI we made so we can show them to the player at the appropriate moment. &lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Using the function we wrote===&lt;br /&gt;
The createLoginWindow function is now complete, but it won't do anything until we call it. It is recommended to create all GUI when the client resource starts, hide them, and show them to the player later when needed. Therefore, we'll write an event handler for &amp;quot;[[onClientResourceStart]]&amp;quot; to create the window:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
-- attach the event handler to the root element of the resource&lt;br /&gt;
-- this means it will only trigger when its own resource is started&lt;br /&gt;
addEventHandler(&amp;quot;onClientResourceStart&amp;quot;, getResourceRootElement(getThisResource()), &lt;br /&gt;
	function ()&lt;br /&gt;
		createLoginWindow()&lt;br /&gt;
	end&lt;br /&gt;
)	&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
As this is a log in window, we now need to show the window when the player joins the game. &lt;br /&gt;
This can be done using the same event, &amp;quot;[[onClientResourceStart]]&amp;quot;, so we can modify the above code to include showing the window:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
addEventHandler(&amp;quot;onClientResourceStart&amp;quot;, getResourceRootElement(getThisResource()), &lt;br /&gt;
	function ()&lt;br /&gt;
		-- create the log in window and its components&lt;br /&gt;
		createLoginWindow()&lt;br /&gt;
&lt;br /&gt;
		-- output a brief welcome message to the player&lt;br /&gt;
                outputChatBox(&amp;quot;Welcome to My MTA:SA Server, please log in.&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
		-- if the GUI was successfully created, then show the GUI to the player&lt;br /&gt;
	        if (wdwLogin ~= nil) then&lt;br /&gt;
			guiSetVisible(wdwLogin, true)&lt;br /&gt;
		else&lt;br /&gt;
			-- if the GUI hasnt been properly created, tell the player&lt;br /&gt;
			outputChatBox(&amp;quot;An unexpected error has occurred and the log in GUI has not been created.&amp;quot;)&lt;br /&gt;
	        end &lt;br /&gt;
&lt;br /&gt;
		-- enable the players cursor (so they can select and click on the components)&lt;br /&gt;
	        showCursor(true)&lt;br /&gt;
		-- set the input focus onto the GUI, allowing players (for example) to press 'T' without the chatbox opening&lt;br /&gt;
	        guiSetInputEnabled(true)&lt;br /&gt;
	end&lt;br /&gt;
)	&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Note that we have a simple security check before making the window visible, so in the unlikely event that the window has not been created, meaning wdwLogin is not a valid element, we don't get an error and just inform the player what has happened. &lt;br /&gt;
In the next step, we will create the button functionality for the log in button.&lt;br /&gt;
&lt;br /&gt;
==Scripting the button==&lt;br /&gt;
Now that we have created our GUI and shown it to the player, we need to make it work. &lt;br /&gt;
&lt;br /&gt;
===Detecting the click===&lt;br /&gt;
When the player clicks on any part of the GUI, the event &amp;quot;[[onClientGUIClick]]&amp;quot; will be triggered for the GUI component you clicked on. This allows us to easily detect any clicks on the GUI elements we want to use.&lt;br /&gt;
For example, we can attach the event to the btnLogin button to catch any clicks on it:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
-- attach the event onClientGUIClick to btnLogin and set it to trigger the 'clientSubmitLogin' function&lt;br /&gt;
addEventHandler(&amp;quot;onClientGUIClick&amp;quot;, btnLogin, clientSubmitLogin, false)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
'''Note the final argument passed is &amp;quot;false&amp;quot;. This indicates that the event will only trigger directly on btnLogin, not if the event has propagated up or down the tree. Setting this to &amp;quot;true&amp;quot; while attaching to gui elements will mean that clicking on any element in the same branch will trigger this event.'''&lt;br /&gt;
&lt;br /&gt;
This line of code can now be added inside the createLoginWindow function. It is a common mistake to try and attach events to non-existant GUI elements, so make sure you always attach your events '''after''' the gui element (in this case, the button) has been created:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
function createLoginWindow()&lt;br /&gt;
	-- create all our GUI elements&lt;br /&gt;
	...&lt;br /&gt;
&lt;br /&gt;
	-- now add our onClientGUIClick event to the button we just created&lt;br /&gt;
	addEventHandler(&amp;quot;onClientGUIClick&amp;quot;, btnLogin, clientSubmitLogin, false)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Managing the click===&lt;br /&gt;
Now that we can detect when the player clicks on the button, we need to write code to manage what happens when they do.&lt;br /&gt;
In our [[onClientGUIClick]] event handle, we told it to call the function clientSubmitLogin whenever btnLogin is clicked.&lt;br /&gt;
Therefore, we can now use the function clientSubmitLogin to control what happens when the button is clicked:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
-- create the function and define the 'button' and 'state' parameters&lt;br /&gt;
-- (these are passed automatically by onClientGUIClick)&lt;br /&gt;
function clientSubmitLogin(button,state)&lt;br /&gt;
	-- if our login button was clicked with the left mouse button, and the state of the mouse button is up&lt;br /&gt;
	if button == &amp;quot;left&amp;quot; and state == &amp;quot;up&amp;quot; then&lt;br /&gt;
		-- move the input focus back onto the game (allowing players to move around, open the chatbox, etc)&lt;br /&gt;
		guiSetInputEnabled(false)&lt;br /&gt;
		-- hide the window and all the components&lt;br /&gt;
		guiSetVisible(wdwLogin, false)&lt;br /&gt;
		-- hide the mouse cursor&lt;br /&gt;
		showCursor(false)&lt;br /&gt;
	end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Now, when the button is clicked, the window will be hidden and all controls will be returned to the player. Next, we will tell the server to allow the player to spawn.&lt;br /&gt;
&lt;br /&gt;
===Triggering the server===&lt;br /&gt;
Triggering the server can be done using [[triggerServerEvent]]. This allows you to trigger a specified event on the server from the client. The same can be done in reverse using [[triggerClientEvent]].&lt;br /&gt;
Here, we use the [[triggerServerEvent]] function to call our own custom event on the server, named &amp;quot;submitLogin&amp;quot;, which will then control the spawning of the player serverside.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
function clientSubmitLogin(button,state)&lt;br /&gt;
	if button == &amp;quot;left&amp;quot; and state == &amp;quot;up&amp;quot; then&lt;br /&gt;
		-- get the text entered in the 'username' field&lt;br /&gt;
		local username = guiGetText(edtUser)&lt;br /&gt;
		-- get the text entered in the 'password' field&lt;br /&gt;
		local password = guiGetText(edtPass)&lt;br /&gt;
&lt;br /&gt;
		-- if the username and password both exist&lt;br /&gt;
		if username and password then&lt;br /&gt;
			-- trigger the server event 'submitLogin' and pass the username and password to it&lt;br /&gt;
			triggerServerEvent(&amp;quot;submitLogin&amp;quot;, getRootElement(), username, password)&lt;br /&gt;
&lt;br /&gt;
			-- hide the gui, hide the cursor and return control to the player&lt;br /&gt;
			guiSetInputEnabled(false)&lt;br /&gt;
			guiSetVisible(wdwLogin, false)&lt;br /&gt;
			showCursor(false)&lt;br /&gt;
		else&lt;br /&gt;
			-- otherwise, output a message to the player, do not trigger the server&lt;br /&gt;
			-- and do not hide the gui&lt;br /&gt;
			outputChatBox(&amp;quot;Please enter a username and password.&amp;quot;)&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Creating the serverside event===&lt;br /&gt;
At this point we now have all the code needed on the client side, so open up your serverside 'script.lua' file (from the [[Scripting Introduction|Introduction to Scripting]]) or another suitable serverside file to work with.&lt;br /&gt;
&lt;br /&gt;
On the server side, recall that we are spawning the player as soon as they login.&lt;br /&gt;
So, first of all, we will need to define the custom event that we used before on the client. This can be done using [[addEvent]] and [[addEventHandler]].&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
-- create our loginHandler function, with username and password parameters (passed from the client gui)&lt;br /&gt;
function loginHandler(username,password)&lt;br /&gt;
&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
-- define our custom event, and allow it to be triggered from the client ('true')&lt;br /&gt;
addEvent(&amp;quot;submitLogin&amp;quot;,true)&lt;br /&gt;
-- add an event handler so that when submitLogin is triggered, the function loginHandler is called&lt;br /&gt;
addEventHandler(&amp;quot;submitLogin&amp;quot;,root,loginHandler)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Logging in===&lt;br /&gt;
Now we have a function that is called through the custom event 'submitLogin', we can start to work on logging in and spawning the player, using our 'loginHandler' function:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
function loginHandler(username,password)&lt;br /&gt;
	-- check that the username and password are correct&lt;br /&gt;
	if username == &amp;quot;user&amp;quot; and password == &amp;quot;apple&amp;quot; then&lt;br /&gt;
		-- the player has successfully logged in, so spawn them&lt;br /&gt;
		if (client) then&lt;br /&gt;
			spawnPlayer(client, 1959.55, -1714.46, 10)&lt;br /&gt;
			fadeCamera(client, true)&lt;br /&gt;
			outputChatBox(&amp;quot;Welcome to My Server.&amp;quot;, client)&lt;br /&gt;
		end&lt;br /&gt;
	else&lt;br /&gt;
		-- if the username or password are not correct, output a message to the player&lt;br /&gt;
		outputChatBox(&amp;quot;Invalid username and password. Please re-connect and try again.&amp;quot;,client)&lt;br /&gt;
        end			&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
addEvent(&amp;quot;submitLogin&amp;quot;,true)&lt;br /&gt;
addEventHandler(&amp;quot;submitLogin&amp;quot;,root,loginHandler)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
'''For the purposes of this tutorial, a very basic username and password system is shown. For a more comprehensive alternative, you can use the Account System or a MySQL database.'''&lt;br /&gt;
&lt;br /&gt;
Also note the use of the variable &amp;quot;client&amp;quot;, it's an internal variable used by MTA to identify the player who triggered the event. &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Finally, do not forget to include the new gui.lua file in the meta.xml of the main resource, and label it as a client script:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;xml&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;script src=&amp;quot;client/gui.lua&amp;quot; type=&amp;quot;client&amp;quot; /&amp;gt;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
At this point, we now have a basic login window that checks the player's username and password when the login button is clicked. If they are correct, the player is automatically spawned.&lt;br /&gt;
&lt;br /&gt;
[[it:Introduzione_allo_scripting_della_GUI]]&lt;br /&gt;
[[ru:Introduction to Scripting the GUI]]&lt;/div&gt;</summary>
		<author><name>R3mp</name></author>
	</entry>
	<entry>
		<id>https://wiki.multitheftauto.com/index.php?title=Template:Client_ped_functions&amp;diff=21580</id>
		<title>Template:Client ped functions</title>
		<link rel="alternate" type="text/html" href="https://wiki.multitheftauto.com/index.php?title=Template:Client_ped_functions&amp;diff=21580"/>
		<updated>2009-09-23T19:44:38Z</updated>

		<summary type="html">&lt;p&gt;R3mp: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{New feature|3|1.0|&lt;br /&gt;
*[[blendPedAnimation]]&lt;br /&gt;
*[[canPedBeKnockedOffBike]]&lt;br /&gt;
*[[createPed]]&lt;br /&gt;
*[[doesPedHaveJetPack]]&lt;br /&gt;
*[[getPedAmmoInClip]]&lt;br /&gt;
*[[getPedAnimation]]&lt;br /&gt;
*[[getPedAnimationData]]&lt;br /&gt;
*[[getPedArmor]]&lt;br /&gt;
*[[getPedBonePosition]]&lt;br /&gt;
*[[getPedClothes]]&lt;br /&gt;
*[[getPedContactElement]]&lt;br /&gt;
*[[getPedControlState]]&lt;br /&gt;
*[[getPedOccupiedVehicle]]&lt;br /&gt;
*[[getPedRotation]]&lt;br /&gt;
*[[getPedSimplestTask]]&lt;br /&gt;
*[[getPedSkin]]&lt;br /&gt;
*[[getPedStat]]&lt;br /&gt;
*[[getPedTarget]]&lt;br /&gt;
*[[getPedTargetCollision]]&lt;br /&gt;
*[[getPedTargetEnd]]&lt;br /&gt;
*[[getPedTargetRange]]&lt;br /&gt;
*[[getPedTargetStart]]&lt;br /&gt;
*[[getPedTask]]&lt;br /&gt;
*[[getPedTotalAmmo]]&lt;br /&gt;
*[[getPedVoice]]&lt;br /&gt;
*[[getPedWeapon]]&lt;br /&gt;
*[[getPedWeaponMuzzlePosition]]&lt;br /&gt;
*[[getPedWeaponSlot]]&lt;br /&gt;
*[[isPedChoking]]&lt;br /&gt;
*[[isPedDoingGangDriveby]]&lt;br /&gt;
*[[isPedDoingTask]]&lt;br /&gt;
*[[isPedDucked]]&lt;br /&gt;
*[[isPedFrozen]]&lt;br /&gt;
*[[isPedHeadless]]&lt;br /&gt;
*[[isPedInVehicle]]&lt;br /&gt;
*[[isPedInWater]]&lt;br /&gt;
*[[isPedOnFire]]&lt;br /&gt;
*[[isPedOnGround]]&lt;br /&gt;
*[[setPedAimTarget]]&lt;br /&gt;
*[[setPedAnimation]]&lt;br /&gt;
*[[setPedCameraRotation]]&lt;br /&gt;
*[[setPedCanBeKnockedOffBike]]&lt;br /&gt;
*[[setPedControlState]]&lt;br /&gt;
*[[setPedDoingGangDriveby]]&lt;br /&gt;
*[[setPedFrozen]]&lt;br /&gt;
*[[setPedHeadless]]&lt;br /&gt;
*[[setPedLookAt]]&lt;br /&gt;
*[[setPedOnFire]]&lt;br /&gt;
*[[setPedRotation]]&lt;br /&gt;
*[[setPedSkin]]&lt;br /&gt;
*[[setPedVoice]]&lt;br /&gt;
*[[setPedWeaponSlot]]&lt;br /&gt;
}}&lt;/div&gt;</summary>
		<author><name>R3mp</name></author>
	</entry>
	<entry>
		<id>https://wiki.multitheftauto.com/index.php?title=SetPlayerMoney&amp;diff=21577</id>
		<title>SetPlayerMoney</title>
		<link rel="alternate" type="text/html" href="https://wiki.multitheftauto.com/index.php?title=SetPlayerMoney&amp;diff=21577"/>
		<updated>2009-09-22T22:06:14Z</updated>

		<summary type="html">&lt;p&gt;R3mp: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;__NOTOC__&lt;br /&gt;
{{Server client function}}&lt;br /&gt;
Sets a player's money to a certain value, regardless of current player money. It should be noted that setting negative values does not work and in fact gives the player large amounts of money.&lt;br /&gt;
&lt;br /&gt;
==Syntax== &lt;br /&gt;
&amp;lt;section name=&amp;quot;Server&amp;quot; class=&amp;quot;server&amp;quot; show=&amp;quot;true&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
bool setPlayerMoney ( player thePlayer, int amount ) &amp;lt;/syntaxhighlight&amp;gt; &lt;br /&gt;
&lt;br /&gt;
===Required Arguments=== &lt;br /&gt;
*'''thePlayer:''' Which player to set the money of&lt;br /&gt;
*'''amount:''' A whole integer specifying the new amount of money the player will have&lt;br /&gt;
&amp;lt;/section&amp;gt;&lt;br /&gt;
&amp;lt;section name=&amp;quot;Client&amp;quot; class=&amp;quot;client&amp;quot; show=&amp;quot;true&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
bool setPlayerMoney (int amount ) &amp;lt;/syntaxhighlight&amp;gt; &lt;br /&gt;
&lt;br /&gt;
===Required Arguments=== &lt;br /&gt;
*'''amount:''' A whole integer specifying the new amount of money the local player will have&lt;br /&gt;
&amp;lt;/section&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Returns===&lt;br /&gt;
Returns ''true'' if the money was added, or ''false'' if invalid parameters were passed.&lt;br /&gt;
&lt;br /&gt;
==Example==  &lt;br /&gt;
'''Example 1:''' This example sets the player's money to the desired amount when he types &amp;quot;setcash&amp;quot; in console.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
function setCash ( thePlayer, command, amount )       -- when the setcash function is called&lt;br /&gt;
    setPlayerMoney ( thePlayer, tonumber(amount) )    -- change player's money to the desired amount&lt;br /&gt;
end&lt;br /&gt;
addCommandHandler ( &amp;quot;setcash&amp;quot;, setCash )           -- add a command handler for setcash&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
'''Example 2:''' This gives all players the amount of 1337 money when &amp;quot;leet&amp;quot; is typed in console.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
function leetmoney()&lt;br /&gt;
	setPlayerMoney( getRootElement(), 1337 )&lt;br /&gt;
end&lt;br /&gt;
addCommandHandler(&amp;quot;leet&amp;quot;, leetmoney)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==See Also==&lt;br /&gt;
{{Player functions}}&lt;/div&gt;</summary>
		<author><name>R3mp</name></author>
	</entry>
	<entry>
		<id>https://wiki.multitheftauto.com/index.php?title=OnClientColShapeLeave&amp;diff=21227</id>
		<title>OnClientColShapeLeave</title>
		<link rel="alternate" type="text/html" href="https://wiki.multitheftauto.com/index.php?title=OnClientColShapeLeave&amp;diff=21227"/>
		<updated>2009-08-25T02:27:25Z</updated>

		<summary type="html">&lt;p&gt;R3mp: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;__NOTOC__&lt;br /&gt;
{{Client event}}&lt;br /&gt;
This event triggers whenever an element (a player, a vehicle...) leaves a collision shape.&lt;br /&gt;
&lt;br /&gt;
==Parameters==&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
element theElement, bool matchingDimension&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
*'''theElement:''' the element that left the colshape.&lt;br /&gt;
*'''matchingDimension:''' ''true'' if theElement is in the same dimension as the colshape, ''false'' otherwise.&lt;br /&gt;
&lt;br /&gt;
==Source==&lt;br /&gt;
The source of this event is the colshape that the element left.&lt;br /&gt;
&lt;br /&gt;
==Example== &lt;br /&gt;
This example outputs &amp;quot;Out.&amp;quot; to the chatbox whenever a local user leaves a collision shape.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
function onClientColShapeLeave( theElement, matchingDimension )&lt;br /&gt;
    if ( theElement == getLocalPlayer() ) then  -- Checks whether the leaving element is the local player&lt;br /&gt;
        outputChatBox( &amp;quot;Out.&amp;quot; )  --Outputs.&lt;br /&gt;
    end&lt;br /&gt;
end&lt;br /&gt;
addEventHandler(&amp;quot;onClientColShapeLeave&amp;quot;,getRootElement(),onClientColShapeLeave)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==See Also==&lt;br /&gt;
===Client colshape events===&lt;br /&gt;
{{Client_colshape_events}}&lt;br /&gt;
===Client event functions===&lt;br /&gt;
{{Client_event_functions}}&lt;/div&gt;</summary>
		<author><name>R3mp</name></author>
	</entry>
	<entry>
		<id>https://wiki.multitheftauto.com/index.php?title=OnClientColShapeHit&amp;diff=21226</id>
		<title>OnClientColShapeHit</title>
		<link rel="alternate" type="text/html" href="https://wiki.multitheftauto.com/index.php?title=OnClientColShapeHit&amp;diff=21226"/>
		<updated>2009-08-25T02:26:58Z</updated>

		<summary type="html">&lt;p&gt;R3mp: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Client event}}&lt;br /&gt;
__NOTOC__&lt;br /&gt;
This event triggers whenever an element (a player, a vehicle...) enters a collision shape.&lt;br /&gt;
&lt;br /&gt;
==Parameters==&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
element theElement, bool matchingDimension&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
*'''theElement:''' the element that entered the colshape.&lt;br /&gt;
*'''matchingDimension:''' ''true'' if theElement is in the same dimension as the colshape, ''false'' otherwise.&lt;br /&gt;
&lt;br /&gt;
==Source==&lt;br /&gt;
The source of this event is the colshape that was hit.&lt;br /&gt;
&lt;br /&gt;
==Example== &lt;br /&gt;
This example outputs &amp;quot;In.&amp;quot; to the chatbox whenever a local user enters a collision shape.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
function onClientColShapeHit( theElement, matchingDimension )&lt;br /&gt;
    if ( theElement == getLocalPlayer() ) then  -- Checks whether the entering element is the local player&lt;br /&gt;
        outputChatBox( &amp;quot;In.&amp;quot; )  --Outputs.&lt;br /&gt;
    end&lt;br /&gt;
end&lt;br /&gt;
addEventHandler(&amp;quot;onClientColShapeHit&amp;quot;,getRootElement(),onClientColShapeHit)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==See Also==&lt;br /&gt;
===Client colshape events===&lt;br /&gt;
{{Client_colshape_events}}&lt;br /&gt;
===Client event functions===&lt;br /&gt;
{{Client_event_functions}}&lt;/div&gt;</summary>
		<author><name>R3mp</name></author>
	</entry>
</feed>