Taslem Scripting Tutorial

From Legacy Roblox Wiki
Jump to navigationJump to search


How to script

Scripting can be confusing or difficult for people who don't understand what they're doing. Many tutorials give free code or start with topics that are irrelevant to becoming an ADVANCED or expert scripter, and instead let them only learn the basics, so they fail to understand errors they recieve and don't know how to write code from scratch.

I'm here to correct that malady.

Even if you think you already know a section, don't skip it, because there's always important info that you've never heard before if you've read the most common tutorials.


Computer

What is a computer?

Computers are machines that reads data about its environment, mainly through the mouse or keyboards, and perform calculations.

Computers process by reading pieces of data, then changing its "memory" and advancing.

So where does Lua come in?

Because the basic instructions that computers run on are tedious to write out and plainly difficult to understand, smart computer designers created higher-level programming languages. Higher-level programming languages simply act (slightly) more like English (or any human language, for that matter) so they are easier for us to write and understand. Lua is a prime example of a very high-level language. When scripting in Lua, the computer encodes it down and down and down into "machine language" where the computer processes it.

Programming Languages

Imperative vs. functional

This section will bore most of you, but it's neccesary. When I talk about programming for the rest of this tutorial, it will be strictly imperative, unless where I say separate (which you won't notice at all, if you're not versed in functional languages.) I am actually in favor of functional languages versus imperative ones, however, for the scope of this lesson, I am going to speak about imperative languages, because Lua is much more imperative that functional. If that flew right over your head, that's fine. Just read the next section. This section is simply to get die-hard Haskellers or LISPers to not attack me in the night.

Variables

Variables are an essential part of programming. A variable is basically a tag that point to two things: a name, and a value.

NAMES: A variable's name can be anything,really. However, it may only contain a-z, A-Z, 0-9 and the _ key. Spaces are PROHIBITED. And, CAPS DOES MATTER. A variable with name "a" is NOT the same as a avariable with the name "A".

Examples:

thisisavariable a b c timer_out reload

etc....

VALUES: Values are essential data (sigular, datum, hee hee) that the computer stores at the "position" of the name of the variable.

Common values are numbers, but much more kinds of data can be stored, which we will go into later.

Examples: 0 1 2 3 5423.654 335.3 -433.3

The equals sign

It's all nice and swell that variables exist, but if they don't do anything, they're just about useless. The equals sign (=) if used to tell the computer to change the variable with the NAME on the left to the VALUE on the right. Variables are DYNAMIC, meaning they change. For instance,

a = 5

This is our first real code, though it doesn't do much. A rough, sarcasm-laden translation in English follows below.

"Oh, gee, I see a variable. Let's rack my memory for a variable with the name 'a'. Here it is! I'll just sweep out whatever was there before, without even looking, and stick a 5 in instead. Isn't that just wonderful?"

\*Cough*/

Anyways... The computer replaces its memory of "a" with a NEW memory of 5. This is nice and quaint, now to make it more hectic.

a = 2 a = 1

ANOTHER poor translation:

"Oh, gee, I see a variable. Let's rack my memory for a variable with the name 'a'. Here it is! I'll just sweep out whatever was there before, without even looking, and stick a 2 in instead. Oh, look another command, let's go look again for a variable called 'a'. Here it is, but there's a useless 2 in there! Let's throw that away. That's better. Now to shove a 1 in there!"

Hm, what happened here? Computer read code top to bottom and (usually) left to right, like we do. So it starts with the first line, calculates the reuslt, then moves to the second. After running this code, 'a' would be equal to 1.

Storing known data to variables is a bad idea, unless it takes a long time to retrieve, and is going to be used a lot. Now we're getting into our NEXT section!

Expressions!

An "expression" is essentially anything on the right side of the equals sign, although there are exceptions. The simplest expressions are just a number. More complex expressions use math.

a = 3 + 3

It should be plain that a is 6. BEFORE even looking at the variable's name, the computer calculates the value to the right of the equals sign. The text on the right side is often called an "expression."

Variables in expressions

Variables may be contained within expression. This might sound confusing at first, since the variable goes on the LEFT side of the equation. But that still doesn't really change.


Take this example

a = 5 b = a + 5

Logic gives us one plausible solution: b is 10! The computer simply switches out variables on the right side for their value counterparts!

In the case of:

a = 1 a = a + 1

a is now 2! Let's take a look. Like I said before, the computer DOES NOT CARE what exists on the left side of the '=' until it computes the expression on the right side. So,

"a = 1" -> Set the 'a' variable to a value of '1'. "a = a + 1" -> Substitute "a" for "1" -> "a = 1 + 1" -> "a = 2" -> set 'a' to '2'

Numbers are nice, but there's a lot else out there! It's time we take a look.

The art of data

Numbers

Numbers are a simple, primary data type. When I speak of "data types" I am referring to the way in which information is stored. A "Data Type" tells the computer what it's looking at: Binary (direct computer language) is totally undecodable if you don't know what to decode it into, Data Types provide this information.

The basic data types are chars, numbers, bools, and functions.

First: NUMBERS.

Numbers are the simplest to understand of all data types, because we are all used to them. 5 + 5 is 10, 5 * 5 (nmultiplication) is 25, and 5/5 (division) is 1.

Two other "operators" or characters like +-*/ are the % and ^.

^ is exponent, so a^b is a*a*a*a*.... b times. (2^3 = 2*2*2 = 8) % is modulo. It's not mentioned outside of programming much. Essentially, it returns the remainder of a division.

(see APPENDIX (A) for the mathematically "correct" implementation in Lua if you want, although it's not neccesary) For instance, 10 % 3 -> 1, because 1 is the remainder of 10/3.

Numbers may also be used in the "math" functions (we'll be adressing them later.)

Next: Bools and Chars.

Bools and Chars

Booleans (referred to as "bools") are truth values. Booleans have two names: true and false. This doesn't seem to fit in with everything else we've discussed, however. In fact, it does!

Introducing: == == (The equality operator) compares the thing on its left and the thing on its right. It's "true" or they're the same, and otherwise "false."

Examples:

5 == 5 --> true 5 == 6 --> false

That's the general idea.

~= is essentially the opposite.

Here's the unusual bit: "x and y" "x ory " and "not z". They are considered logical operators.

and -- requires that both are "true" to return true. Otherwise, false. true and true --> true false and true --> false true and false --> false false and false --> false

or -- at least one must be true to return true, otherwise, false. true or true --> true false or true --> true true or false --> true false or false --> false

not -- Returns the opposite. not true --> false not false --> true

Bools are useful (and neccesary) for structural control, which will be discussed later.

"Chars" (Please note: sounds like 'cars') are representations of any character. The letters, number, as well as the special characters are all "chars." Chars on their own are actually useless, because they can't be constructed in Lua. Their use comes in STRINGS.

Strings

Strings are a series of chars which are "strung" together. Essentially,a word, phrase, sentence, or any imaginable piece of text is stored as a string. In Lua, and most other languages, quotes (either single or double) are used to show where strings start and end.

Examples:

"horse" "dog" 'hi there world'

Please note that: "HELLO' is WRONG, because it ends with a single quote, but starts with a double quote. Also note that " " is difference from "", the first being a space, the second being empty.

To smash strings together, use the .. operator.

"DOGS ARE " .. "GOOD" --> "DOGS ARE GOOD"

String manipulation functions make Strings more useful, we will get into them in a bit.

Tables

Tables are arguably the most complex feature of Lua. They enable the most elegent solutions, create extremely short code, and even allow for OOP (Object Oriented Programming)

Tables are created by using {}

Here's an example:

a = {}

Simple, eh? You can put stuff in the parenthesis.

a = {1,2,6,3,2,54,45,3,2,2,4,653,546,43,4536}

Then it acts as a list of the values 1,2,6, etc etc etc. To get something from it, [] is used.

a = {9,8,7,6,5,3} b = a[2]

The second one in the list is set to b, so b is 8. Or, viceversa.

a = {1,2,3,4,5,6} a[2] = 9

So, a is essentially a list of 1,9,3,4,5,6.

Lists are funny, they're technically "pointers." That means this:

{} == {} wil returns FALSE AND NOT TRUE.

Additionally, doing:

a = {1,2,3} b = a b[2] = 5

WILL ALSO CHANGE THE VALUE IN a.

Got it? Good. This can cause unexpected problems. If you forget this basic rule, your code might go wrong, and you won't know why. UNLIKE OTHER DATA: SETTING A TABLE VARIABLE TO ANOTHER DOES NOT PRODUCE A COPY. THEY ARE THE SAME THING. Definitely important.


Besides numbers, strings can also be accessed as "indexes" of the table.

For instance:

a = {} a["hi"] = 5

So, when a["hi"] is accessed, 5 is retrieved.

Also, instead of typing: a["b"] you can type a.b if b contains no spaces.

a = {} a.hi = 5

Both methods work EXACTLY THE SAME, although the first is more dynamic, but slower to type out for general use.

One last thing: [] takes whole expressions.

a = {1,2,3,4,5,6,7,8,9} b = 3 a[ b + 3 ] = a[ b + 4 ] * 2

Which may lead to increasingly complex tables.

Nil

Nil is, essentially nothing. It's quite simple. It acts a lot like "false", cannot be added or concatted. It's only equal to itself. It's only special property is that any variable which is yet to be defined is nil. For instance:

a = 5

What's the value of b? Seems like a trick question. However, it's just nil. Rather simple. The only other useful thing to know is that acessing nil as a member of a table produces an error, and all yet-to-be-defined indexes in tables also have the value nil.



The last frontier

Structure

Code structure makes code USEFUL. The examples we have shown before are decent, but not neccesarily all that great. They lack dynamic ability to change. Unless you're brilliant at math, there's rather little you can do with them.

That's where "IF" "WHILE" and "FOR" statements come in.

\***IF***/ if-statements are REALLY useful. Like, they're so useful that it's hilarious we got on for as long as we did without them.

An if-statement is basically this:

IF (this is true) THEN (I should do this) ELSE (I should do this)

(That's semantics) In otherwords, it's wrong for code.

Code expresses if-statements in the forms

if a then b else c end if a then b end

It comes down to this: a is an expression (See above). b is a series of commands. c is an optional series of commands. The remaining words are vital.

Here's where bools come into play.

If-statements typically look for a boolean value. Which not strictly neccesary, it helps.

Here's a simple if-statement.

if true then a = 5 else a = 7 end

So, what is a? It's 5. This is actually pretty simple. If we had said "if false" it would have made a = 7, and not 5. If statements are "true" for non-nil, non-false values, and true for all others.

Similarily:

a = 6 == 6 b = 3 if not a then b = b * 3 end

b's value is now 3. Note that the else-clause is OPTIONAL, it may be excluded. There's one last form of if statement: the "if elseif" statement. a = 3 if a == 1 then b = 1 elseif a == 2 then b = 54 elseif a == 3 then b = -43 elseif a == 4 then b = 0 end

There can be 0, 1, 2, or as many else-if's as neccesary. But remember that excessive use of elsi-if's is usually bad. In most cases, tables and metatables (see later on) work better for more elegant and expandable solutions.


\***WHILE***/

While takes the same principals as if.

while a do b end

Essentially, "while a do b end" can be said to go like this:

MARKER if a then b GO BACK TO MARKER end

Whoa. Whoa. Slow down. You mean to tell me that I can tell the computer to repeat a task for as long as I like?

Yes! Say you want to multiply 2 by itself, say, 10 times. Instead of typing:

a = 2*2*2*2*2*2*2*2*2*2

You could say:

a = 1 i = 0 while i < 10 do i = i + 1 a = a * 2 end

Which is easier to read (for the most part) and can be easily adapted to allow as large or little as you want.

\***REPEAT***/ I won't delve into "repeat" much, because it's mostly not useful. (EDIT: As it turns out, repeat is actually (negligibly) faster than the other loops.) However....

repeat a until b

Is the same as doing:

a while b do a end


It has its uses and drawbacks.


\***FOR***/

--To be added. This is reasonably complex, and I'm still fuzzy on the details. You do not "need" "for" for most applications, though it can make your job easier eventually.




Functions

Functions. For those of you who aren't far through math courses, and no nothing about programming, functions don't "make sense."

A function is like a machine. You build the machine to run specific code. Then, you run the function (like running a machine) by giving it some or no input. Then the machine may alter memory, or spit back a value.

Functions are technically not neccesary in a language which supports loops and if-statements, but they make it much simpelr to create complex systems than arithmetic and structure allows.

A function whose name (functions are a type, thus stored in vasriables) is "called" with the single argument b by doing:

a(b)

Simple enough. The function "print" is standard to Lua (and most other languages) and displays a data in the "output" bar of your Roblox studio.

So doing:

print(5)

"prints" 5 to the output bar, on a new line. Please note that the 'b' in 'a(b)' is called an "argument." Functions may take as many arguments as they are wanting. For instance, print() takes as many as you want, displaying each on their own lines. If you give a function too few arguments, it will supply them as "nil." Too many, and it will discard the extras. Some functions may take however many arguments you want.

So far, we haven't discussed how to actually USE functions. The first kind we'll discuss are "anonamous" functions.

a = function(b) return b end

There's some new stuff here. First, we see "function." At first, it seems that it actually IS a function, but, contrary to what you might think, it's not. Instead, it's a syntactical structure explaining to "give me a data of type 'function' which takes the following arguments, and then runs the following code."

Now, what about "return"? Well, essentially, whatever FOLLOWS the return statement (b) will be assigned as the value of the function's call.

So, if we assigned a as above, and then did

c = a(5)

c would be 5. This seems a bit redundant- IT IS! However, functions are REALLY useful.

There's another way to write functions, that's usually better (not always).

function a(b) c end

(same as doing a = function(b) c end) This is the form we'll be using for a while.

Functions and scripting

Arguments

Functions can take more than one argument. Before, we did:

a(5)

But, if designed so, we could also do:

a(5,6)

Note the comma separating them.

Likewise, to define a function with more than one argument*:

  • see appendix B for exceptions.


function a(b,c,d,e,f)

end

etc. Commas also separate the arguments here. Functions may also take 0 arguments!

function a()

end

Simple enough.

If the wrong number of arguments are supplied: 1) Any extras are discarded. 2) All arguments which have no corresponding value are assigned nil.

Scope

Scope, arguably, is fairly difficult to comprehend. It takes a bit of lateral thinking. Additionally, it requires the idea that functions have "depth."

Think of it like this: Your code is a flat plot of land. When you reach a function, you can't fit it in your land anymore. What do you do? You dig deeper, and put it underneath. If IT calls a function, you dig again, etc. When you're done with a function, you fill it back in again. While less specific, if-statements, while-loops, for-loops (which I have yet to cover), do-blocks (which I doubt I'll cover) and repeat-until-loops all require their own "dig downwards."

Scope is all about variables. I'm going to continue to use the example of the miner- digging down for function, to explain it.

The miner is lazy. He does not like to have to go upwards, when it is his job to dig downwards.

The current statement is: "a = 5" So, the miner grumbles slightly, then wanders ALL THE WAY UP TO THE SURFACE, and drops the variable on the ground. He goes ALL THE WAY TO THE BOTTOM again. The next line is: "a = a + 1" So he grumbles a bit more, goes ALL THE WAY UP TO THE SURFACE, scribbles out the 5, and makes it a 6. The next line is a function call, so he digs down ANOTHER level. The line after that is: "a = a / 2" So he goes ALL THE WAY UP TO THE SURFACE, and rewrites 'a' as 3.

So, that's neat and all. Variables are all on the surface, so you know where to find them. But, believe it or not- this is actually quite slow. The computer must search EVERY LEVEL before going up. And there's another problem: what if the computer is in the middle of a loop, and calls itself with different arguments? When that function reaches the SAME loop, it will be using the SAME VARIABLES, and screw it up completely!

That's where scope comes into play.

Let's do something a bit different.

Here's pseudocode, meaning "fake code." It's not proper Lua, but it fits our purpose.

a = 1 function call a = a + 1 function call local a = 7 function call a = a + 3 end end end

If you look closely, there's something new there. We'll explain it when we get there.

a = 1: Simple enough. Variable called 'a' is put on the surface.

function call: dig a layer down, and climb in!

a = a + 1: Simple enough. There's no variable here, so go up, write on it, and head back down again.

function call: dig a layer down, and climb in!

local a = 7: WAIT! This is different. "local" was added. "local" means PUT THE VARIABLE HERE, NOT ON THE SURFACE. K? So, drop a variable 'a' in this layer.

function call: dig a layer down, and climb in! Leave the variable on the ground on the layer above.

a = a + 3: Well, the miner looks around. No local variable is on this level. Therefore, he has to go up to the only place a non-local variable could be: the surface. The surface is rewritten.

end: fill in the lowest layer.

end: fill in the layer with the local variable. It's just going to be buried- it will dissolve, and won't ever appear again.

end: fill in the last layer below the surface.

All that's left is a = 5.


Yes, this is difficult to understand. Figuring out exactly how scope will act is difficult. Even I have to struggle with it a lot- and I don't know all of this by memory, I have to go and check it out to make sure I'm right.

Also note that the highest level of scope (surface) local variables are no different than others, except that they run much faster.


Coming next: Metatables and anything else I might have missed.

Thanks for reading!





APPENDIX

A) function modulo(a,b) --a and b are numbers while a < 0 do a = a + b end while a >= b do a = a - b end return a --Technically, division accomplishes this task much more quickly, although this is the place where the term 'modulo' originates from, 'modular arithmetic.' end

B) The lambda calculus is a form of computation where all functions take exactly one argument. There are also no variables in this language.

\ is the lambda symbol. . is the binding operator. (space) is the application operator.

(\x.x) Is a function, called a lambda abstraction. Other expressions may be applied to lambda expressions, by putting a space after the lambda expression, and following the space with the applied statement.

For instance:

(\x.x) (\y.(\a.a) y)

Evaluates to:

(\y.(\a.a) y)

Yes, it is tricky to understand. Essentially: (\a.t) b = 't' where all instances of 'a' are replaced by 'b', assuming 'b' is not already found in 't'. (\a.t) = (\b. 't' with all instances of 'a' replaced by 'b', assuming 'b' is not already found in 't')