ACS

Scripting with [[Vavoom]] is just like scripting for [[Hexen]], and [[Hexen]]’s acs utility is even used to compile scripts. The only significant difference is that scripts should include ”’vcommon.acs”’ instead of ”common.acs” so that they can get definitions appropriate for [[Vavoom]] instead of [[Hexen]]. This file just includes three others:

* vspecial.acs * vdefs.acs
* vwvars.acs

The [[Hexen]] Script Language is called ”’Action Code Script”’, or ”ACS”.

Each map has an ACS file that contains the scripts specific to that map. The scripts within it are identified using numbers that the general special [[ACS_Execute]] uses.

A script itself can call the [[ACS_Execute]] special, which will spawn (start) another script that will run concurrently (at the same time) with the rest of the scripts.

A script can also be declared as ”’OPEN”’, which will make it run automatically upon entering the map. This is used for perpetual type effects, level initialization, etc.

The compiler takes the ACS file and produces and object file that is the last lump in the map WAD (”’BEHAVIOR”’).

To create a compiled ACS file from a text script from DOS type: C:\HEXEN> ACS filename [enter]

== Script Shared Structure ==
Map scripts should start with ”#include “vcommon.acs””, which is just…

#include “vspecial.acs” #include “vdefs.acs” #include “vwvars.acs”

The file ”’vspecial.acs”’ defines all the general specials. These are used within scripts just like function calls. The file ”’vdefs.acs”’ defines a bunch of constants that are used by the scripts. The file ”’vwvars.acs”’ defines all the world variables. It needs to be included by all maps so they use consistent indexing.

== Variables and their Scope ==

There is only one data type ACS, a 4 byte integer. Use the keyword ”int” to declare an integer variable. You may also use the keyword ”str”, it is synonymous with ”int”. It’s used to indicate that you’ll be using the variable as a string. The compiler doesn’t use string pointers, it uses string handles, which are just integers.

”’Declaring a variable”’
There are two “types” of variables:

1. “str” 2. “int”

A third type of informal variable is a fixed-point number. This type is the same as int (and is identified as an int), except that half the number is treated as a fractional value. To convert from an int to a fixed, shift the number left by 16 (<< 16). To convert from a fixed to an int, shift the number right by 16 (>> 16). If you use a decimal point in a number (e.g. 35.0 instead of 35), acc will automatically create the correct fixed point value for you. ACS includes some commands specifically for performing fixed point math. examples:

str mystring; int myint;

or:

str texture, sound; int i, tid;

”’Note:”’ You can’t assign a variable in its declaration; you must give it a value in a different

expression.
The SCOPE of a variable is one of the following:

1. World-scope 2. Map-scope 3. Script-scope

”World-scope”

World-scope variables are global, and can be accessed in any map. [[Hexen]] maintains 64 permanent globals, numbered 0-63. You must assign one of the globals a name in order to access it, like this:

world int 5:Grunt;

This tells [[Hexen]] to reference world global number 5 whenever it encounters the name “Grunt”.

”Map-scope”

Map-scope variables are local to the current map. They must be declared outside of any script code, but without the world keyword. These variables can’t be accessed in any other map.

”Script-scope”
Script-scope variables are local to the current script – they can’t be accessed by any other script or map.

Here’s some code that shows the declaration of all three scopes: world int 3:DungeonAccess; ”’// World-scope”’
int mapTimer; ”’// Map-scope”’

script 4 (void) {

int x, y; ”’// Script-scope”’

… }

== Language Grammar ==
Here is a quick reference manual type definition of the language.
”’Keywords”’
The following identifiers are reserved for use as keywords, and may not be used otherwise:

* break
* case
* const
* continue * default

* define * do

* else
* goto
* if
* include * int

* open
* print
* printbold * restart

* script
* special * str
* suspend * switch

* terminate * until
* void
* while

* world

Comments

Comments are ignored by the script compiler. There are two forms: 1. /*…your comment… */

All information between the first /* and last */ is ignored. The leading /* and trailing */ are required. 2. // your comment

All information past the // is ignored examples:

/*
This is a comment.

*/

int a; // And this is a comment ”’World-variable definitions”’

world int <constant-expression> : <identifier> ;

world int <constant-expression> : <identifier> , … ; ”’Map-variable definitions”’
Declares a variable local to the current map.

int <identifier> ;
str <identifier> ;
int <identifier> , … ;

”’Include Directive”’

Includes the source of the specified file and compiles it. This acts the same as if you have “included” the source in the file it resides in. Use this to make a common reference set of code you use often.

#include <string-literal>
The supplied required includes shown earlier are an illustration:

#include “specials.acs” #include “defs.acs” #include “wvars.acs”

”’Define Directive”’
Replaces an identifier with a constant expression.

#define <identifier> <constant-expression>

Whenever “identifier” is used in the source, the “constant-expression” is substituted. This is similar to a macro or keyboard short-cut.

”’Constant Expressions”’ <integer-constant>:

decimal (200)
hexadecimal (0x00a0, 0x00A0)


fixedpoint(32.0, 0.5, 103.329)

any radix <radix>_digits :

binary (2_01001010)
octal (8_072310)
decimal (10_50025) hexadecimal (16_00a03f2)

”’String Literals”’ <string-literal>:

“string”

Example: “Hello there”

”’Script Definitions”’ To define a script: <script-definition>:

script <constant-expression> ( <arglist> ) { <statement> }

script <constant-expression> OPEN { <statement> } For example:

script 10 (void) { … }
script 5 OPEN { … }
”’Note:”’ that OPEN scripts do not take arguments.

”’Statements”’ <statement>:

<declaration-statement> <assignment-statement> <compound-statement> <switch-statement> <jump-statement> <selection-statement> <iteration-statement> <function-statement> <linespecial-statement> <print-statement> <control-statement>

”’Declaration Statements”’

Declaration statements create script variables.

<declaration-statement>:
int <variable> ;
int <variable> , <variable> , … ;

”’Assignment Statements”’
Assigns an expression to a variable. <assignment-statement>:

<variable> <assignment-operator> <expression> ; <assignment-operator>:

=
+=
-=
*=
/=
%=
”’Note:”’ An assignment of the form V <op>= E is equivalent to V = V <op> E. For example: A += 5;

is the same as

A = A + 5;
”’Compound Statements”’ <compound-statement>:

{ <statement-list> }

<statement-list>:

<statement>

<statement-list> <statement> ”’Switch Statements”’

A switch statement evaluates an integral expression and passes control to the code following the matched case.

<switch-statement>:
switch ( <expression> ) { <labeled-statement-list> }

<labeled-statement>:
case <constant-expression> : <statement>

default : <statement>

Example:

switch (a) {

case 1: b = 1; break;

case 2: b = 8;

// when a == 1
// .. this is executed,
// and this breaks out of the switch().

// when a == 2
// .. this is executed,

// but there is no break, so it continues to the next

// case, even though a != 3. case 3: // when a == 3

b = 666; // .. this is executed,

break; // and this breaks out of the switch(). default: // when none of the other cases match,

b = 777; // .. this is executed. }

”’Note for C users:”’

While C only allows integral expressions in a switch statement, ACS allows full expressions such as

“a + 10”.
”’Jump Statements”’

A jump statement passes control to another portion of the script. <jump-statement>:

continue;

break;

restart;
”’Iteration Statements”’

<iteration-statement>:
while ( <expression> ) <statement>
until ( <expression> ) <statement>
do <statement> while ( <expression> ) ;
do <statement> until ( <expression> ) ;
for ( <assignment-statement> ; <expression> ; <assignment-statement> ) <statement>

The continue, break and restart keywords can be used in an iteration statement:

* the continue keyword jumps to the end of the last <statement> in the iteration-statement. The loop continues.

* the break keyword jumps right out of the iteration-statement.
”’Function Statements”’
A function statement calls a Hexen internal-function, or a Hexen linespecial-function. <function-statement>:

<internal-function> | <linespecial-statement>
<internal-function>:

<identifier> ( <expression>, … );

<identifier> ( const : <constant-expression> , … ) ;

<linespecial-statement>:

<linespecial> ( <expression> , … ) ;

<linespecial> ( const : <constant-expression> , … ) ; ”’Print Statements”’

<print-statement>:
print ( <print-type> : <expression> , … ) ; printbold ( <print-type> : <expression> , … ) ;

<print-type>: s (string)
d (decimal)
c (constant)

”’Selection Statements”’ <selection-statement>:

if ( <expression> ) <statement>

if ( <expression> ) <statement> else <statement> ”’Control Statements”’

<control-statement>:
suspend; // suspends the script

terminate; // terminates the script