Jump to content

The ultimate Lua tutorial


Recommended Posts

Good tutorial but maybe you should explain how you can use tables more efficiently, many people store simple information that's only used within the resource itself by using setElementData and getElementData when it can simply be used with a table and if you want to use it outside the resource you can use a simple export to return the table :)

Yes, I have noticed that with new scripters, lol. I'll go back later and add a "Table Efficiency" section :P

Link to comment

Update - Added commands!

Commands

Good, you've made it this far, you have what it takes to be a successful scripter, without a doubt!

Now, I'm sure you want to learn how to add commands, because they're fast and easy to both create and execute. To add a command, you just stimply need to use the function <em>addCommandHandler</em>. Simple as that, just throw in your command name and the callback function! Here, let's get you started to just make a simple /kill command.

addCommandHandler ( "kill", function ( player ) 
    killPed ( player ) 
end ) 

Now, as you see in the code before, the player who executed the command is NOT source as many new people to scripting MTA might think, don't be ashamed though, that's exactly what I thought when I first used the function. The player, the one who executed the command will be defined to the first argument of the callback function, so in my little /kill command script, it just set the player to the variable player (go figure lol). So, now let's build a bit of a more advanced command to do /spawn INT and where INT is, you can enter a number and it'll spawn a vehicle to you. Let's get started!!

function callbackFunct ( player, command, arg1 ) 
    if ( not arg1 or not tonumber ( arg1 ) ) then 
        outputChatBox ( "The correct syntax for /"..tostring(command).." is /"..tostring(command).." [integer from 400 to 611]", player, 255, 0, 0 ) 
        return false 
    end 
  
    -- Now we know he has a vehicle ID (arg1) and it's an integer, now we need to check if it's between 400 and 611. 
    local arg1 = math.floor ( tonumber ( arg1 ) ) -- Let's convert and round it, to prevent "code-buggers" 
    if ( arg1 > 400 and arg < 611 ) then  
        local x, y, z = getElementPosition ( player ) 
        local _, _, rz = getElementRotation ( player ) 
        local veh = createVehicle ( arg1, x, y, z, 0, 0, rz ) 
        warpPedIntoVehicle ( player, veh ) 
        outputChatBox ( "You have created a vehicle!", player, 0, 255, 0 ) 
    else 
        outputChatBox ( "Invalid vehicle number. Valid: 400-611", player, 255, 0, 0 ) 
    end 
end 
addCommandHandler ( "spawn", callbackFunct ) 

As you can see in the code above, it's pretty straight forward. When you enter the command /spawn it'll run the callbackFunct function. arg1 will be set to the first argument that the player gives in the command. (This: /spawn arg1) arg1 will be set to the value that the user gives. First the function will check to see if the argument exists, and if it does, or the argument cannot be converted to a number then it will output a simple syntax error and stop the function with return. If arg1 exists, and it can be converted to a number, then the code will take the value, convert it to a number, then round it to the lowest number if it's a decimal. After that, it checks if the number is a valid vehicle ID, and if it isn't then it just outputs a basic error saying it's invalid. If it is a valid number, it'll get the players position and rotation, then create a vehicle in the position and set the rotation Z axis to the players, then warp the player in and output a message.

addCommandHandler

Link to comment
  • 1 month later...

Update -

Added the exports section, the tutorial is now complete!

Exports

What an export is

You might be asking yourself, what is an export? Well, when you create a function, if it's global or a local function, MTA will make it only accessable by your resource. When you try to call the function in another resource, it'll say that it is undefined. An export gives you the ability to call a function that is contained in another resource. For example, in my resource TopBarChat (It's horrible English, I know) I made the function sendClientMessage exported, so it can be used in any resource. Now, it's actually very easy to add an export, it's all about the meta. You just need an tag, with an attribute function which is equal to the function that you want to export, and an optional attribute type which tells whether it's a server or client function, server by default. There's some other attributes, however i'm not going to get into them because they're more for web-based applications.

Creating an export

Let's say I have a resource named messages and it contains a function outputMessage with the arguments:


  • - msg - A string of the message
    - player - The player element to output to
    - r - the R color from RGB
    - g - the G color from RGB
    - b - the B color from RGB

So, in the messages resource, let's go head and create the server-side function.

-- message_server.lua 
function message ( message_, player, r, g, b ) 
    if ( not msg ) then return false; end 
    if ( player and not isElement ( player ) ) then return false; end 
    if ( not player ) then player = getRootElement ( ); end 
    if ( not r ) then r = 255; end  
    if ( not g ) then g = 255; end  
    if ( not b ) then b = 255; end  
     
    outputChatBox ( "[*message-system] ".. message_, player, r, g, b ) 
end 

Now that the function is created, we need to create the meta.

  
<meta> 
    <info author="xXMADEXx" name="Message-System" version="1.0" type="script" /> 
    <script src="message_server.lua" type="server" /> 
</meta> 

Now that we have our meta, we need to add the following line to export the function into other resources.

<export function="message" type="server" /> 

Basically, the export line in the meta adds the function to a table called exports under the index of the resource name. Pretty basic right? Here is a basic diagram of the exports table:

1AMv4ZW.png

Calling the export

Say we have another resource, and we want to call the message function that is exported in the messages resource. All you have to do is call the exports -> resource -> function_name. Here's what it would look like for the messages resource and the function message function:

  
--Method 1 (Method I use) 
exports["messages"]:message ( "You were selected!", getRandomPlayer ( ), 0, 255, 0 ) 
--       resource   -- function         -- function arguments 
  
-- Method 2 (Different style than Method 1) 
exports.messages:message ( "You were selected!", getRandomPlayer ( ), 0, 255, 0 ) 
--       resource   -- function         -- function arguments 
  
-- Method 3 (Using the call function) 
call ( getResourceFromName ( "messages" ), "message", "You were selected!", getRandomPlayer ( ), 0, 255, 0 ) 
--     Resource (as [i]resource[/i] type)   function    function arguments 
  

The main reason I never use method 3 is because it's easier to get confused, and it takes longer to type. I typically do method 1, but sometimes method 2.

Link to comment
  • 2 weeks later...
Good tutorial but maybe you should explain how you can use tables more efficiently, many people store simple information that's only used within the resource itself by using setElementData and getElementData when it can simply be used with a table and if you want to use it outside the resource you can use a simple export to return the table :)

would be very nice if this tutorial topic had this as well

Link to comment
  • 3 weeks later...
  • 3 weeks later...
  • 2 weeks later...
  • 1 month later...

One bug i noticed is in The "Commands" section, in the "callbackFunct" Line 9, You get "attempt to compare nil with number",

it should be like this

if ( arg1 > 400 and arg1 < 611 ) then 

This is a great tutorial, but i wanted to take into notice this little problem, because most newbie scripters will not notice this.

I'm out.

Link to comment
One bug i noticed is in The "Commands" section, in the "callbackFunct" Line 9, You get "attempt to compare nil with number",

it should be like this

if ( arg1 > 400 and arg1 < 611 ) then 

This is a great tutorial, but i wanted to take into notice this little problem, because most newbie scripters will not notice this.

I'm out.

Thanks, I fixed the code.

Link to comment
  • 1 month later...
It might be worth making your tutorial make use of the predefined variables in MTA, such as 'root' and 'resourceRoot'. The amount of times I've seen people use getResourceRootElement(getThisResource()), when you can just use 'resourceRoot'. The same for getRootElement() and 'root'.

Thanks for the feedback.

I thought that this was a good idea, because I see this too lol. I added a section for it in the "General Lua" category, but i'ts pretty short because I wasn't too sure of what to put it in it.

Link to comment
  • 4 months later...
  • 2 years later...
  • 3 weeks later...

Hi,

Firstly, this tutorial is very good and really important for beginners. It can be developed, too. BTW, in Formatting Your Code section, you made a little mistake but it can confuse minds for beginners:

...
if (arg1 > arg2) then
	while ( arg1 > arg2 ) do  
		arg2 = arg2 + 1 
	end
...

Here, the arg1 variable already bigger than arg2. So, when this statement is true, while loop will start and one time it'll add 1 to arg2 variable. Then this loop ends... So that's correct:

...
if (arg1 > arg2) then
	while ( arg2 > arg1 ) do  
		arg2 = arg2 + 1 
	end
...

 

Thanks for this tutorial...

I hope that it is useful for beginners. (:

Link to comment
  • Recently Browsing   0 members

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