Skip to content

Conventions

If you are familiar with almost any programming language, you should find GreyScript easy to pick up. However, GreyScript does perform some things a little differently. Let's cover some of the ABCs of GreyScript.

Syntax

Improper Syntax vs Proper Syntax

See the example below of incorrect vs correct syntax.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
function foo(bar){
  if(bar > 5){
    return bar;
  }

  while(bar <= 5){
    print('Something');
    bar++;
  }
}

foo(4);
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
foo = function(bar)
  if bar > 5 then
    return bar
  end if

  while bar <= 5
    print("Something")
    bar = bar + 1
  end while
end function

foo(4)

Can you spot what's wrong with the incorrect example?

  • Line 1: functions should be declared as a variable
  • Lines 1, 4, 6, 9 & 10: code blocks in GreyScript do not use curly braces { }
  • Lines 2 & 6: Brackets/Parentheses should generally not be wrapped around conditional statements
  • Lines 3, 7, 8 & 12: semicolons should be avoided. One line of code per line.
  • Line 7: strings require "double quotes"
  • Line 8: the numerical increment operator (++) is not supported

One statement per line

In GreyScript, each code statement typically belongs on a single line. There are no semicolons (;) or curly braces ({ }).

Multiple statements on one line

The exception to this rule is where you want to have more compact code, by joining multiple statements on one line. While this is discouraged, it is nevertheless supported.

x = 0; while x < 10; x=x+1; print(x); end while //prints numbers 1-10

Single quotes ('like this') are not supported

Instead use "double quotes".

See strings

Code Blocks

You may be accustomed to seeing curly braces around blocks of code. In GreyScript, code blocks always begin with a keyword (if, for, while, or function) and end with a matching end statement (end if, end for, end while, or end function).

Indentation is not required for code blocks, although it does make your code blocks more readable.

Indentation Example

Both blocks A and B are valid, and perform exactly the same function, but block B uses indentation.

Block A
lastIndexOf = function(list, val)
if list.indexOf(val) == null then
return null
end if
i = 0
li = 0
for e in list
if e == val then
li = i
end if
i=i+1
end for
return li
end function
Block B
lastIndexOf = function(list, val)
  if list.indexOf(val) == null then
    return null
  end if
  i = 0
  li = 0
  for e in list
    if e == val then
      li = i
    end if
    i=i+1
  end for
  return li
end function

Whitespace

Between strings, numbers, and operators, spacing is optional. Additional spacing looks cleaner, but is not required.

Example

1
2
3
4
5
a = 1 * 2 + 3
b = "x" + "y" + a

a=1*2+3
b="x"+"y"+a

In the above example, lines 1 & 2 are the same as lines 4 & 5.

Case Sensitivity

Variable names are case sensitive.

Comments

Comments are a means of placing notes within your code, to remind you (or help others who are reading your code better understand) what the code is doing.

As with many other languages, comments begin with two slashes.

Example

print("Hello world!") //this line prints the message 'Hello world!'

// Another comment here
print("The above line is not processed as code")

Brackets

GreyScript has some unconventional behaviours when it comes to brackets (also known as parentheses).

In GreyScript, brackets are typically only used in the following three instances:

  1. grouping mathematical operations

    num = (1+2) * 5 // not the same as 1 + 2 * 5
    
  2. passing arguments in function calls

    print("Hello")
    

    See passing arguments.

  3. declaring a function

    myFunction = function()
      return true
    end function
    

Brackets do not belong elsewhere (such as in if statements or while loops).

Example

You may want to write this:

if(params[0] == "y") then
  while(i > 10) then
    // perform miracles
    i=i-1
    end while
end if

Instead, write this:

if params[0] == "y" then
  while i > 10 then
    // perform miracles
    i=i-1
    end while
end if

Passing arguments

While in many languages, a function is called with brackets e.g. myFunction(), in GreyScript we only use brackets when calling a function if we are passing arguments to that function.

Example

If we wish to print an empty new line, we can call the print function without any arguments. The correct way to do this is by running simply print, instead of print().

print("Something")
print
print("Something else")

Variable Scope

In many languages, as with GreyScript, we need to be aware of any limitations to scope.

Variables in GreyScript are always local in scope. Accordingly, each variable is scoped to the function executing at the time.

Usage Example

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
fun = function(x)
  print(x) //this 'x' has local scope
  print(y) //can read 'y', but cannot alter it outside this function
  x=(x+1)
  y=y+1
end function

x = 4 // global scope
y = 5 //global scope
fun(y)
print(x)
print(y)
5
5
4
5

globals.var

If we need the reference to a global variable in order to modify that variable from within a function, we can use globals.

Usage Example

foo = function()
  globals.bar = 0
end function

bar = 1
print(bar)
foo // call foo(), setting bar to 0
print(bar)
1
0

locals.var

If we need the reference to a local variable for the current function, we can use locals.

This function is largely of minimal use, because variable scope is always local, but it can help us to be clear in our code when we are seeking local scope only.

Usage Example

count = 0
state = "New York"
go = function()
  globals.count = globals.count + 1
  locals.state = "Mississippi"
  print(globals.count + " " + state)
end function

go
go
go
print(state)
1 Mississippi
2 Mississippi
3 Mississippi
New York

Objects and Classes

Like many other programming languages, GreyScript utilises Object Oriented Programming (or OOP) with prototype-based inheritance. This also means that there are no differences between a class and an object.

In simple terms, this means that we have objects with their own functions, called by objectname.functionname e.g. Computer.lan_ip.

Creating a Class

Fruit = {}
Fruit.colour = ""

Here we have established a new base class (which is essentially just a map), while providing a colour property. We have told GreyScript that our Fruit class should always have a colour property with an empty default.

Now let's create a subclass with new Fruit, assigning this to Apple. We should also override the colour property of Fruit (apples are often green, after all).

Apple = new Fruit
Apple.colour = "green"

Now we can instantiate our Apple subclass:

a = new Apple
print(a.colour)  // prints "green"

While these are essentially just maps, because they have been created with new, these maps contain a property named __isa, which points to the parent map. You should not need to worry about this property, other than to know two things:

  • When you create a map using the new operator, the __isa member is set for you.
  • When you look up an identifier in a map, GreyScript will walk the __isa chain looking for a map containing that identifier. The value returned is the first value found.

Let's add to the above, by creating a function under Fruit, which will work on any subclass.

Fruit.capitalise = function()
  return slice(self.colour, 0, 1).upper + slice(self.colour, 1)
end function

print(t.capitalise) // prints "Green"

Note that the Fruit.capitalise function is able to utilise the special self variable, which refers to the object on which it was invoked (in this case t). Through self, class functions can access, as well as modify, object data.

Booleans

In GreyScript boolean values are represented as numbers: either 1 (true) or 0 (false).

The keywords true and false can be used as return types in functions (e.g. return true) but these are exactly equal to the numbers 1 and 0 respectively.

if and while

When using if and while or in any other context that evaluates the truth of a variable, anything equalling 0 will always evaluate as false, while almost anything else will evaluate as true (with the exception on empty values below).

Usage Example

fun = function()
  return true // actually returns `1`
end function

if fun then
  print("fun")
end if
fun

Empty Values

As is common in many languages, any non-empty variable (string, map, or list) will evaluate as true. Furthermore, any variable that equals null will evaluate as false.

mylist = [] // false
mylist = ["blah"] // true

str = "" // false
str = " " // true

pam = {} // false
pam = {"a":"b"} // true

x = null // false

Control Flow

In GreyScript usage of if statements and loops (for and while) are straightforward, providing you remember the guidance concerning brackets, booleans, and code blocks.

if statements

As explained on the subject of code blocks, if statements should begin if, and end with end if.

if condition then
//do things
end if
A basic if statement

total = 100

if total == 100 then
  print("The total is 100")
end if
The total is 100

if and else

total = 50

if total == 100 then
  print("The total is 100")
else
  print("The total is not 100")
end if
The total is not 100

if and else-if

total = 25

if total == 100 then
  print("The total is 100")
else if total >= 10 and total < 20 then
  print("The total is between 10 and 20")
else if total >= 20 and total < 30 then
  print("The total is between 20 and 30")
else
  print("The total is something else (" + total + ")")
end if
The total is between 20 and 30

shortcut

'Shortcut' if statements are if statements written on a single line. Both if and if/else are supported, although else if is not.

Limitations:

  • A single statement for the then block
  • A single statement for the else block (if used)

Example

hello = 1
if hello then print("Hello!")

greeting = 0
if greeting then print("Hello!") else print("Goodbye")

for loops

A for loop can loop through a list, with each iteration handling a value from the list.

for e in list
//do things with 'e'
end for
Usage Example

for i in range(10, 1)
  print(i + "...")
end for
print("Liftoff!")
10...
9...
8...
7...
6...
5...
4...
3...
2...
1...
Liftoff!

strings

You can also use a for loop over a string, where the string is essentially split into a list of its characters.

Usage Example

fruit = "apple"
for c in fruit
  print(c)
end for
a
p
p
l
e

maps

It is also possible to loop over a map, though in this case the iteration will equal a mini-map consisting of key and value. See the example below.

Usage Example

mymap = {"fruit": "apple", "colour": "orange", "vegetable": "cucumber"}

for item in mymap
  print("The key '" + item.key + "' has the value: " + item.value)
end for
The key 'fruit' has the value: apple
The key 'colour' has the value: orange
The key 'vegetable' has the value: cucumber

while loops

If you are not familiar with while loops, they essentially loop over a block of code while a condition remains true. The block repeats infinitely, until the condition evaluates as false.

Usage Example

i = 1
while i <= 5
  print(i)
  i = i + 1 //without this line, i would not increase and the loop would keep running infinitely
end while
1
2
3
4
5

This example declares i as 0. The while loop checks whether i is less than or equal to 5, and if so then prints i and increases i by 1. The while loop runs again and again, until i has increased to 6 (which is not <= 5) and therefore the loop ends before its sixth iteration because the condition is no longer true.

break and continue

As with other languages employing loops, break and continue operate in their usual way, in while and for loops

break

Run from inside the loop, this halts the loop

Usage Example

i = 0

while i < 5
  i=i+1
  print(i)
  if i == 3 then
    break
  end if
end while
1
2
3

This stops at the number 3 because when i equals 3, break quits the loop after print(3).

continue

Run from inside the loop, this skips the specific iteration and the loop continues

Usage Example

i = 0

while i < 5
  i=i+1
  if i == 3 then
    continue
  end if
  print(i)
end while
1
2
4
5

This does not print the number 3 because when i equals 3, continue skips the iteration before print is called.

Behaviour

While GreyScript unlocks many exciting opportunities, not everything is possible. It is important to beware of some of the limitations in GreyScript.

Script Execution

When working with GreyScript it is important to understand that any code is executed on the multiplayer server (or in single player, the local server), and once completed, the output is then returned to the client terminal.

It is now possible to prompt the user for information from within the terminal, (instead of requiring all parameters. In this case, script execution will continue once the user input is provided.

Filesize Limits

There is a limit of 80,000 characters for a compiled binary.

Terminal Output

There is a limit of 2,000 characters on the text any script can print to the terminal. If the script attempts to exceed this, the output will be cut down to its last 2,000 characters.