SEL Flow Control

SEL Flow Control

 

Line Structure

Unless a line is flow control line (e.g. if/else, while, opening and closing braces etc.- this does NOT include &return lines) e.g. if it is a statement/expression (this DOES include &return statements), the line must be terminated with a semicolon ;  There is only one exception to this rule and that is if the line is the only line passed to the SEL interpreter (e.g. in your ABML tags if you only have one line to pass for SEL processing you may omit the semi colon, but for practice purposes I recommend always including it to prevent lax coding behaviour).

e.g.

$gold=$gold+1;

… is valid

This will cause an error:

$gold=$gold+1

$skill=$skill+1;

Since both those lines will be looked at as 1 line combined.

 

Flow control with IF…ELSE

SEL’s IF statement (and associated ELSE) operate, in general terms, the same as any other programming language.

IF (condition)
{
statement…;
…;
…;
}
ELSE
{
statement…;
…;
…;
}

The condition is any valid SEL expression that evaluates to either 0, NULL, or “” for FALSE, and any non-zero type value for TRUE (e.g. a negative number actually counts as TRUE). If the expression evaluates to TRUE then the block of statements delimited by the curly braces { and } immiediately after the IF statement will be executed, and unsurprisingly if the condition evaluates FALSE, the block will not be executed.

The ELSE statement can only be used in conjunction with an IF statement, and must follow directly after the closing brace } of the IF condition block. It requires no arguments/conditions, as it merely applies the converse of the IF result as it would in plain English – when condition of the IF statement is FALSE, the ELSE’s block of statements is executed, and when it is TRUE it is not. Quite simply: IF (something is true) {do this} ELSE {do this}.

In regards to the condition of the IF statement, beginners should take care when trying to make an equality statement. IF ($gold=10) may seem as if the author is testing to see whether the variable $gold equals 10, but this is in fact a very common error, as the single ‘=’ actually assigns the value 10 to the variable $gold. The author, if as is most likely, wants to make a comaparitive equality statement, the ‘==’ double equal sign should be used.

Please also note that the terminating semi-colon is not used after the IF or the ELSE statement, unlike normal statements which always require that. A semi-colon after IF or ELSE will cause errors in your code.

A quick note to any programmers wondering whether the brace blocks are necessary for 1 statement, yes I am afraid they are. You cannot do IF (condition) statement; Also Perl programmers may be wondering whether: statement IF (condition); is possible. Again the answer is no. They will not be forthcoming either, unless someone can write me a proper guide to parsing in 3 easy steps – I might do it then 😉

Looping with WHILE

Again as with IF, WHILE operates like any other programming language

WHILE(condition)
{
statement…;
…;
…;
}

When executing the program, the first time a WHILE is encountered it behaves like an IF statement – if the condition is TRUE, the block is executed, otherwise it is skipped. Unlike the IF however, if the block is executed, the program goes back to the beginning of the WHILE and and tests the condition again, and if it is still true, the block is executed again, and so on until the condition evaluates to false

As with SEL IF, the normal semi-colon statement terminator should not be used on the WHILE itself. And again, there is no abbreviation or variation on the structure of the WHILE loop – use it as shown or not at all.

Beginners (and experienced programmers still commonly make this mistake), should be 100% sure that at some time in the block something will change to make the condition evaluate false. Otherwise you will have an infinite loop on your hands, which unfortunately will never report as an error, but will be obvious as your code will ‘hang’ – not producing any output or accepting input. In reference to using this with ABML for an adventure, the page you are hoping will appear just never will in any form, erroneous or otherwise, and most likely you will receive a Gateway Timeout error from your internet browser.

Subroutines with SUB

As with all languages, reinventing the wheel is annoying and pointless. Which is why subroutines (or more correctly, functions) exist. If you have a program that ‘rolls dice’ frequently, you don’t want to have to write several lines of the same code each time you want to do this. SUB allows you to write a block of statements and give it a name, so that when you want to ‘roll dice’, instead of writing several lines of code, you can simply say &roll_dice; Whenever the program sees that statement it will pop off to the subroutine, do those lines of code, and once finished it will come back to the point it left, and carry on.

This explanation of SUB is very simplistic, but if you are new to this concept, it will do for now – programers should already know what else to expect from subroutines/functions, and beginners can look into the details following the example once they are comfortable with its simplest form.

Defining a SUB follows this form:

sub subname ($parameter1,$parameter2,…$parameterX)
{
statement…;
…;
…;
}

Using a SUB is simply a matter of using the subname, preceeded with an ampersand, &, followed by any parameters required (with optional parentheses if you need to worry about precedence):

&MySubroutine($value1,$value2);

or

&MySubroutine $value1,$value2;

Firstly, for alarmed beginners, when creating a SUB, parameters are optional – and when using a SUB that has no parameters you need not worry about the parentheses/parameters after &MySubroutine; Having said that though, most useful SUB’s do require parameters to be passed to them.

At this time in development, SUB’s can only be defined in a Library file. However since at this time the only access to what is considered the ‘main’ program is the code you have in your ABML tags (e.g. every file you edit in the Function Editor is considered a library file) it is unlikely you will fall foul of this error.

When creating a SUB, bear in mind that the name must be unique – not only in the file you are writing, but also in any files that are ‘included’ with it. Although a clash of names will not cause an error directly, it is uncertain which SUB will actually be used when you call that name – which could well cause other errors depending on how its used in your code. This is an issue that is pretty high on my list of developing a more satisfactory solution.

The list of parameters in SUB creation are all local variables that are created automatically when the SUB is called, as though you had used the &my function. They are filled with whatever is actually passed when the SUB is used, e.g. if I had a SUB declared in my library like so:
sub &dice ($howmany)
{
do some statements…
}
and somewhere else, I used it like this:
&dice(3);

The program would go to my SUB called &dice, and fill the local variable $howmany with the value ‘3’. I could then use that variable in the SUB &dice statements, most likely to determine how many dice need to be rolled.

If somebody passes a variable into a SUB, say I used the &dice sub like this:
&dice($monsters);
… using $monster instead of the number ‘3’ from the previous example, then the $howmany variable in the sub would receive whatever number $monster currently holds. It is very important to know however, that if the variable $howmany is changed in the sub, this DOES NOT MEAN that $monster will change. In programming terms this means that all SEL functions and subs are pass by value and not pass by reference. If this is gobbledegook to you, don’t worry, I only mentioned it for any experienced programmers that may be wondering. And if they are wondering whether I will add the facility for pass by reference, the answer is maybe, but don’t hold your breath.

Returning Values from a SUB

Now you may be wondering why I mentioned at first that SUB’s are more correctly called Functions. First, I should describe what a Function is – it is simply a SUB that returns a value. This means it can be used where, say, a number or a sentence would be used. To give you an idea, lets say we are making a Dungeons and Dragons character. A D&D character has six attributes, Strength, Intelligence and so on, the value of each determined by rolling 3 dice. so, we have our six variables $strength, $intelligence, and we need to fill them with the value of 3 rolled dice each. This, using a sub that returns a value – a function – would be done like this:
$Strength=&dice(3);
$Intelligence=&dice(3);
… and so on
But what allows us to use a sub like that? In a word, its another builtin function* like &my called &return. In a sub, when the program encounters &return, it immiediately exits the sub and returns the value(s) given as parameters. In our dice example, the sub would look something like this:

sub &dice($howmany)
{
&my $count,$result;
$count=1;
WHILE ($count {
$result=$result+&random(1,6);
}
&return $result;
}

If again thats gobbledegook, dont worry – all thats important to understand is that when we get to the bold line &return $result;, $return holds the value of 3 random numbers from 1 to 6, added up, and &return passes that number back to where the function &dice was ‘called’. Any statements after &return are not executed, which may not sound as silly as it seems – you might want to create a function that returns different things under different circumstances, using an IF statement – a good example of which would be something like a function to Test Luck.

Lastly I would like to note that ‘local’ variables are described under the &my function entry of the SEL Reference, and the importance of using &my should not be understimated if you embark upon writing your own functions. It is important because after a while it starts getting hard to remember what variables you have used for something, and if you had to remember what variable names were used in every library that your book uses it would be impossible, and errors would start coming up all the time. Using &my lets you create a function that uses those variables safe in the knowledge that if there is another variable with the same name elsewhere, it wont matter because the variable you are using is ‘hidden’ from the rest of the code and wont interfere with it. In my example dice function, changing the variable $count will not affect any other variable called $count, anywhere else, ever. Likewise with $result.

So, you can see a function is merely a subroutine that returns a value. Strictly speaking it is actually the other way around – a Subroutine is a function that doesn’t return a value – even that is not strictly speaking true either! Every sub does return a value, whether you use &return or not – it returns the value of the last statement evaluated before the subs’ closing brace } – return is often just a way of making it clearer what is actually being returned. Perl programmers will be comfortablwe with this, but for everyones sake I recommend using &return at all times for clarity if you design a sub to return a value.

Passing Lists to a SUB

If you wish to pass a list to a SUB, and you do not know how long this list might be, you will want to be able to receive that list into one variable name for use in the SUB – the definition outlined above is only useful for single value parameters. Say for example you want to pass the entire contents of the characters equipment list into a sub – how do you write an argument list that receives all those values when you do not know how many itms there will be? Simply define the variable name in the argument list with an @ sign instead of the usual $ sign – but only in the argument list, use $ to refer to that variable thereafter. All items passed at that point in the parameter list to the end will be put into the variable name denoted by the @ – for example:

sub &check_equipment($looking_for, @equipment)

{
if (&countinlist($equipment, $looking_for))
{
&return “The item is in the equipment list”;
}
else
{
&return “The item is not in the equipment list”;
}
}

Please also note – using an @ name in the argument list will swallow ALL arguments passed to the function at that point onwards, therefore in a sub declaration:

sub &check_equipment($looking_for, @equipment, $another_parameter)…

The argument $another_parameter will *NEVER* receive a value, because the list argument @equipment swallows all remaining parameters passed to the function. It follows therefore that you can only a) Have 1 list argument in a function, and b) A List argument should always be the last argument in a SUB declaration

 

Comments:

Comments are a way of documenting your code for your reference or anothers in the code itself – i.e. ‘what does that line do?’.  To add a comment to your code simply create a line that starts with the # symbol.  Everything written after this symbol will be completely ignored when the code is executed.

 

*Techie Note:defining Return as a function rather than a flow control directive was a concious design decision, again down to my lack of proper parsing knowledge, I just did what seemed to work. One day this may change, but like implementing pass by reference, don’t hold your breath

Leave a Reply

An online project to bring the worlds of Fighting Fantasy, Lone Wolf, Choose Your Own Adventure and other Gamebooks to life

Skip to toolbar