BSL:Introduction: Difference between revisions

From OniGalore
Jump to navigation Jump to search
(okay, I was going to say a lot more, but that will have to wait until later)
(textual overview, replacing the table that I think is more confusing than helpful)
Line 1: Line 1:
Like any scripting or programming language, BSL uses branching logic and logical operators to build functions which process data that is stored in variables.
{{TOCfloat}}
Like any typical scripting or programming language, BSL scripts consist of [[#Files|plain-text files]] which use [[#Logic|branching logic]] and [[#Operators|various operators]] to process [[#Types|data]] with [[#Functions|functions]] that act upon [[#Variables|variables]]. Click one of those words to jump to the brief explanations of those terms below, but if you are new to programming, you'll also want to read the "Details" pages that are linked to.


==Syntax overview==
For those familiar with C, the syntax is similar and you will feel at home in BSL, but BSL's feature set is stripped down to a degree that is simpler than even most scripting languages. Fortunately, this makes BSL fast to learn.
{| border="1" cellpadding="5" cellspacing="0" style="margin-left:auto; margin-right:auto;" align="center"
{{clearall}}
|+'''BSL syntax overview table'''
==Files==
|-
When Oni loads a level, it also loads and parses all .bsl files in the folder in [[IGMD]] which contains that level's scripts (the name of the folder being specified by the level's [[ONLV]] resource). Like C, the code automatically begins running with the function called "main", regardless of which .bsl file it is found in.
| style="border-bottom:3px solid grey;"|
 
{| border="0"
From that point on, only other functions that are called by main() will run on their own, though you can also manually call any of those functions from the [[Developer Mode|developer console]] (however, you cannot actually define variables or functions through the console). Thus, to see how the script for a level will flow, you must locate the main() function and read from there.
|+''BSL separators''
 
|-
Note that the optional [[global]] folder is also loaded for all levels, but this code cannot run on its own unless you edit another function that does run automatically so that it calls a function in a global BSL file.
| width="100px" | [[BSL:Statements|<tt>;</tt>]]
 
| width="100px" | [[BSL:Functions|<tt>,</tt>]]
==Logic==
| width="100px" | [[BSL:Comments|<tt>#</tt>]]
:''See [[BSL:Statements]] for details.''
| width="100px" | [[BSL:Types|<tt>"</tt>]]
In order to react to various conditions, you need branching logic, which basically boils down to an if-else statement in this form:
|-
 
| width="100px" | [[BSL:Statements|<tt>{</tt>]]
if (value1 operator value2)
| width="100px" | [[BSL:Statements|<tt>}</tt>]]
{
| width="100px" | [[BSL:Functions|<tt>(</tt>]]
   
| width="100px" | [[BSL:Functions|<tt>)</tt>]]
}
|-
else
| colspan="4" style="border-top:1px solid red; border-right:1px solid red; border-bottom:2px solid red; border-left:1px solid red;" |
{
Click on a separator for details
   
|}
}
|-
 
| style="border-bottom:3px solid grey;"|
To explain the above:
{| border="0"
*The arrangement of braces and whitespace is somewhat flexible, but this is the standard style used in most places and is considered to be the most readable style.
|+''BSL operators''
*You may not need the "else" statement, in which case simply omit it.
|-
*<tt>value1</tt> and <tt>value2</tt> can be variables or constants. <tt>operator</tt> refers to one of the arithmetical or relational operators in BSL (see "Operators" below). A typical "if" statement would look like...
| width="100px" | [[BSL:Operators|<tt>+</tt>]]
 
| width="100px" | [[BSL:Operators|<tt>-</tt>]]
if (counter eq 3)
| width="100px" | [[BSL:Variables|<tt>=</tt>]]
{
| width="100px" | [[BSL:Operators|<tt>!</tt>]]
    # some code here
|-
}
| width="100px" | [[BSL:Operators|<tt>and</tt>]]
 
| width="100px" | [[BSL:Operators|<tt>or</tt>]]
...where counter is a variable declared beforehand (see "Variables" below). You can also test multiple conditions at once in an "if" statement.
| width="100px" | [[BSL:Operators|<tt>eq</tt>]]
 
| width="100px" | [[BSL:Operators|<tt>ne</tt>]]
==Operators==
|-
:''See [[BSL:Operators]] for details.''
| width="100px" | [[BSL:Operators|<tt><</tt>]]
We're all familiar with the four basic arithmetical operations: addition, subtraction, multiplication and division. Well, BSL only has the first two :-) They're the "+" and "-" symbols, as you would expect. Example:
| width="100px" | [[BSL:Operators|<tt>></tt>]]
 
| width="100px" | [[BSL:Operators|<tt><=</tt>]]
counter = counter + 1 # increases counter's value by one
| width="100px" | [[BSL:Operators|<tt>>=</tt>]]
 
|-
To compare two values, you use relational operators, like this:
| colspan="4" style="border-top:1px solid red; border-right:1px solid red; border-bottom:2px solid red; border-left:1px solid red;" |
 
Click on an operator for details
if (counter < 3)
|}
 
|-
==Types==
| style="border-bottom:3px solid grey;"|
:''See [[BSL:Types]] for details.''
{| border="0"
 
|+''BSL keywords''
When declaring a variable or a function, you must specify the type of data it contains or returns:
|-
 
| width="75px" | [[BSL:Keywords|<tt>at</tt>]]
var int x;
| width="75px" | [[BSL:Types|<tt>float</tt>]]
func int my_func(void)
| width="75px" | [[BSL:Statements|<tt>if</tt>]]
{...}
| width="75px" | [[BSL:Keywords|<tt>repeat</tt>]]
 
| width="75px" | [[BSL:Types|<tt>string</tt>]]
You can choose from "bool" (can be true/false or 1/0), "int" (can be any whole number), "float" (a value with a decimal point), or "string" (some text).
|-
 
| width="75px" | [[BSL:Types|<tt>bool</tt>]]
==Functions==
| width="75px" | [[BSL:Keywords|<tt>for</tt>]]
:''See [[BSL:Functions]] for details.''
| width="75px" | [[BSL:Types|<tt>int</tt>]]
Unlike C, functions do not need to be declared or defined before they are called. Functions are defined by starting with the keyword "func", then giving the type of data (see "Types" above) that the function returns, then the name of the function. After that, any parameters it receives should be listed within parentheses. Finally, the actual code for the function should be given within braces, like so:
| width="75px" | [[BSL:Functions|<tt>return</tt>]]
 
| width="75px" | [[BSL:Keywords|<tt>using</tt>]]
func int my_awesome_function(int some_input)
|-
{
| width="75px" | [[BSL:Statements|<tt>else</tt>]]
    # code here that acts on "some_input"
| width="75px" | [[BSL:Functions|<tt>fork</tt>]]
}
| width="75px" | [[BSL:Keywords|<tt>iterate</tt>]]
 
| width="75px" | [[BSL:Keywords|<tt>schedule</tt>]]
Now that it is defined, we can call it from anywhere in the BSL for the same level by using this invocation:
| width="75px" | [[BSL:Variables|<tt>var</tt>]]
 
|-
var result = my_awesome_function(counter); # sets "result" to the result of the function after it processes "counter"
| width="75px" | [[BSL:Keywords|<tt>every</tt>]]
 
| width="75px" | [[BSL:Functions|<tt>func</tt>]]
Note that (1) we can set a variable to the result (see "Variables below) and then use that value elsewhere, and (2) the name of the variable we pass in to the function does not have any relation the name that the function uses for that value internally. That's because we might simply desire to pass a constant number to the function:
| width="75px" | [[BSL:Keywords|<tt>over</tt>]]
 
| width="75px" | [[BSL:Keywords|<tt>sleep</tt>]]
var result = my_awesome_function(3);
| width="75px" | [[BSL:Types|<tt>void</tt>]]
 
|-
No matter what, the value passed in will be called "some_input" inside the function.
| colspan="5" style="border-top:1px solid red; border-right:1px solid red; border-bottom:2px solid red; border-left:1px solid red;" |
 
Click on a keyword for details
==Variables==
|}
:''See [[BSL:Variables]] for details.''
|}
 
You've already seen some example of variable declaration. One more thing to be aware of is that variables can be initialized upon declaration:
 
var int y = 9;
 
or not:
 
var int y;
 
In the second case, "y" is set automatically to zero.
 
When declaring variables, it's important to be aware of scope. The scope is the range of the BSL script within which the variable can be referred to. If a variable is declared with global scope...
 
func some_function
{...}
 
var int y = 0;
 
func another_function
{...}
 
...then it can be accessed from both some_function and another_function, and any other function in the level's BSL files, for that matter. If it is declared with function scope...
 
func another_function
{
    var int y = 0;
}
 
...then it can only be accessed within that function. If it is declared with block scope...
 
func another_function
{
    if (...)
    {
      var int y = 0;
      ...
    }
}
 
...then only other code inside the "if" block can access it.


[[Category:BSL syntax]]
[[Category:BSL syntax]]

Revision as of 23:41, 3 December 2015

Like any typical scripting or programming language, BSL scripts consist of plain-text files which use branching logic and various operators to process data with functions that act upon variables. Click one of those words to jump to the brief explanations of those terms below, but if you are new to programming, you'll also want to read the "Details" pages that are linked to.

For those familiar with C, the syntax is similar and you will feel at home in BSL, but BSL's feature set is stripped down to a degree that is simpler than even most scripting languages. Fortunately, this makes BSL fast to learn.

Files

When Oni loads a level, it also loads and parses all .bsl files in the folder in IGMD which contains that level's scripts (the name of the folder being specified by the level's ONLV resource). Like C, the code automatically begins running with the function called "main", regardless of which .bsl file it is found in.

From that point on, only other functions that are called by main() will run on their own, though you can also manually call any of those functions from the developer console (however, you cannot actually define variables or functions through the console). Thus, to see how the script for a level will flow, you must locate the main() function and read from there.

Note that the optional global folder is also loaded for all levels, but this code cannot run on its own unless you edit another function that does run automatically so that it calls a function in a global BSL file.

Logic

See BSL:Statements for details.

In order to react to various conditions, you need branching logic, which basically boils down to an if-else statement in this form:

if (value1 operator value2)
{
   
}
else
{
   
}

To explain the above:

  • The arrangement of braces and whitespace is somewhat flexible, but this is the standard style used in most places and is considered to be the most readable style.
  • You may not need the "else" statement, in which case simply omit it.
  • value1 and value2 can be variables or constants. operator refers to one of the arithmetical or relational operators in BSL (see "Operators" below). A typical "if" statement would look like...
if (counter eq 3)
{
   # some code here
}

...where counter is a variable declared beforehand (see "Variables" below). You can also test multiple conditions at once in an "if" statement.

Operators

See BSL:Operators for details.

We're all familiar with the four basic arithmetical operations: addition, subtraction, multiplication and division. Well, BSL only has the first two :-) They're the "+" and "-" symbols, as you would expect. Example:

counter = counter + 1 # increases counter's value by one

To compare two values, you use relational operators, like this:

if (counter < 3)

Types

See BSL:Types for details.

When declaring a variable or a function, you must specify the type of data it contains or returns:

var int x;
func int my_func(void)
{...}

You can choose from "bool" (can be true/false or 1/0), "int" (can be any whole number), "float" (a value with a decimal point), or "string" (some text).

Functions

See BSL:Functions for details.

Unlike C, functions do not need to be declared or defined before they are called. Functions are defined by starting with the keyword "func", then giving the type of data (see "Types" above) that the function returns, then the name of the function. After that, any parameters it receives should be listed within parentheses. Finally, the actual code for the function should be given within braces, like so:

func int my_awesome_function(int some_input)
{
   # code here that acts on "some_input"
}

Now that it is defined, we can call it from anywhere in the BSL for the same level by using this invocation:

var result = my_awesome_function(counter); # sets "result" to the result of the function after it processes "counter"

Note that (1) we can set a variable to the result (see "Variables below) and then use that value elsewhere, and (2) the name of the variable we pass in to the function does not have any relation the name that the function uses for that value internally. That's because we might simply desire to pass a constant number to the function:

var result = my_awesome_function(3);

No matter what, the value passed in will be called "some_input" inside the function.

Variables

See BSL:Variables for details.

You've already seen some example of variable declaration. One more thing to be aware of is that variables can be initialized upon declaration:

var int y = 9;

or not:

var int y;

In the second case, "y" is set automatically to zero.

When declaring variables, it's important to be aware of scope. The scope is the range of the BSL script within which the variable can be referred to. If a variable is declared with global scope...

func some_function
{...}
var int y = 0;
func another_function
{...}

...then it can be accessed from both some_function and another_function, and any other function in the level's BSL files, for that matter. If it is declared with function scope...

func another_function
{
   var int y = 0;
}

...then it can only be accessed within that function. If it is declared with block scope...

func another_function
{
   if (...)
   {
      var int y = 0;
      ...
   }
}

...then only other code inside the "if" block can access it.