BSL:Introduction: Difference between revisions

From OniGalore
Jump to navigation Jump to search
(→‎Syntax: moving details to BSL:Syntax; some syntax corrections)
(Introduction is now explicitly aimed at the experienced coder who just wants the short story, not the long story at BSL:Manual)
Line 1: Line 1:
{{TOCfloat}}
This page gives a brief look at BSL for those with scripting or programming experience. For those familiar with a typical procedural language like C, BSL's syntax and concepts will be very familiar, but BSL's feature set is stripped down to a degree that is simpler than even most scripting languages. For details on any aspect of the language, look at the [[BSL:Manual|Manual]] page.
Like any typical scripting or programming language, BSL scripts consist of [[#Comments|commented]] [[#Files|plain-text files]] which employ [[#Logic|branching logic]] and [[#Operators|various operators]] according to a [[#Syntax|strict syntax]] to process [[#Types|data]] using [[#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 from each section.
{{TOClimit|2}}
 
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.
{{clearall}}
 
==Comments==
==Comments==
Comments are notes from the programmer to explain some code. They are supposed to be placed above or after a line of code:
Comments are marked with the pound sign:


'''# The following block of code calculates the meaning of life'''
  var int a = 0; # this global is also modified in my_cutscenes.bsl
if [block of code begins here]
 
  var int a = 0; '''# this global is also modified in my_cutscenes.bsl'''
 
In documentation outside of source code or script files, such as this page, they are still sometimes used to tell the reader something in a way that doesn't break the actual code, if the user should type it in exactly as it appears, comments and all.


==Files==
==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 (Oni's scripts always place it in a file called *_main.bsl). Only other functions that are called by main() (and the functions it calls) 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.
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 (Oni's scripts always place it in a file called *_main.bsl).
 
Note that the optional [[IGMD/global|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==
Note that the optional [[IGMD/global|global]] folder is also loaded for all levels, but any function found in a .bsl file there will be stranded and only accessible by console unless you edit a function in some level's existing BSL file so that it calls your global function.
:''See [[BSL:Statements]] for details.''
In order for game events to react to the player's actions, you need branching logic, which basically boils down to an if statement in this form:
 
if (counter eq 3) # "if counter's value is equal to three, do this..."
{
    # some code here
}
 
...where "counter" is a variable declared beforehand (see "Variables" below). By reading the BSL:Statements page, you can also learn how to test for multiple conditions at once in an "if" statement, use an "else" condition, etc.
 
==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)


==Syntax==
==Syntax==
:''See [[BSL:Syntax]] for details.''
BSL supports strong and weak syntax in some ways. Here's a typical statement:


===Punctuation===
dmsg("Hello");
Braces define blocks of code, whether the block is a function or a conditional:


func void some_function(void)
You can omit the semicolon, parentheses, and also the quotes if your string doesn't have any spaces in it:
'''{'''
    # some code
'''}'''


  if (condition)
  dmsg Hello
'''{'''
    # some code
'''}'''


In C-style BSL, semicolons end a statement, and parentheses enclose function parameters:
Similarly, here's the formal syntax for a snippet of code:


  func void some_function(void)
  func void some_function(void)
Line 70: Line 33:
  }
  }


The same code would look like this in shell-style BSL:
The same code would look like this in the weak syntax:


  func void some_function(void)
  func void some_function(void)
Line 83: Line 46:
  }
  }


Notice that parentheses are always needed with "if" statements and semicolons are always needed on variable declarations.
Notice that parentheses are always needed with "if" statements and semicolons are always needed on variable declarations. Note that using the strong syntax avoids certain weird aspects of BSL (see the Manual's "Old vs. new syntax" section for details).


==Types==
==Reserved words==
:''See [[BSL:Types]] for details.''
===Declaration===
You always need to use "var" when declaring a variable and "func" when defining a function:


When declaring a variable or a function, you must specify the type of data it contains or returns:
var int a = 0;
func int get_enemy_count(void)


var int x;
Functions do not need to be defined or declared before they can be called, unlike in C.
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).
===Type specification===
BSL does not support weak typing. You need to specify your types when making declarations, as seen in the above examples. You can choose from "bool", "int", "float" (rarely useful because of BSL's limited math operations), and "string". As with C, you use "void" to mean "no type" when defining functions.


==Functions==
===Conditional===
:''See [[BSL:Functions]] for details.''
You can make use of the standard if-else statement, and "if" can take multiple conditions:
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 curly braces, like so:


  func int my_awesome_function(int some_input)
  if ((a < b) and (c > d))
{
    # ...
}
else
  {
  {
     var some_output = some_input + 5;
     # ...
    return some_output;
  }
  }


Now that it is defined, we can call it from anywhere in the BSL for the same level by using this invocation:
There is no else-if statement.
 
===Flow interrupt===
There is no "goto" statement in BSL, nor any loop controls like "continue" or "break" (since there are no proper loops!). There's a "return" keyword in BSL, but you can't use it except at the end of the function because of a bug in BSL that will fire a "return" inside of an "if" statement regardless of whether the statement evaluates to true or false. So you only use "return" to return data, not to exit early (see "Functions" below).


var result = my_awesome_function(counter); # sets "result" to the the value of "counter" plus 5
There's also a "sleep" command that pauses BSL execution; you pass it a number in ticks:


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:
sleep(60); # wait for one second


var result = my_awesome_function(3);
===Loop===
There's no loop keyword like "for" or "while" in BSL, but you can kind of get a loop using one of two methods. First, you can call a function recursively, but BSL has a short stack, so don't expect to get more than four levels deep. If you just want a loop and not recursion, then you can avoid recursion by sleeping for a tick or so and then forking the recursive call. See [[BSL:Snippets]] for an example that also makes up for the missing multiply operator in BSL.


No matter what, the value passed in will be called "some_input" inside the function.
Second, you could use schedule-repeat-every:


==Variables==
schedule some_function() repeat 50 every 20;
:''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:
Just be aware that the BSL will continue executing without waiting for this loop to stop.


var int y '''= 9''';
===Multi-threading===
BSL doesn't have robust multi-threading, but you can sort of hack your own solution using "fork" or "schedule". Please see the Manual's section called "Concurrency" for examples.


or not:
==Operators==
Like some other languages, BSL differentiates between checking for equivalency ("eq") and setting equivalency ("="):
 
if (counter eq 3) ...
i = 4;
 
BSL's operators are pretty standard stuff:
+ -
eq ne < > <= >=
and or !


var int y;
But you'll note that there is no operator for multiplying or dividing. See the [[BSL:Snippets]] page for a cheap hack for multiplication.


In the second case, "y" is set automatically to zero.
==Data types==
You can choose from "void" (when defining a function), "bool", "int", "float", and "string":


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 void something(void)
var int a = 1;


func some_function
The "int" type is signed 32-bit. See the Manual's "Data types" section to learn about various limitations with math between types in BSL.
{...}<br>
var int y = 0;<br>
func another_function
{...}


...then it can be accessed from both <tt>some_function</tt> and <tt>another_function</tt>, or any other function in the level's BSL files, for that matter. If it is declared with function scope...
==Functions==
As mentioned above, functions do not need to be declared or defined before they are called. Defining and calling a function looks exactly like C, except for the "func" keyword:


  func another_function
a = get_enemy_count(false);<br />
  func int get_enemy_count(bool count_dead)
  {
  {
     var int y = 0;
     ...
    return count;
  }
  }


...then it can only be accessed within that function. If it is declared with block scope...
Once again, please see the Manual's "Functions" section to learn about concurrent and recursive calling.


  func another_function
==Variables==
{
As usual, variables can be explicitly initialized:
    if (...)
 
    {
  var int y = 9;
      var int y = 0;
 
      ...
or not:
    }
 
}
var int y;
 
In the second case, "y" is set automatically initialized to zero.
 
Variables can have global scope, if declared outside of a function.


...then only other code inside the "if" block can access it.
==Built-in functions and variables==
Like any game, Oni provides access to a number of hardcoded functions and global variables that can be used to write level scripts. They are listed [[BSL:Reference|here]], and grouped by common task in the [[:Category:Scripting tasks|Scripting tasks]] category.


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

Revision as of 22:19, 4 December 2015

This page gives a brief look at BSL for those with scripting or programming experience. For those familiar with a typical procedural language like C, BSL's syntax and concepts will be very familiar, but BSL's feature set is stripped down to a degree that is simpler than even most scripting languages. For details on any aspect of the language, look at the Manual page.

Comments

Comments are marked with the pound sign:

var int a = 0; # this global is also modified in my_cutscenes.bsl

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 (Oni's scripts always place it in a file called *_main.bsl).

Note that the optional global folder is also loaded for all levels, but any function found in a .bsl file there will be stranded and only accessible by console unless you edit a function in some level's existing BSL file so that it calls your global function.

Syntax

BSL supports strong and weak syntax in some ways. Here's a typical statement:

dmsg("Hello");

You can omit the semicolon, parentheses, and also the quotes if your string doesn't have any spaces in it:

dmsg Hello

Similarly, here's the formal syntax for a snippet of code:

func void some_function(void)
{
   var int a;
   a = 4;
   sleep(60);
   if (a eq 4)
   {
      dprint("Hello");
   }
}

The same code would look like this in the weak syntax:

func void some_function(void)
{
   var int a;
   a = 4
   sleep 60
   if (a eq 4)
   {
      dprint "Hello"
   }
}

Notice that parentheses are always needed with "if" statements and semicolons are always needed on variable declarations. Note that using the strong syntax avoids certain weird aspects of BSL (see the Manual's "Old vs. new syntax" section for details).

Reserved words

Declaration

You always need to use "var" when declaring a variable and "func" when defining a function:

var int a = 0;
func int get_enemy_count(void)

Functions do not need to be defined or declared before they can be called, unlike in C.

Type specification

BSL does not support weak typing. You need to specify your types when making declarations, as seen in the above examples. You can choose from "bool", "int", "float" (rarely useful because of BSL's limited math operations), and "string". As with C, you use "void" to mean "no type" when defining functions.

Conditional

You can make use of the standard if-else statement, and "if" can take multiple conditions:

if ((a < b) and (c > d))
{
   # ...
}
else
{
   # ...
}

There is no else-if statement.

Flow interrupt

There is no "goto" statement in BSL, nor any loop controls like "continue" or "break" (since there are no proper loops!). There's a "return" keyword in BSL, but you can't use it except at the end of the function because of a bug in BSL that will fire a "return" inside of an "if" statement regardless of whether the statement evaluates to true or false. So you only use "return" to return data, not to exit early (see "Functions" below).

There's also a "sleep" command that pauses BSL execution; you pass it a number in ticks:

sleep(60); # wait for one second

Loop

There's no loop keyword like "for" or "while" in BSL, but you can kind of get a loop using one of two methods. First, you can call a function recursively, but BSL has a short stack, so don't expect to get more than four levels deep. If you just want a loop and not recursion, then you can avoid recursion by sleeping for a tick or so and then forking the recursive call. See BSL:Snippets for an example that also makes up for the missing multiply operator in BSL.

Second, you could use schedule-repeat-every:

schedule some_function() repeat 50 every 20;

Just be aware that the BSL will continue executing without waiting for this loop to stop.

Multi-threading

BSL doesn't have robust multi-threading, but you can sort of hack your own solution using "fork" or "schedule". Please see the Manual's section called "Concurrency" for examples.

Operators

Like some other languages, BSL differentiates between checking for equivalency ("eq") and setting equivalency ("="):

if (counter eq 3) ...
i = 4;

BSL's operators are pretty standard stuff:

+ -
eq ne < > <= >=
and or !

But you'll note that there is no operator for multiplying or dividing. See the BSL:Snippets page for a cheap hack for multiplication.

Data types

You can choose from "void" (when defining a function), "bool", "int", "float", and "string":

func void something(void)
var int a = 1;

The "int" type is signed 32-bit. See the Manual's "Data types" section to learn about various limitations with math between types in BSL.

Functions

As mentioned above, functions do not need to be declared or defined before they are called. Defining and calling a function looks exactly like C, except for the "func" keyword:

a = get_enemy_count(false);
func int get_enemy_count(bool count_dead) { ... return count; }

Once again, please see the Manual's "Functions" section to learn about concurrent and recursive calling.

Variables

As usual, variables can be explicitly initialized:

var int y = 9;

or not:

var int y;

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

Variables can have global scope, if declared outside of a function.

Built-in functions and variables

Like any game, Oni provides access to a number of hardcoded functions and global variables that can be used to write level scripts. They are listed here, and grouped by common task in the Scripting tasks category.