TeaScript Syntax
Data Types and Variables
User Variables
User variables can be access in the variable menu or by pressing ctrl+i. All of these variables must be created using this interface.
Doubles & Strings
By clicking the "Add" button in the variable interface you create a user variable.
You may also select if the variable is a global user variable. Local variables can only exist in a single level and the value is reset every time the level begins. Global variables save the value per level and remembers the value even after quitting the game.
Variable Naming Standard
- Names are not case sensitive.
- Names must not contain spaces.
- Names must be made using a combination of using letters and numbers.
- Names must start with a letter
User variables work in an unusual way compared to other scripting languages. A user variable has two sides, a double and a string. There are different methods to access each side
' By creating a variable called "myVar" in the interface you can...
' === Access doubles
'Local
val(myVar) or v(myVar)
'Global
gval(myVar) or gv(myVar)
'Local Concatenation in TXTCreate and Event Messages
&val(myVar)
'Global Concatenation in TXTCreate and Event Messages
&gval(myVar)
' === Access strings
'Local
str(myVar)
'Global
gstr(myVar)
'Local Concatenation in TXTCreate and Event Messages
$val(myVar)
'Global Concatenation in TXTCreate and Event Messages
$gvl(myVar)
' === Example
v(myVar) = 5
str(myVar) = "Hello"
v(myVar) = v(myVar) + 2
str(myVar) = str(myVar) & " World"
' v(myVar) now has the value of 7
' str(myVar) now has the value of "Good Morning"
' Notice how a user variable simultaneously hold a double and a string at the same time. The double side does not interfere with the string side and vice versa.
Note how a user variable simultaneously can hold a double and a string.
Arrays
By clicking "Add" while holding shift in the variable interface you create a user array. Currently, arrays can only be double and only hold doubles. Arrays must first be initialized using the redim function before usage.
' By creating an array called "myArr" in the interface you can...
' Initialize the array using redim
' Read documentation on redim for more information on usage
call redim(0, myArr, ARRAY_LENGHT)
' Access value of an array at an index
array(myArr(index))
' === Example call
redim(0, myArr, 3)
array(myArr(1)) = 5
array(myArr(2)) = 7
array(myArr(3)) = array(myArr(1)) + array(myArr(2))
' The array now has the following values of [5, 7, 12]
Dim Variables
Dim variables are a different way of creating and interacting with variables than user variables. A dim variable can only have a single type of data that must be defined on creation. Variable naming standards are the same as user variables, except you may not use the same name of other existing functions and keywords.
' You can initialize a variable
dim varName as type
' You can initialize a variable with a defined value
dim varName as type = value
'Once initialized you just write the variable name to access it
varName
' === Example
dim myInt as integer
dim myLng as long
dim myDbl as double = 5
dim myStr as string = "Hello"
myInt = myDbl*2
myLng = myDbl*5
myStr = myStr & " World"
'myInt has the value of 10
'myLng has the value of 25
'myDbl has the value of 5
'myStr has the value of "Hello World"
Expressions
Operators
Mathematical Operators
| Mathematical Symbols | ||
|---|---|---|
| Symbol | Name | Example |
| + | Addition | 12 + 2 + 3 'returns 17
|
| - | Subtraction | 12 - 2 - 3 'returns 7
|
| * | Multiplication | 12*2*5 'returns 120
|
| / | Division | 'Note that division by 0 will crash SMBX
12/2/5 'returns 1.2
|
| \ | Division with no remainder | 'Note that division by 0 will crash SMBX
12\2\5 'returns 1
|
| ^ | Power | 'Note that 0^0 will return 1
12^2 'returns 144
|
| mod | Modulus | 'Note that modulating by 0 will crash SMBX
12 mod 5 'returns 2
|
| & | Concatenation | "ABC" & ";" & "123" 'returns "ABC;123"
|
| ( ) | Parenthesis | 12*(2 + 5) 'returns 84
|
Comparing Operators
Note that all comparative operators require both sides use the same data type. (You can compare numbers with other numbers and strings with other strings, but you cannot compare numbers with strings)
| Comparitive Operators | ||
|---|---|---|
| Symbol | Name | Description |
| = | Equal | Numbers Returns -1 if both sides are equal, otherwise 0 |
| Strings Returns -1 if both sides are equal, otherwise 0 | ||
| <> | Not equal | Numbers Returns -1 if both sides are not equal, otherwise 0 |
| Strings Returns -1 if both sides are not equal, otherwise 0 | ||
| > | Grater than | Numbers Returns -1 if the value on the left is larger, otherwise 0 |
| Strings Unknown pattern | ||
| < | Less than | Numbers Returns -1 if the value on the left is smaller, otherwise 0 |
| Strings Unknown pattern | ||
| >= | Greater than or equal | Numbers Returns -1 if the value on the left is larger or equal, otherwise 0 |
| Strings Unknown pattern | ||
| <= | Less than or equal | Numbers Returns -1 if the value on the left is smaller or equal, otherwise 0 |
| Strings Unknown pattern | ||
| like | Like | Numbers Not compatible |
| Strings https://docs.microsoft.com/en-us/dotnet/visual-basic/language-reference/operators/like-operator | ||
Logical Operators
Logical operators only work on numbers. They are commonly used with -1 and 0 to represent true and false respectively. Other numbers can be used but it may yield different patterns.
| Logical Operators | ||||||||
|---|---|---|---|---|---|---|---|---|
| P | Q | not P | P and Q | P or Q | P xor Q | P eqv Q | P imp Q | |
| 0 | 0 | -1 | 0 | 0 | 0 | -1 | -1 | |
| 0 | -1 | -1 | 0 | -1 | -1 | 0 | -1 | |
| -1 | 0 | 0 | 0 | -1 | -1 | 0 | 0 | |
| -1 | -1 | 0 | -1 | -1 | 0 | -1 | -1 | |
Special Values
These special values behave like numbers.
| Special Values | |
|---|---|
| Name | Value |
| pi | 3.141592654 |
| e | 2.71828182 |
| rnd | A random number between 0 and 1. The value changes every time the variable is accessed. |
Built-in Functions
Functions are powerful tools that allow you to simplify and expand the flexibility of your scripts. To access a function, you write the function name and in parenthesis write the parameters separated by commas. You can put functions in expressions just as it were a regular number or string.
myFunc(param1, param2, ..., paramN)' === Example
dim x as integer = -5
dim y as integer
y = abs(x) + 1
' x returns -5; y returns 6
' Note how the abs() function is used
These are the mathematical functions provided.
Parameters can be numbers, strings, and arrays.
| Functions | ||
|---|---|---|
| Name and Parameters | Return Type | Description and Example |
| abs(x) | Number | Returns the absolute value of a number
abs(-3) 'returns 3
|
| exp(x) | Number | Returns the number to the power of the e constant
exp(5) 'returns e^5
|
| log(x) | Number | Returns the log of the number with a base of e
log(e) 'returns 1
|
| sgn(x) | Number | Returns the sign of the number (1, -1, or 0)
sgn(10) 'returns 1
sgn(0) 'returns 0
sgn(-10) 'returns -1
|
| int(x) | Number | Returns the number rounded up. Similar to the common ceiling function
int(2.1) 'returns 3
|
| fix(x) | Number | Returns the number rounded down. Similar to the common floor function
fix(2.9) 'returns 2
|
| sqr(x) | Number | Returns the square root of a number
sqr(9) 'returns 3
|
| sin(x) | Number | Returns the sine of the number. Uses radians
sin(pi) 'returns 0
|
| cos(x) | Number | Returns the cosine of the number. Uses radians
cos(pi) 'returns 1
|
| tan(x) | Number | Returns the tangent of the number Uses radians
tan(pi/4) 'returns 1
|
| atn(x) | Number | Returns the inverse tangent of the number. Uses radians
atn(1) 'returns pi/4
|
| getangle(x, y) | Number | Returns the angle (from 0 to 1) formed between the triangle. Similar to the common atan2 function.
getangle(1, 0) 'returns 0
getangle(1, 1) 'returns .125
getangle(0, 1) 'returns .25
getangle(-1, 0) 'returns 0.5
getangle(0, -1) 'returns 0.75
|
| rgba(red, green, blue, alpha) | Number | Returns an SMBX color value. Parameters must be between 0 and 255
rgba(255, 255, 255, 255) 'returns -1
|
| round(x, decimal place) | Number | Returns the number roundedround(1.3456, 2) 'returns 1.35
|
| len(txt) | Number | Returns the length of the text
len("ABC") 'returns 3
|
| left(txt, len) | String | Returns the text cropped from the string inputted. The crop begins from the start and ends with the length specified.left("Hello", 2) ' Returns "He"
|
| right(txt, len) | String | Returns the text cropped from the string inputted. The crop ends from the end and begins with the length specified.right("Hello", 3) ' Returns "llo"
|
| mid(txt, start, len) | String | Returns the text cropped at the specified start and has the specified length provided. mid("Hello", 2, 3) ' Returns "ell"
|
| replace("txt", "search", "replacement", #start, #count, #case_insensitive) | String | Replaces a part of the text with a new one.
|
| asc(char) | Double | Returns the ANSI code. It will use the first character if more than one is passed |
| chr(code) | String | Returns a string using the ANSI code. Accepts 0-255 |
| ascw(char") | Double | Returns the unicode code. It will use the first character if more than one is passed |
| chrw(code) | String | Returns a string using the unicode code. Accepts 0-65535 |
| cstr(num) | String | Converts the number to a string |
| cdbl(txt) | Double | Converts the string into a number |
| instr(start, txt, search) | Double | To return the point of the first appearance of a given string in another string.
|
| ubound(array) | Number | Returns the length of the arraycall redim(0, myArr, 3)
ubound(myArr) ' Returns 3
|
Control Flow
When a script is run in TeaScript it will start reading the script from top to bottom, left to right. It will read and execute the code in that order. the following is a list of ways to customize and manipulate what code gets executed in your scripts.
Conditions
Conditions represent "true" and "false". In Teascript -1 and 0 represents true and false. Any number that is not 0 may also represent true, but use -1 and 0 for consistency reasons.
-1 ' Represents True
0 ' Represents False
5 ' Represents True (because non-zero numbers represent true)
dim w as integer = -1
dim x as integer = 5
dim y as integer = 5
dim z as integer = 0
w ' Represents True (because w has the value of -1)
x ' Represents True (because x has a value of a non-zero number)
y ' Represents True (because y has a value of a non-zero number)
z ' Represents False (because z has a value of 0)
z - 1 ' Represent True (because 0 - 1 = -1)
w + 1 ' Represent False (because -1 + 1 = 0)
' Using logical operators
not w ' Represent False
not (y and z) ' Represents True
w or z ' Represents True
If Statements
The "if statement" is a basic but useful statement. It has one parameter being "condition".
' Basic if statement
if conditon then
statement
end if
' Shortcut if statement
if condition then statement
' If statement using one elseif and an else statement
if conditon then
statement
elseif condition then
statement
... ' You can have as many elseif as you want
else
statement
end if
When TeaScript reads an if statements it will check each condition from top to bottom until it reaches a condition that is true. When it reaches a condition that is true, it will execute the code that is inside that statement and continue the code after the entire "if statement". This means that conditions written on the top will have priority over those in the bottom.
The "else" is special since it does not require any conditions. An else must be written in the bottom after all other "elseif"s statements (if there are any). The code inside the "else" will only run if every other condition in the "if" and "elseif" statements evaluated to false.
' === Example
dim x as integer = 0
dim y as integer = -1
dim z as integer = -1
' Since (x and y) evaluates to 0, this statement is not run.
if x and y then z = 0
' Since (x and z) evaluates to 0, this statement is not run.
if x and z then
y = 0
' Since (y) evaluates to -1, this statement is run.
elseif y then
x = -1
' Since the previous elseif has priority and only one statement can be run, this statement is not run
else
z = -1
end if
Select Case
Select Case lets you easily organize the control flow based on a value. It has one parameter being "value".
select case value
case -1
'Code that should pass if the value is exactly -1
case 0 to 1
'Code that should pass if the value is between (inclusive) 0 and 1
case is < -1
'Code that should pass if the value is less than negative one
case 2, 3, 4
'Code that should pass if the value is exactly 2, 3 or 4
case "example"
'Script that should pass if the value is exactly "example".
case else
'Code that should pass if the value does not match any of the other conditions
end select
"Select case" at its core is similar to various "if statement"s and behaves similarly to the common "switch" statement in other languages. It will read the value that is passed and only executes the code in which the value matches. It will read the cases from top to bottom giving priority to cases at the top.
The "to" keyword can be used when checking for a case.
- Doubles Will be true if the value is between (inclusive) the two numbers provided.
- Strings Unknown pattern
The "is" keyword can be used to make comparisons to the value. It can be used with "<", ">", "<=", or ">=" symbols.
You can use commas to check for multiple cases at once. The commas behave similarly to an "or" operator. The case will go through if it matches with any of the cases.
With Statements
With statements are useful to set multiple statements to a given object.
with object
[statement]
end with
Object means an object of the game. Here's an example:
with npc(1)
.x = 12345
.y = 54321
end with
Goto
Using goto will force the script to jump to a specific line using a label.
Example:
[statements]
goto Example
When the script reached "goto Example" it will jump to "Example" and execute the script below it. The labels used with goto statements must: have names that do not contain characters that do not follow variable name rules, there must not be two labels with the same name and there should not be goto statements inside "with" statements either (meaning you can't use them when scripting an npc).
GoSub
Gosub statements are very similar to goto ones, but there is a noticeable difference.
mysub1:
[statement 1]
gosub mysub1
return
mysub2:
[statement 2]
gosub mysub2
return
While goto statements will simply jump into a given line, gosub statement can keep track of where it came from. This means the program won't search through the whole stack to find a given label, instead it will do from the last "return" found. Gosub statements must follow the same rules as goto statements.
Loops
It is important to note that you should avoid an infinite loop. Make sure to either have a "sleep" function (if the script was called by an event) or an "exit" if you set up a for loop to go indefinitely.
Pure
A "pure loop" is a very simple and basic form of a loop.
'Pure loop:
do
'Code that will be executed multiple times
loop
The loop will run indefinitely.
While
The game will repeat executing statements inside do statement until condition returns true. The condition be checked at the beginning or either at the end of the loop.
In this example the game checks the condition at the beginning, meaning if condition is false the game won't execute statements inside "do".
do while condition
[statement]
loop
In this example the condition is checked at the end of the loop. This means that is condition is false the game will execute anyway statements inside "do" until it reaches "while" and verify the condition.
do
[statement]
loop while condition
Until
The game will repeat executing statements inside do statement until condition returns false. You can also make the game check the condition at the beginning or at the end of the loop like with "while" statements.
do until condition
'Code that will be executed multiple times
loop
do
'Code that will be executed multiple times
loop until condition
For
A "for" loop is a loop that will run a certain amount of times. It has three parameters: "initial_value", "ending_value", and "setp_value".
for v(myCounter) = initial_value to ending_value step step_value
'code that will be executed multiple times
next
'step_value is optional and if omitted the loop will behave with a step of 1
for v(myCounter) = initial_value to ending_value
'code that will be executed multiple times
next
An already existing variable must be set to "initial_value". The variable will start the loop with this and increment by the value set in "step_value". You can still manipulate the variable while inside the "for loop".
The loop will continue going until the variable is larger or equal to "ending_value" when the script reaches "next". The loop will also stop if the variable is less than the "initial value" when it reaches next. Once the loop stops it will continue reading the script.
When TeaScript reads an "exit for" while inside a "for loop" it will immediately skip to the next keyword and resume the script.
Exit
An exit will terminate a loop and skip the code after it until it reaches the "loop" or "next" keyword (Depending on what loop it was used on).
'This will work while inside a pure, while, or until loop
exit do
'This will work while inside a for loop
exit for
'This will force the game to stop immediately executing the script
exit script
Script
Using the script keyword, it allows you to make useful custom functions and procedures in Teascript.
v(myvar) = exampleWithReturn(5, "test")
call exampleWithNoReturn()
'A script set up as a function (has a return)
script exampleWithReturn(myDoubleParam as double, myStringParam as string, return double)
return param(myDoubleParam) + len(strparam(myStringParam))
end script
'A script set up as a procedure (has no return)
script exampleWithNoReturn()
v(myVar) = v(myVar)*2
end script
When setting up a script, all parameters must be defined by name and type as shown below. You may have as many parameters as needed. Note that return is optional. All script and parameter naming standards are similar to variable naming standards with one exception. Script names must not contain numbers.
script example(name as type, name as type, ..., return type)
param(name) 'Use param when reading the value of a double
strparam(name) 'Use strparam when reading the value of a string
end script
Unlike common functions in other languages, TeaScript cannot do the following:
- Set the value of passed down parameters. All parameters passed down are read-only.
- Create recursive scripts. You cannot call a script within itself.
The "return" keyword will only in functions. If a function has no return, then it will return 0 or "" (based on the return type that was specified. SMBX will error if you include a return in a procedure.
It is important to note that when called, procedures must have the "call" keyword. This also applies to a function if you do not read the returned value.
Oddities and Quirks
The following is a list of oddities that you may experience when using TeaScript
Writing Double Quotation Marks
Since double quotation marks are reserved for defining string, you must use chr or chrW to write a double quotation mark inside a string.
str(myVar1) = chrW(34) '34 is the ID of the double quotation marks. (ID 34 works too in chr() too)
'You can define a variable as a quotation mark or call the quotation mark directly, both work the same
str(myVar2) = "These are some "&str(myVar1)&"special"&chrW(34)&" marks"
'str(myVar2) is "These are some "special" marks"
> THESE PROBLEMS ARE FIXED in 1.4.5 <
Writing Decimal Numbers
When writing decimal number, you must include a number before the decimal point.
'Wrong
v(myVar) = .1
'Correct
v(myVar) = 0.1
Writing negative numbers
When writing a negative number, make sure there are no other symbols beforehand (except parenthesis).
'Wrong (Teascript errors due to seeing * and - next to each other)
v(myVar) = 5*-4
'Correct
v(myVar) = 5*(-4)
v(myVar) = -4*5