Signup Now
Results 1 to 10 of 10
  1. #1
    Moderator Leonardo's Avatar
    Join Date
    Dec 2013
    Location
    Brazil
    Posts
    758
    Reputation
    77
    Rep Power
    22

    The Lua Tutorial

    The Lua Tutorial

    Index


    1. Introduction

    1.1. Before you start...
    1.2. The Basics
    1.3. It's Easy!

    2. Values and Types

    2.1 What the hell are those values ?
    2.2 WindBot types.
    2.3 Conditions and Loops.
    2.4 Your first script.

    3. More Advanced!

    2.1 What means more advanced ?
    2.1.1 Creating a Class.
    2.1.2 Function Iteration.
    2.1.3 Recursive Looping.
    2.2 Exclusive Content
    2.2.1 WindBot foreach
    Last edited by Leonardo; 09-01-2014 at 07:51 PM.

  2. #2
    Moderator Leonardo's Avatar
    Join Date
    Dec 2013
    Location
    Brazil
    Posts
    758
    Reputation
    77
    Rep Power
    22
    Introduction

    Well, most of you users already know Lua, it's the language behind Tibia, and helps us developing scripts for Windbot, for those who don't know, this language is responsible for all scripts we have in our forum, it serves as a helper for C programs, however, we won't cover this part.

    This tutorial is directed for people who never heard about programming languages so I'll keep stuff clear as it's your first programming language.

    Before You start...
    Lua is a powerful, fast, lightweight, embeddable scripting language.

    Lua combines simple procedural syntax with powerful data description constructs based on associative arrays and extensible semantics. Lua is dynamically typed, runs by interpreting bytecode for a register-based virtual machine, and has automatic memory management with incremental garbage collection, making it ideal for configuration, scripting, and rapid prototyping.
    This is not very important for scripting, but it's cool if you want to follow the computer science and know what you are dealing with.

    The Basics

    Have you ever know what's a variable ? Well if you didn't, don not worry. It's easy, just imagine an empty refrigerator, you can put food on it, liquids, or even tools if you lost mind, but the same happens with a variable, you can put things on it and remove whenever you want, use them or let them stored.

    This is how you declare a variable:

    my_variable = 'hell yeah'


    The variable 'my_variable' now holds the text "hell yeah". Its type is called string. But how to check a variable type? There's a function for that.

    Input:
    my_variable = 19

    var_type = type(my_variable)

    print(var_type)
    Output:
    #> 'number'

    Yes a number, because that's what 19 is. And that print function is to showing us what we've got. I'll show more stuff:

    Gimme a boolean:

    with_windbot = true

    with_windbot variable is assigned as true.

    Assign a new variable with an old variable:

    do_you_pg = with_windbot

    do_you_pg is assigned as true because with_windbot is a true value.

    Gimme a table:

    my_table = {"A guy opens his door and gets shot and you think that of me?",  "No.",  "I am the one who knocks!"}

    A table filled with text strings, you can put other values in tables, including themselves!

    A local variable:

    Input:
    local Nothing = 'I lied'

    print(Nothing == nil)
    Output:
    #> false -- pretended to put nothing on that variable, but I'm a liar haha

    I've set the local variable Nothing with a value 'I lied', well a local variable cannot be access outside its own scope, it's hard to understand this but let's see another example:

    Input:
    function Lying()
    local Nothing = "LIAR!"
    print(Nothing)
    end

    Lying() -- use my function

    print(Nothing)
    Output:
    #> 'LIAR!' -- printed when I've used the Lying function. 'Nothing' exists!
    #> nil -- Nothing is outside the global scope, it's inside Lying function, therefore can't be accessed

    Those examples covers most of how we set variables to work. The next chapter will show an example of how they work together.

    It's Easy!

    Input:
    function get_forms_areas(A, B, C) -- creates a function and nomeate the values variables they will assign the values later

    -- areas values:
    local triangle = (A * C) / 2
    local circle = 3.14159 * (C * C)
    local trapezium = ((A * C) + (B * C)) / 2
    local square = B * B
    local rectangle = A * B

    local texts = {
    -- creating a ['key'] = value based table, assuming the sentences to keys and areas to values:
    ["The area of the rectangled triangle that has base A and height C:"] = triangle,
    ["The area of the circle of radius C:"] = circle,
    ["The area of the trapezium which has base A and B and C by height:"] = trapezium,
    ["The area of the square that has side B:"] = square,
    ["The area of the rectangle that has sides A and B:"] = rectangle
    }

    table.foreach(texts, print)

    return -- we did our first script now let's break
    end

    get_forms_areas(2, 3, 4)


    Output:
    The area of the circle of radius C:    50.26544
    The area of the rectangled triangle that has base A and height C: 4
    The area of the trapezium which has base A and B and C by height: 10
    The area of the rectangle that has sides A and B: 6
    The area of the square that has side B: 9


    Whoa!! What happened here ??

    We created a serie of mathematical calculations and sent the result as the output, using a function created just for it. The function can be created once, and whenever we need it, all we need to do is call its name, on the example get_forms_areas, also when using functions they can accept internal values or not, in this example the internal values are A, B and C, which can be set after the function call. After the calculations the results were stored on a table and then printed out. The output for that example is right down:
    Last edited by Leonardo; 04-05-2014 at 12:54 AM.

  3. #3
    Moderator Leonardo's Avatar
    Join Date
    Dec 2013
    Location
    Brazil
    Posts
    758
    Reputation
    77
    Rep Power
    22
    Values and Types


    What the hell are those values ?

    Basically there are 6 potential types in Lua, they are listed down, with a quick list of features for each one:


    Number

    • This type can hold various number values: 1, 15.0, 25.5.
    • You can compare them with other number vars using operators: <, >, <=, >=, == and ~= (respectively, less than, higher than, less equal than, higher equal than, equal to, different from), returning true or false for the operation.
    • You can do calculations with them using other operators such as: -. +, /, * and % (respectively, minus, plus, divided, multiplied and rest of division).
    • You can index a part of a table or string using it, for example on a table that hold 5 values, if I wanted to access the 3rd value, I would index it by using: MyTable[3].


    String

    • This type can hold any alpha-numeric characters: "abcdef", "123abc", "dafuqisthis{[()]}".
    • You can compare them with other string vars using operators <, >, <=, >=, == and ~=, returning true or false for the operation, BUT you can't compare a string that way with other type.
    • Different from numbers, you can't use mathematical operators on strings, that will raise an error, so forget this operators for strings: +, -, /, * and %.
    • You can index part of a string using a number, in that case you'll use a function from the string library, for example: string.sub("WindBot", 1, 4) will return the characters 1 to 4 on the string, in that case "Wind".



    Table

    • This is a special type in Lua, in can hold the other types inside of it, creating a list of items, it can hold a table element aswell: {{"a", "b", "c"}, {1, 2, 3}, {{}, {}, {}}, true}.
    • Different from strings and numbers, there's not any operator that can be used with it, with exception of the # (sharp) character, using it on the front of a table will return its size, for example #{1, 2, 3, "a", "b", "c"} would return 6, because there are 6 elements on the table. Key-Value elements are not counted, like {["key"] = 10}.
    • You can loop trough the table items more easily than the other types, there are 3 types of function loops that we can use: pairs(), ipairs() and key indexing.


    Boolean

    • This kind contains only 2 possible values: true or false.
    • They are the most basic conditions in any programming language, every comparation you do, creates a boolean value wheter is true or false. Remember: conditionals consider false and nil as false and anything else as true.
    • You can compare them using "==" or by statements (var = true; if var then ...).


    Functions

    • This is probably the most used type. Functions may return anything else listed above, acting with arguments given inside brackets and resulting on something or just executing some action.
    • Functions are always come with brackets, inside them is where is located arguments if there are any. Example: print("hello world", "heavy breathing..", "bye world")


    Nil

    • Nil is equal to nothing or null, non existent. It's used to kill a variable, when you assing a variable to a nil value, or to check if some variable exists.
    • Both nil and false values are taken as false on a statement, but beware comparing these values using "==", that would just check if it's really equal to nil/false and not both of them as false.


    WindBot Types

    Among other Lua types there's some exclusive in WindBot, also called pointers:


    WindBot Pointers

    • This type is similar to a table, it holds information about something and should be indexed for the value we want, for example, creature pointer hppc (creature.hppc) would return the health percent of a creature.
    • Some functions accept this type as a parameter, like attack can receive a creature name, ID or pointer for a creature type.
    • In WindBot, indexing a pointer with a non existent member of its type will trigger an error, saying it wasn't found. To know if the type has a specific index, use the hasproperty index.
    • All the types can be found in the sub section Types, in the documentation page.


    Conditions and Loops

    Now that you have knowledge about types, let's see how conditions and loops work:

    Input:
    -- A do block provides scoping
    do
    local foo = 'Hello'
    print('Inside the do block, foo is: ', foo)
    end

    print('Outside the do block, foo is: ', foo)




    -- if then else

    local kittens = 1

    if kittens > 0 then print('You have kitten(s)') end

    if kittens == 0 then
    print('You have no kittens')
    elseif kittens == 1 then
    print('You have a kitten')
    else
    print('You have many kittens')
    end



    -- while

    local kittens = { 'Mr Tibbs', 'Tufty', 'Kipper' }

    while #kittens > 0 do
    local kitten = table.remove(kittens, 1)
    print(kitten)
    end




    -- repeat until

    local kittens = { 'Mr Tibbs', 'Tufty', 'Kipper' }

    repeat
    local kitten = table.remove(kittens, 1)
    print(kitten)
    until #kittens == 0




    -- break

    local kittens = { 'Mr Tibbs', 'Tufty', 'Kipper' }

    while #kittens > 0 do
    local kitten = table.remove(kittens, 1)
    if kitten == 'Tufty' then break end
    print(kitten)
    end




    -- numeric for

    for i = 1, 10 do -- count up
    print(i..' banana')
    end

    for i = 10, 1, -1 do -- count down
    print(i..' green bottles')
    end

    print('i is scoped to the for loop: ', i)




    -- generic for

    local random = { 'boot', foo = 'bar', 22 }

    for key, val in ipairs(random) do -- ipairs iterates over numerical indexed elements only.
    print(key, val)
    end

    for key, val in pairs(random) do -- pairs iterates over all elements.
    print(key, val)
    end
    Output:
    Inside the do block, foo is: 	Hello
    Outside the do block, foo is: nil
    You have kitten(s)
    You have a kitten
    Mr Tibbs
    Tufty
    Kipper
    Mr Tibbs
    Tufty
    Kipper
    Mr Tibbs
    1 banana
    2 banana
    3 banana
    4 banana
    5 banana
    6 banana
    7 banana
    8 banana
    9 banana
    10 banana
    10 green bottles
    9 green bottles
    8 green bottles
    7 green bottles
    6 green bottles
    5 green bottles
    4 green bottles
    3 green bottles
    2 green bottles
    1 green bottles
    i is scoped to the for loop: nil
    1 boot
    2 22
    1 boot
    2 22
    foo bar
    (Example took from moonshinejs.org/examples)

    Ok, there's more than you've had learned on the lesson, but try to figure out what each line is and what they represent as an output. I'll be covering control statements soon.

    Your first script

    Instead of downloading Lua, you'll use an online editor and compiler, which you can easily use to write any code that don't need Windbot functions. Use the link down and go for it, just wait a little after you open it to make sure it opened correctly.

    Moonshine Lua Editor
    Moonshine Usage Manual
    Last edited by Leonardo; 09-01-2014 at 02:21 PM.

  4. #4
    Moderator Leonardo's Avatar
    Join Date
    Dec 2013
    Location
    Brazil
    Posts
    758
    Reputation
    77
    Rep Power
    22
    More Advanced!


    What means advanced ?
    It means now we're going to have all the stuff learnt in the past chapters mixed with WindBot and some new tricks.


    Creating a Class
    This one could be hard but it's an important tool in some cases, and it also should be easier to use.

    Input:
    MyClass = {} -- a table
    MyClass.__index = MyClass -- this is necessary for classes
    -- as it enables the methods for it

    -- setting the definition of each function for our new class
    -- this function just create our class and return it
    function MyClass.New()
    return setmetatable({
    --scriptversion = '',
    }, MyClass)
    end

    -- this function gives our script a version
    function MyClass:setVersion(str)
    self.scriptversion = str
    end

    -- this function returns our script version or an empty string if it wasn't created yet
    function MyClass:getVersion()
    return self.scriptversion
    end

    -- now let's use our simple functions

    local Script = MyClass.New()
    -- instead of MyClass.Function() we can now index as Script.Function()

    print(Script:getVersion())
    -- why use : you should be guessing, we'll talk about that later

    Script:setVersion("1.2.0")

    print(Script:getVersion())
    Output:
    nil
    1.2.0

    But how does that work ? It's not so simple as anything we saw before, anyway, it's not so complicated.

    This is called methamod tables, they have a different behaviour than the common tables.

    We're first creating a class function, called New, using the setmetatable function.

    That will return our class as a pack and insert into a new variable in the future. Then we're creating the other functions getVersion and setVersion, the last being used to give our class a version, the other used to pick and return the version.

    When using metaclasses we can also index using the ":" symbol, because the class was inserted into our variable before, so we can't use MyClass.Function() anymore, that would just return the default value.

    There are some good examples for classes in some of the libraries in WindBot, sirmate's library is fully made in Classes, also Raphael's library is partially made of classes (HUD and JSON classes). Other examples are the basic classes in Lua, string, math and io.


    Function Iteration
    This is usually used to create a loop like ipairs/pairs functions, but in other environments.

    Input:
    -- copied from Leonardo's library (very edited)

    -- first declare our function
    function screentiles()
    local Positions = {}

    for x = -7, 7 do
    for y = -5, 5 do
    local _x, _y = $posx + x, $posy + y

    if tilehasinfo(_x, _y, $posz) then
    table.insert(Positions, {_x, _y, $posz})
    end
    end
    end

    -- this is what we want
    local i = 0
    return function()
    i = i + 1

    if Positions[i] then
    return Positions[i][1], Positions[i][2], Positions[i][3]
    end

    return
    end
    end

    -- using our new loop
    for x, y, z in screentiles() do
    addwaypoint(x, y, z, "stand")
    end
    Output:
    -- no output

    This will add a stand waypoint for all the positions visible on your screen. How does that loop work ?

    First we do a loop, inside the function, and get all the positions axis and store them in the var Positions. Then we start a numeric loop using a function, this is possible in Lua, because the interpreter will run this as a loop and not a function that is called and used. We use the i value to index the table, returning our 3 positions axis, x/y/z, then all we need to do is return them.


    Recursive Looping
    This is called recursive, because we call the function we're creating inside itself in determined situations. This makes the script shorter than using other iteration.

    Input:
    local timenow = os.clock()

    function factorial(num)
    return num > 1 and factorial(num - 1) * num or 1
    end


    print("Recursive way: " .. factorial(11))
    print("Took " .. os.clock() - timenow .. " ms to run.")
    -- common loop way

    local timenow = os.clock()
    local result = 1

    for i = 2, 11 do
    result = result * i
    end

    print("Loop way: " .. result)
    print("Took " .. os.clock() - timenow .. " ms to run.")

    -- actually is pretty hard to benchmark lua scripts as they run fast, so the results for this script are 0
    Output:
    Recursive way: 39916800
    Took 0 ms to run.
    Loop way: 39916800
    Took 0 ms to run.

    Recursive loops could be usefull but it doesn't run faster than common iteration in Lua, in some other languages it's slower or faster, depending on the environment. However it's shorter (assuming that the recursive function is already implemented).

    Exclusive Content
    The next stuff are similar to what we've seen before but it's exclusively to WindBot.


    WindBot foreach
    This is used to loop between some variables, unlike table.foreach, this can only receive specific variables to loop for, while the other is used to loop between any table, however they have the same engine. And sometimes there's a parameter to filter results.

    Input:
    foreach creature cre "ps" do
    if cre.name ~= $name then
    while paround(cre.name) > 0 do
    beep()
    wait(500)
    end
    end
    end
    Output:
    -- no output

    This is a simple code to alarm if some player is in your screen, using foreach together with creature will loop over creatures with the given filter, this filter is "ps". In this specific case, "ps" is used to find players visible on screen. The creature in each loop round will be stored at the var cre, this cre is a creature type variable (check Chapter 2: WindBot Types for more info).

    This example shows how to deal with foreach creature, but you can also use for other types, for a complete list check the documentation Iterators section.
    Last edited by Leonardo; 09-02-2014 at 12:00 PM.

  5. #5
    Moderator Leonardo's Avatar
    Join Date
    Dec 2013
    Location
    Brazil
    Posts
    758
    Reputation
    77
    Rep Power
    22
    Well, this tutorial was stopped for a long time and now I'll be back on it again. But to let you try some of the stuff that are included on this tutorial, I'll be posting parts of it until I can finish.

    If you have some doubt relationed with it, don't be shy and ask for it.

  6. #6
    Moderator mistgun's Avatar
    Join Date
    Dec 2013
    Location
    Lodz, Poland
    Posts
    1,821
    Reputation
    220
    Rep Power
    26
    I just waited for this bro, greatest tutorial! Great job

  7. #7
    Wind Tester
    Join Date
    Dec 2013
    Location
    Warsaw, Poland
    Posts
    2,578
    Reputation
    149
    Rep Power
    27
    So basic stuff, but i hope it will help out people on forum. Guys, with this tutorial you have no excuse that you dont know what programming is and you cant start making scripts ; )

  8. #8
    Free User Jesusz0r's Avatar
    Join Date
    Dec 2013
    Location
    Spain
    Posts
    278
    Reputation
    70
    Rep Power
    21
    Looking forward to this!!

  9. #9
    Moderator Leonardo's Avatar
    Join Date
    Dec 2013
    Location
    Brazil
    Posts
    758
    Reputation
    77
    Rep Power
    22
    Added the second chapter of the tutorial.

  10. #10
    Moderator Dehan's Avatar
    Join Date
    Dec 2013
    Posts
    1,404
    Reputation
    315
    Rep Power
    26
    wow he added the "Most Advanced" cheapter!

    Nice Job buddy!

    Level Latest Scripts by Dehan
    250+
    [EK & ED & MS & RP] [Navigation] Prison -1
    200+
    [EK & ED & MS] [Navigation] Asura Palace
    200+
    [EK & ED] [Navigation] Lower Roshamuul Softcore

 

 

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •