Scripting: Difference between revisions

From Archon Wiki
Jump to navigation Jump to search
(Created page with "Scripting Archon scripting is as much expanded iteration on the original STUB scripting. The original documentation is included/updated below. Script Syntax CScript is a s...")
 
 
(11 intermediate revisions by 3 users not shown)
Line 1: Line 1:
Scripting
Archon scripting is a much expanded iteration on the original STUB scripting.  The original documentation is included/updated below.


Archon scripting is as much expanded iteration on the original STUB scripting.  The original documentation is included/updated below.
== Script Syntax ==
 
Script Syntax


CScript is a simple scripting language, based on the basic C syntax. It provides a simple framework to hook it up to an application, effectively the function call handling.
CScript is a simple scripting language, based on the basic C syntax. It provides a simple framework to hook it up to an application, effectively the function call handling.
Line 13: Line 11:
All scripting must be part of a function. A function has the form:
All scripting must be part of a function. A function has the form:


FUNCTION <name>( [<param>], [<param>], ...)
<code>FUNCTION <name>( [<param>], [<param>], ...)
{
{
<function body>
<function body>
}
}</code>


For example
For example


FUNCTION Tick( side )  
<code>FUNCTION Tick( side )  
{
{
}
}</code>
 
or
 
<code>FUNCTION Process( TType data )
{
}</code>


There is a limit of 12 parameters that can be passed to a given function.
There is a limit of 12 parameters that can be passed to a given function.
Line 28: Line 32:
All functions return a value, although you do not have to use it, nor use the return should you decide not to. To return a value use:
All functions return a value, although you do not have to use it, nor use the return should you decide not to. To return a value use:


return <value> ;
<code>return <value> ;</code>
 
Note that a call to return will skip any further processing in the function and exit with the value immediately.
Note that a call to return will skip any further processing in the function and exit with the value immediately.


Macros
=== Macros ===


You can define macros - textual substitutions - in the same way as for C.  Note that #/## notations are not supported.  E.g.
You can define macros - textual substitutions - in the same way as for C.  Note that #/## notations are not supported.  E.g.


#define MAX_UNITS 256
<code>#define MAX_UNITS 256</code>


Structures
==== Predefined Macros ====
 
Some macros may be predefined based on other data files.  The names of these predefined macros will always begin with a $ character and all characters will be in uppercase.
* Macros will be predefined for all colours specified in the COLOURDICTIONARY chunk of DATA/UISETTINGS.TXT that are appropriate for use where script commands expect colours as parameters.
* Macros will be predefined for all fonts specified in SYSTEM/FONT.TXT that are appropriate for use where script commands expect fonts as parameters.
 
For example, <code>DrawMapString(x, y, $SMALLFONT, $ALERTCOLOUR)</code>
 
=== Structures ===


You can define structures in a similar way to C.  The format is:
You can define structures in a similar way to C.  The format is:


struct <typename>
<code>struct <typename>
{
{  
<contents>
<contents>
}
}</code>


For example
For example


struct TPos
<code>struct TPos
{
{
int x ;
int x ;
int y ;
int y ;
}
}
 
struct TObject
struct TObject
{
{  
int type ;
int type ;
TPos position ;
TPos position ;
int orders[4] ;
int orders[4] ;
}
}</code>


Access is as per standard C syntax:
Access is as per standard C syntax:


TObject obj ;
<code>TObject obj ;
obj.type = 5 ;
obj.orders[0] = 0 ;
obj.position.x = 9 ;</code>


obj.type = 5 ;
=== Control ===
obj.orders[0] = 0 ;
obj.position.x = 9 ;
 
Control


You have 2 ways to control the flow of a function. The IF statement, and the FOR statement. All code executed by an IF or FOR statement must be enclosed in a block (within a { } pair).
You have 2 ways to control the flow of a function. The IF statement, and the FOR statement. All code executed by an IF or FOR statement must be enclosed in a block (within a { } pair).
Line 75: Line 88:
An IF statement has the form:
An IF statement has the form:


if( <condition> )
<code>if( <condition> )
{
{
<execute if condition true>
<execute if condition true>
}
}
else
else if( <condition 2> )
{
{
<execute if condition false>
<execute if condition 2 true>
}
}
else
{
<execute if neither condition false>
}</code>


Note that the else keyword and following code is optional. Where the condition can be made up of various logical operators such as && (and) and || (or). So an example statement would be:
Note that the else keyword and following code is optional. Where the condition can be made up of various logical operators such as && (and) and || (or). So an example statement would be:


if( ( a == 10) || ( b == 5 ) )
<code>if( ( a == 10) || ( b == 5 ) )
{
{
}
}</code>


A FOR statement has the form:
A FOR statement has the form:


for(<start>; <condition>; <delta>)
<code>for(<start>; <condition>; <delta>)
{
{
}
}</code>


<start> is a statement initialising the loop variable, <condition> is a check where the loop will continue so long as it is true, and the <delta> statement is a simple expression incrementing (or decrementing) the loop variable. So the statement:
<start> is a statement initialising the loop variable, <condition> is a check where the loop will continue so long as it is true, and the <delta> statement is a simple expression incrementing (or decrementing) the loop variable. So the statement:


for( i=0; i<10; i++ )
<code>for( i=0; i<10; i++ )
{
{
}
}</code>


would repeat the code inside the block with i having values of 0 to 9 inclusive, before moving onto any following code.
would repeat the code inside the block with i having values of 0 to 9 inclusive, before moving onto any following code.
Line 110: Line 127:
+ IF statements can can use only a single && or || statement pair when expressions are not contained in brackets. That is:
+ IF statements can can use only a single && or || statement pair when expressions are not contained in brackets. That is:


if( a == 0 && b == 0 && c == 0 ) is invalid
<code>if( a == 0 && b == 0 && c == 0 ) is invalid
if( (a == 0) && (b == 0) && (c == 0) ) is valid</code>
 
+ All atomic variables are signed integers.


if( (a == 0) && (b == 0) && (c == 0) ) is valid
+ Single line IF and FOR result expressions are not allowed:


+ There is no concept of ELSE IF() in the language. You can only pair a single ELSE with any IF statement.
<code>if(a == 0) is invalid
a = 10 ;
if(a == 0) is valid
{
a = 10 ;
}</code>


+ FOR statements do not allow bracketed terms in the increment (3rd) expression. That is:
+ All structures are passed by reference to functions (e.g. any changes to a passed in struct in a function will affect the passed in variable in the calling function).


for( a = 0 ; a < 10 ; a += (10 – c ) ) is invalid


+ All atomic variables are signed integers.
=== Including Files ===


+ There is no implicit typing of arrays.
You can include other files in your scripts. These can contain useful utility functions, either of your own, or from the game. The syntax for including a file is:


int big[10][10] ;
<code>include "filename.bsf"</code>
int small[10] ;


small = big[3] is invalid
(note that #include will work also)


+ String expressions are only allowed as input to function calls. There is currently very limited support for string functionality (see below).
The script system will look for the file in the following places in the following order:


+ Single line IF and FOR result expressions are not allowed:
same folder as the initial file
<campaign folder>/DATA/BATTLE/SCRIPTS
<campaign folder>/DATA/SCRIPTS
DATA/BATTLE/SCRIPTS
DATA/SCRIPTS
filename as provided


if(a == 0) is invalid
=== Singletons ===
a = 10 ;


if(a == 0) is valid
Any variables defined outside a function are considered to be global, singleton variables.  These variables are a single instance across all scripts that access them.  You can also initialise singletons (but not local variables) this initialiser lists.  These should exactly match the number of entries, and do not support sub-lists.  E.g.
{
a = 10 ;
}


+ All structures are passed by reference to functions (e.g. any changes to a passed in struct in a function will affect the passed in variable in the calling function).
<code>int gArray[3][2]={0,1,2,3,4,5} ;</code>
Including Files


You can include other files in your scripts. These can contain useful utility functions, either of your own, or from the game. The syntax for including a file is:
=== The char Type ===


include "filename.bsf"
You can define and use arrays of chars as strings.  Versions of the sprintf and strcpy functions exist.  These functions are safe, in that they cannot exceed the bounds of their output strings.


(note that #include will work also)
<code>char name[32] ;
char work[32] ;
int someValue ;
someValue = 99 ;
name[0] = 'A' ;
PrintStringLiteral( name ) ;
sprintf( work, "%d", someValue ) ;
strcpy( name, work ) ;</code>


The script system will look for the file in the following places in the following order:
Limitations to note:


same folder as the initial file
char arrays must be multiples of 4 in size, multidimensional arrays are supported.
<campaign folder>/DATA/BATTLE/SCRIPTS
<campaign folder>/DATA/SCRIPTS
DATA/BATTLE/SCRIPTS
DATA/SCRIPTS
filename as provided


Singletons
== The Debugger ==
There is an integrated script debugger which can be activated with <b>CTRL+F3</b>.  This allows you to check variable values, flow, etc.  Note that the debugger is still work in progress.  You can insert a breakpoint into your code using the


Any variables defined outside a function are considered to be global, singleton variables. These variables are a single instance across all scripts that access them.  You can also initialise singletons (but not local variables) this initialiser lists.  These should exactly match the number of entries, and do not support sub-lists.  E.g.
  <code>DebugBreak;</code>


int gArray[3][2]={0,1,2,3,4,5} ;
intrinsic, as well as dynamic breakpoints you set yourself in the code.


The char Type
=== User Watch List ===
To add an expression, type the expression in the edit box below the list, or you can hit W to add the current mouseover expression to the watch list.  DEL should delete an entry in the list.  The list is saved and loaded between sessions.


You can define and use arrays of chars as stringsThis functionality is still under construction. And example is:
Note that only expressions which evaluate to an integer or string are currently accepted (so you cannot enter an array element then explore it)I am planning to improve this.


char name[32] ;
When maximum script debugging is enabled (only on builds built to support this) then add a # to the start of the expresion.  E.g. to break on myBreakVar enter #myBreakVar into the editbox.  Note that this requires the DEBUGMODE value in USER.TXT to be 32 or 64 (64 enables CTRL+0 (zero) to break into a running script.  Enabling this causes a notable reduction in script performance.


name[0] = 48 ;
== Performance ==
PrintStringLiteral( name ) ;
=== For Loops ===
Some loop constructs will execute more quickly than others.  Specifically loops that are on a variable from a numeric start, with a less than test against either a numeric value or a simple variable, and a ++ increment.


Limitations to note:
Faster
for(i=0;i<10;i++)
for(i=0;i<count;i++)


char arrays must be multiples of 4 in size
Not faster
multidimensional string arrays are not supported (possible they may be)
for(i=0;i<=10;i+=1)
character notation (e.g. ‘A’) is not implemented, but will be.
for(i=x;i<array[7].count;i++)

Latest revision as of 17:05, 17 October 2018

Archon scripting is a much expanded iteration on the original STUB scripting. The original documentation is included/updated below.

Script Syntax

CScript is a simple scripting language, based on the basic C syntax. It provides a simple framework to hook it up to an application, effectively the function call handling.

Even if you have not had experience with scripting languages before, you can begin to add or alter your custom scripts using just a simple text editor (see the Tools section for details on how to help make editing better with syntax highlighting and other useful features).

The team recommend taking a look at the existing scripts to begin to see the way the scripting works. Beginning by tweaking existing scripts is a great way to see something onscreen quickly.

All scripting must be part of a function. A function has the form:

FUNCTION <name>( [<param>], [<param>], ...)
{
	<function body>
}

For example

FUNCTION Tick( side ) 
{
}

or

FUNCTION Process( TType data )
{
}

There is a limit of 12 parameters that can be passed to a given function.

All functions return a value, although you do not have to use it, nor use the return should you decide not to. To return a value use:

return <value> ;

Note that a call to return will skip any further processing in the function and exit with the value immediately.

Macros

You can define macros - textual substitutions - in the same way as for C. Note that #/## notations are not supported. E.g.

#define MAX_UNITS 256

Predefined Macros

Some macros may be predefined based on other data files. The names of these predefined macros will always begin with a $ character and all characters will be in uppercase.

  • Macros will be predefined for all colours specified in the COLOURDICTIONARY chunk of DATA/UISETTINGS.TXT that are appropriate for use where script commands expect colours as parameters.
  • Macros will be predefined for all fonts specified in SYSTEM/FONT.TXT that are appropriate for use where script commands expect fonts as parameters.

For example, DrawMapString(x, y, $SMALLFONT, $ALERTCOLOUR)

Structures

You can define structures in a similar way to C. The format is:

struct <typename>
{ 
	<contents>
}

For example

struct TPos
{
	int x ;
	int y ;
}

struct TObject
{ 
	int type ;
	TPos position ;
	int orders[4] ;
}

Access is as per standard C syntax:

TObject obj ;

obj.type = 5 ;
obj.orders[0] = 0 ;
obj.position.x = 9 ;

Control

You have 2 ways to control the flow of a function. The IF statement, and the FOR statement. All code executed by an IF or FOR statement must be enclosed in a block (within a { } pair).

An IF statement has the form:

if( <condition> )

{
	<execute if condition true>
}
else if( <condition 2> )
{
	<execute if condition 2 true>
}
else
{
	<execute if neither condition false>
}

Note that the else keyword and following code is optional. Where the condition can be made up of various logical operators such as && (and) and || (or). So an example statement would be:

if( ( a == 10) || ( b == 5 ) )
{
}

A FOR statement has the form:

for(<start>; <condition>; <delta>)
{
}

<start> is a statement initialising the loop variable, <condition> is a check where the loop will continue so long as it is true, and the <delta> statement is a simple expression incrementing (or decrementing) the loop variable. So the statement:

for( i=0; i<10; i++ )
{
}

would repeat the code inside the block with i having values of 0 to 9 inclusive, before moving onto any following code.

Key Differences with C

+ There is no operator priority. Brackets are supported and their use recommended.

+ IF statements can can use only a single && or || statement pair when expressions are not contained in brackets. That is:

if( a == 0 && b == 0 && c == 0 )		is invalid

if( (a == 0) && (b == 0) && (c == 0) )	is valid

+ All atomic variables are signed integers.

+ Single line IF and FOR result expressions are not allowed:

if(a == 0)							is invalid
	a = 10 ;

if(a == 0)							is valid
{
	a = 10 ;
}	

+ All structures are passed by reference to functions (e.g. any changes to a passed in struct in a function will affect the passed in variable in the calling function).


Including Files

You can include other files in your scripts. These can contain useful utility functions, either of your own, or from the game. The syntax for including a file is:

include "filename.bsf"

(note that #include will work also)

The script system will look for the file in the following places in the following order:

same folder as the initial file
<campaign folder>/DATA/BATTLE/SCRIPTS
<campaign folder>/DATA/SCRIPTS
DATA/BATTLE/SCRIPTS
DATA/SCRIPTS
filename as provided

Singletons

Any variables defined outside a function are considered to be global, singleton variables. These variables are a single instance across all scripts that access them. You can also initialise singletons (but not local variables) this initialiser lists. These should exactly match the number of entries, and do not support sub-lists. E.g.

int gArray[3][2]={0,1,2,3,4,5} ;

The char Type

You can define and use arrays of chars as strings. Versions of the sprintf and strcpy functions exist. These functions are safe, in that they cannot exceed the bounds of their output strings.

char name[32] ;
char work[32] ;
int someValue ;

	someValue = 99 ;
	name[0] = 'A' ;
	PrintStringLiteral( name ) ;
	sprintf( work, "%d", someValue ) ;
	strcpy( name, work ) ;

Limitations to note:

char arrays must be multiples of 4 in size, multidimensional arrays are supported.

The Debugger

There is an integrated script debugger which can be activated with CTRL+F3. This allows you to check variable values, flow, etc. Note that the debugger is still work in progress. You can insert a breakpoint into your code using the

DebugBreak;

intrinsic, as well as dynamic breakpoints you set yourself in the code.

User Watch List

To add an expression, type the expression in the edit box below the list, or you can hit W to add the current mouseover expression to the watch list. DEL should delete an entry in the list. The list is saved and loaded between sessions.

Note that only expressions which evaluate to an integer or string are currently accepted (so you cannot enter an array element then explore it). I am planning to improve this.

When maximum script debugging is enabled (only on builds built to support this) then add a # to the start of the expresion. E.g. to break on myBreakVar enter #myBreakVar into the editbox. Note that this requires the DEBUGMODE value in USER.TXT to be 32 or 64 (64 enables CTRL+0 (zero) to break into a running script. Enabling this causes a notable reduction in script performance.

Performance

For Loops

Some loop constructs will execute more quickly than others. Specifically loops that are on a variable from a numeric start, with a less than test against either a numeric value or a simple variable, and a ++ increment.

Faster

for(i=0;i<10;i++)
for(i=0;i<count;i++)

Not faster

for(i=0;i<=10;i+=1)
for(i=x;i<array[7].count;i++)