Community ACS Tutorial
Contents |
Introduction
This is the tutorial, started by kuchikitaichou and, i hope, will be edited by someone good with ACS. My grammar may be worst, but I hope this help to develop your maps with nice effects, caused by ACS (like invasion, ctf, etc..). Hope it'll help. This page is still in development.
Script structure
You should start by getting to know the script structure. A script is made with the following syntax:
script <script number> <script type>
{ //Open script
//<comment>
<actions>
} //Close script
Comment: // makes a comment line. Compiler will ignore anything after the slashes. For multi-line comments you may use the following:
/* - open comment. */ - close comment.
Script number: This is the script identifying number. The same number can't be used twice.
Script type: Script type is how script will be activated. There's list of some:
OPEN //Script activates just when the game is started. ENTER //Activates When the player enters the game. (void) //Script must be activated by line special (action 80) or other script.
More about script types you can find out there.
Actions: List of actions. View under.
An example script would be:
#include "zcommon.acs"
script 1 OPEN
{
print(s:"Hello, world!");
}
This script will be run as soon as the map is loaded. It will print "Hello, world!" on the screen.
ZCommon.acs
ZCommon is an ACS file, that contains function definitions, constants, and other useful stuff. It should always be included in your ACS with the following syntax:
#include "zcommon.acs"
This should always be the very first line of your ACS file. Once you get into more complex scripting, you may have more than one #include line. For now, though, this is all you need.
Identifiers
Variables
Variable syntax:
int <identifier>=<value>; //Setting value is optional. You can use 'int <indentifier>;'. str <stringident>="<string>"; //String must be in quotes. bool <booleanident>=TRUE/FALSE; //Boolean has only TRUE or FALSE.
A variable's value can be changed anywhere in the scripts. If you want all of your scripts have that identifier (global variable), declare the variable before your scripts as been below:
#include "zcommon.acs" //Look above... int i; int j=1; str k="lol"; bool t=TRUE; script ...
If you want only one script to have the identifier (local variable), declare the variable inside the scripts body:
script 1 open
{
int i; //NOTE: i won't work in other scripts.
<actions>
}
To change a variable's value, state the identifier, an operator, and then depending on your operator a value in which the variable should equal as seen below:
i=1; i=playercount(); i=-6; i=3+6; i++; //Increases i by 1. i--; // Decreases i by 1.
You may use a constant (see below) or another variable in these statements if you wish.
Constants
Constant syntax:
#define <identifier> <value> //Can be integer or string.
A constant is like a variable, however its value can not be changed and will always remain the same. Some constant examples from zcommon.acs:
#define TRUE 1 #define FALSE 0 #define TEAM_BLUE 0 #define TEAM_RED 1 #define NO_TEAM 2
Arrays
An array is a collection of variables of the same type. Array syntax:
<type> <identifier>[<array count>]={<value of array 1>,<value of array 2>...}; //Can be used:
int[x].
Type: Can be int, str, bool.
Identifier: See above.
Array Count: Number of values in identifier.
Value of array x: Setting array's value. Some examples:
int x[2]={1,3}; //This one is correct one.
int x[1]={1,3); //This one is bad, it wont be compiled.
int x[3]={1,3}; //This one will be compiled, but last array's value will be 0.
NOTE: If array is:
int y[3]={5,7,9};
Then values will be:
y[0]=5 y[1]=7 y[2]=9
As you can see, arrays are in [0;n-1] interval.
Functions and procedures
Function is procedure that does some action, and, if it isn't set void (read on to know), it returns value. Uses the following syntax:
#include "zcommon.acs"
function <type> <function name>(<arguments used>)
{
<actions>
}
Type: Can be the following:
<pe> int str bool void </pre>
Void means that it's not function, but just a procedure. Procedure doesn't return any value. It just does some actions. Example:
function void clearprint(void)
//clearprint is function name and void is arguments used.
//if arguments are void, function uses no arguments.
//if arguments are identified like "function void meh(int i)", then
//you must use this function like this: "meh(25)".
{
print(s:""); //This cleans middle screen, if there's something printed.
}
If you use else types, function goes like this:
function bool isthereimps(void)
{
if(thingcount(T_IMP,0)==0) //If there's no imps...
return TRUE; //returning true.
return FALSE; //returning false.
}
Some skulltag function examples:
getinvasionwave() getinvasionstate() bluecount() redcount()
Functions are mostly used in if stuff.
NOTE: You cannot use latent functions (delays, scriptwait, tagwait etc.) in functions.
Conditional Script
If
If syntax:
if(<condition>)
{
<actions>
}
Condition: If condition is TRUE, then script will execute, else it'll be skipped. Condition can be a function, with returns a boolean value, alone or equality:
if(i==3) if(j>5) if(playerredskull()) //NOTE: This function is disabled in 0.97b
These symbols are used:
== equal //if(i==5) != not equal //if(i!=6) > more than //if(i>3) < less than //if(i<4) >= more or equal //if(i>=0) <= less or equal //if(i<=7) && and //if(i>=4&&i<=7) || or //if(i==1||i==2) ! not //if(!i==1||i>=3)
Else
Else is used after if script. Else syntax:
if(...)
{
...
}
else
{
...
}
If that condition is FALSE, if actions wont be executed, but instead, else actions will be executed. Additional else if statements can be added if multiple conditions are needed. Examples:
if(...) action; else if(...) action; else action;
While
While is loop script, that is executing till the condition is FALSE. While syntax:
While(bluecount()!=redcount())
{
print(s:"Team player counts are not equal! Game start failed!");
delay(35); //Loops must have at least 1 tic pause beetwen looping...
}
door_open(...); //When teams are not equal, loop goes.
//When loop stops, door_open script executes.
Do...While
Quite the same as While but use this if you want to run the loop at least one time. Do...While syntax:
Do {
} While (Condition);
Different with the While loop is that the condition will be tested at the end of the block instead of the beginning so the loop will at least run once and if the condition is true it goes back to the beginning of the block and will execute it again.
example:
Int x = 3;
Do {
Print(s:"lol");
Delay(1);
} While(x != 3);
This will print lol at least one time at the screen, after that it checks if the condition is true (what is not the case) and if so it will print 'lol' again until the condition returns false.
For
Loop for goes fixed ammount of cycles. For syntax:
for(<identifier>;<condition>;<action, executed each time>)
{
<actions>
}
Example:
for(int j=1;j<=6;j++) //Loop goes 6 times.
{
for(int i=1;i<=6;i++)
{
thing_spawn(i,T_IMP,0,0); //Spawns 6 Imps in map spots in [1;6] interval.
}
delay(35);
}
Until
Opposite to while.
Commands and functions
You'll, at last, know what actions is. Syntax is simple:
//Must be in script...
script 1 open
{
<command>(<argument1>,<argument2>...);
}
Prints and HUDs
print(type:text); //Text appears on activator's screen. printbold(type:text); //Text appears on everyone's screen. hudmessage(type:text;hud type,hud id,color,x,y,duration...fadeouttime/fadeintime/typetime/fadeouttime); hudmessagebold(-"-); // I guess this doesn't need to be explained. setfont(font string);
Example:
script 1 enter
{
print(s:"Please select your team.");
setfont("BigFont");
hudmessage(s:"Temple by kuchikitaichou";HUDMSG_FADEOUT,0,CR_GREEN,0.5,0.96,15.0,1.0);
setfont("SmallFont");
}
Other
A lot of functions you can find in:
Built-in ACS functions
Action Specials
Skulltag ACS functions
Useful script stuff
Entering credit script
The following script will appear when player enters the game.
script 1 enter
{
hudmessage(s:"Welcome!";HUDMSG_FADEOUT,0,CR_GRAY,0.5,0.96,15.0,1.0);
}
Team selecting
You know what to do...
script 1 (int iBase,int iAction)
{
switch(iAction)
{
case 0:
{
switch(iBase)
{
case TEAM_BLUE:
print(s:"\chBlue team hall.");
break;
case TEAM_RED:
print(s:"\cgRed team hall.");
break;
case NO_TEAM:
print(s:"\ccAutoselect hall.");
break;
}
break;
}
case 1:
{
int i;
if(iBase!=NO_TEAM)
i=iBase;
else
{
if(bluecount()==redcount())
i=random(TEAM_BLUE,TEAM_RED);
else if(bluecount()<=redcount())
i=TEAM_BLUE;
else
i-|TEAM_RED;
}
break;
}
player_setteam(i);
activatorsound("announcer/97b/preparetofight",127);
if(i=TEAM_BLUE)
teleport(...);
else
teleport(...);
}
}
For Invasion
The following script makes executing wait till the wave and state you need.
script 1 open
{
while((getinvasionwave()!=3)||(getinvasionstate()!=IS_COUNTDOWN)
delay(1); //While wave is not 4 and state is not countdown, wait 1 tic.
//After...
<actions>
}
What you need for making ACS in Skulltag?
Well, you'll need latest ACC compiler, ACS configuration (if you're using DooM Builder) and any editing program (I can't tell you which one is the best, because I only ever used DB). That is all.