💾 Archived View for gem.sdf.org › rellwood › doc.gmi captured on 2023-06-14 at 14:08:15. Gemini links have been rewritten to link to archived content
-=-=-=-=-=-=-
CELL RUNNER DOCUMENTATION
Cell Runner has a built-in programming language that can be used to customize your worlds, maps, sprites, and other aspects of your games to your liking. The language is reasonably simple to understand and yet offers decent power and flexibility. Experienced programmers shouldn't have much trouble getting familiar with it, and first-time programmers may find it to be a good introductory language to use to learn how to program.
The language is designed in conceptual layers, and so will be explained as such, one layer at a time from the most fundamental syntax to the included library of functions for creating your game.
At its most fundamental, writing code consists of combining four basic types of elements: numbers, strings, symbols, and nil. (There are other, more complex, fundamental types such as functions, enumerations, and structures, but those will be discussed later.)
A number is just that. It can be positive, negative, or fractional. Eg.,
5 -18.2 45.9667
A string is a collection, or "string" of characters. It is represented in the language by enclosing the characters in double-quotes. E.g.,
"Hello" "The quick brown fox jumbed over the lazy dogs." "f" ""
The last one is an empty string, zero characters long.
If you want to include the doube-quote character in a string, proceed it with a back-slash. E.g.,
"She said, \"Hello\" to me."
A symbol is used to represent something else, such as a number, string, function, or various other possible types of values. Often, other languages call this concept a "variable." A number of built-in symbols are provided for you, but you can also create your own with the assignment operator. They can be made up of the letters a - z, numbers and the underscore, but cannot start with a number. They can be any length and are case-sensitive. E.g.,
mySymbol width2 this_is_a_very_long_symbol_name_but_theres_no_length_limit_so_who_cares R2D2
Nil is another basic type of element. It can be thought of as a special symbol that means "no value" or "nothing." It is always written in all lower-case: nil.
A statement is a complete instruction given to the computer, and a program consists of a collection, or a list, of statements. They are evaluated one-by-one in the order they are given, although various language features allow the evaluation of the program to jump around to different points in the program. A statement is always ended with a semicolon (;) and are typically written one statement per line (though they don't have to be.)
Human-readable comments, annotations, and any other text can be inserted into a program by using the tilde (~) to start your comment, and a second tilde to end it. They can be as short or long as you like, and can span multiple lines. E.g.,
~This is a comment. It spans multiple lines.~
All of the above, numbers, strings, symbols, and nil, are put together into these statements with operators. That is, operators are the glue that bind all of the above together. As Cellrunner evaluates (or processes) your programs, it looks for an operator, what's on each side of it, and computes the result. E.g.,
5 + 6; ~This evaluates to 11~
by taking the addition operator (+), adding together what's on either side of it and coming back with (or "returning") the result. Thus, above operator and operand group is a complete an expression and therefore is concluded with the semicolon. Several operators can be combined in one statement. E.g.,
5 + 6 * 8 - 4 / 2;
is a valid statement. It performs the multiplication first (6 * 8 = 48), then the division (4 / 2 = 2), then the addition (5 + 48 = 53) and the subtraction (53 - 2 = 51).
The complete set of mathematical operators are
and they all work as expected for performing basic arithmetic. The modulo, if you're not familiar with it, computes the remainder of a division operation. For example, when dividing 19 by 4, you get 4 with a remainder of 3. So,
19 % 4; ~returns 3.~
You are only allowed to use numbers, or symbols of numbers, as operands to these mathematical operators.
There is one operator that works on strings.
The concatenate operator joins two strings together into one longer string. E.g.,
"Hello, " $ "world!"; ~returns "Hello, world!"~
Both operands of the concatenate operator must be strings or symbols of strings.
Much of what a program does is to look at different values and compare them to each other for the purpose of branching to this or that section of the program depending on the result of the comparison. This is accomplished by returning a number that is either 0 which means false, or non-zero which means true. (Although I say non-zero, these operators will always return 1 for true. However, non-zero is more correct as a general term because any non-zero number is considered "true" by the language.) The equality operators are,
where = returns true if the operands are considered equal to each other and ! returns true when the operands are not considered equal to each other. In other words, given the same operands, = and ! will always return the opposite result. The equality operator can be described as follows,
The relational operators compare the relationship between numbers. They cannot be used on strings or nil. They are,
and should do as you expect.
4 < 5; ~returns true~ 4 > 5; ~returns false~ 5 < 5; ~returns false~ 5 <= 5; ~returns true~ 6 >= 4; ~returns false~
Often, you want to combine two or more equality and relational operators to logically combine in different ways. The logical operators achieve this. For example, suppose you wanted to know if the symbol x is greater then 5 and if the symbol y is less than 7. That is, if BOTH x is greater than 5 AND y is less than 7. If they're both true, then we want to return true, but if one is true and the other isn't, or if they're both false, return false. For this, you'd use the logical-and operator, &, as follows,
x > 5 & y < 7;
and the statement will evaluate as desired. The complete list of logical operators are,
The difference between logical-or and logical-nor is that logical-or translates to "if one or the other or both are true, than return true otherwise return false if they're both false" and logical-xor translates to "return true if one or the other are true, but not if they're both true or if they're both false." Think of this as like choosing a side dish with your sandwich at a restaruant. The waiter asks you if you would like soup or salad with your sanadwich, meaning you can choose either one or the other side dish but you can't have both.
The negated versions of each logical operator are simply logically inverted from their non-negated counterpart. For example, logical-nand can be translated to "return FALSE if either one or the other or both are true, otherwise return TRUE if they're both true."
Finally, the logical-not operator logically negates its operand. That is, false becomes true and true becomes false. It is unique in that it alone is an operator that only takes one operand whereas all the others take two, one operand on each side of the operator. In the case of logical-not, the operand is placed just after the ^. E.g.,
^1; ~returns false~
All of the logical operators must have zero or non-zero numbers as their operands.
The following truth-tables will show every logical return from each combination of true or false imputs for each logical operator. The left and right colums indicate the truthiness of both the left- and right-hand operands, and the last column indicates the result.
left | right | logical-and (&) -----+-------+---------------- 0 | 0 | 0 0 | 1 | 0 1 | 0 | 0 1 | 1 | 1 left | right | logical-nand (@) -----+-------+---------------- 0 | 0 | 1 0 | 1 | 1 1 | 0 | 1 1 | 1 | 0 left | right | logical-or (|) -----+-------+---------------- 0 | 0 | 0 0 | 1 | 1 1 | 0 | 1 1 | 1 | 1 left | right | logical-nor (\) -----+-------+---------------- 0 | 0 | 1 0 | 1 | 0 1 | 0 | 0 1 | 1 | 0 left | right | logical-xor (#) -----+-------+---------------- 0 | 0 | 0 0 | 1 | 1 1 | 0 | 1 1 | 1 | 0 left | right | logical-xnor (?) -----+-------+---------------- 0 | 0 | 1 0 | 1 | 0 1 | 0 | 0 1 | 1 | 1 right | logical-not (^) -------------+---------------- 0 | 1 1 | 0
All of the above operators and types are vital for building up statements. However, they have one major problem as they've been explained so far. As soon as a statement is evaluated and a result is calculated, that result is immediately thrown away and is gone forever. This would seem to make the whole excerise useless. However, that's where symbols and the assignment operator come into play.
The assignment operator is used to create symbols. A symbol "points" to a piece of data assigned to it and can be used in place of the data itself. E.g.,
my_symbol: 5;
creates a symbol named my_symbol and assigns the number 5 to it. Once that's done, you can use my_symbol in place of 5.
sum: my_symbol + my_symbol; ~sum is assigned the number 10~
If you assign a new value to an existing symbol, the previous value is lost and the new value takes its place.
value: 12; ~the symbol "value" is created and assigned the number 12~ value: "Cell Runner"; ~The previous value 12 is discarded and the string "Cell Runner" takes its place~
You can also use the symbol in a statement that results in assigning the same symbol a new value.
counter: 1; ~set counter to 1~ counter: counter + 1; ~add one to counter, and assign the result to counter, making it now a symbol for the number 2~ counter: counter + 1; ~and again, counter is now a symbol for the number 3~ ## Operator precedence ## Blocks ## Functions ### Calling functions #