GalaxyHack AI scripts can be written using any program capable of editing text files - Notepad++, Notepad, KWrite, etc. However, make sure you always save files as plain text files - don't, for instance, save them as .docs in a word processor. In addition, they must be given the file extension ".ai", and they must be stored in the directory of the fleet that is going to use them (GalaxyHack/fleets/nameofyourfleet).
AI scripting differs slightly for different group types:
The following simple script gives targets for its fire commands, and so is really designed for a frigate, though it would also work for small ship groups and capital ships (which would just ignore the extra information given with the "fire" commands):
main:
#I can write anything I want to here!
if aenemy type == smallship health < 100
move nenemy type == smallship health < 100
fire nenemy type == smallship health < 100
else
move nenemy
fire nenemy
return
The first line of the script begins with "main:". Every single GalaxyHack AI script must begin with "main:". Lines that begin with a single word followed by a colon are function labels, which are dealt with somewhat later on.
After a little blank space there is a hash - "#". Anything that follows a hash is ignored by the game. You can put comments either on a line of their own or on the end of a line of code. You can use them to keep notes about how your script works, or keep a note of which bits need changing, or whatever you want.
The third line begins with "if". In GalaxyHack AI scripts everything must be in lowercase.
An "if" command can do one of two similar things. If the first group named in a comparison is a group of "nearest" type, it performs a comparison between two numbers. For example, you can compare the nearest group's distance to the number 500. Comparing 500 to the nearest group's distance (i.e. the other way round) is also allowed.
If the first group in a comparison is of an "any" type group, it is comparing one number against many other numbers in turn. You might for instance check whether any enemy group is less than 500 distance, for which the game will compare 500 to every enemy group's distance. Though logically it might be possible, GalaxyHack will not let you do "any" group type comparisons the other way round - you cannot check whether 500 is less than any enemy's distance.
There are various different group types that you can specify in AI commands - see the reference guide for a complete list - including, for instance, our, nenemy, or afriend. "our" simply means the group running the script. "n" stands for "nearest", whilst "a" stands for "any".
If, overall, an "if" evaluates to "true", then the script will continue on to the command (or block of commands) that follows on the next line. If the comparison turns out to be false, the script skips the next command (or block of commands). It is possible to nest if/else/elif statements - e.g. you can have one "if" block inside the block of another "if" statement.
A "block" is a group of commands which share the same amount of tabbed indentation. Rather than using curly brackets or "endif" statements or some other method of showing where blocks of code begin and end, GalaxyHack works out which commands are grouped together by looking at how many tabs each line of code begins with. Note that you must use tabs to indent blocks of code, you cannot use the space bar. By grouping commands into blocks you can execute or skip a large number of commands on the basis of a single "if" test.
Returning to our example script, the "if" is checking whether there are any enemy groups that are composed of small ships, and in addition have less than 100 health.
After specifying a group type, we need to specify what piece of information we want from that group - again see the reference guide for a complete list. Examples include "bigammo" and "health". Specifiers usually total up the stats of all the units in a group - e.g. health is the total health of all the units in a group.
To get a piece of information from a group, you name the group type, followed by the piece of information that it is you want to get at.
As well as specifying a piece of information about a group, you also have the option of using a positive integer number in comparisons, e.g. "if aenemy health < 56". "Integer" means no decimal points or fractions.
Various "operators" allow you to compare pieces of information. A full list is available in the reference guide. The most important ones are probably > ("greater than"), < ("less than") and == ("equals"). It is important to note that to check for equality you must use TWO equals signs, because a single equals sign is used to assign a new value to a variable (see later).
In this AI script the first comparison is between the type of the group and "smallship". In this case using a greater than or less than operator wouldn't make any sense - we want to know if the group equals a smallship group or it doesn't, so we check for equality with "==". We then demand a further piece of information from the same group with "if aenemy type == smallship health < 100". If we had written:
if aenemy type == smallship && aenemy health < 100
then the game would evaluate firstly whether there is an enemy group which is composed of small ships, and secondly whether there is also an enemy group with less than 100 health. It is possible that there might be one enemy group which is composed of small ships, and another with less than 100 health, but at the same time there could well be no enemy groups at all for which both conditions are true. By putting just a space inbetween two different stat comparisons, we can see whether multiple conditions all apply to a single group.
If the "if" statement tests true, then the indented block following the "if" will be run. This block tells the group to move towards the nearest enemy group which is composed of small ships and which also has less than 100 health, and then also to fire at that group. GalaxyHack features two sorts of weapons: "small" and "big". "small" weapons are either single or twin lasers. These are dealt with automatically by the game - you dont need to tell units to fire them. "big" weapons - which means missiles, torpedos and very large lasers - must be scripted, or they will not fire. As noted at the top of this page, frigates must specify a target for their big weapons, whilst for small ships their fire target is always the same as their current movement target.
If the "if" does not test true, then the indented block following the "else" is run instead. In this example script the else block instructs the group to move towards and fire at the nearest enemy, regardless of their type or health.
* * * * * * *
It is important to note that in GalaxyHack AI scripts logical operators (e.g. ==, >, <) are used in two very different ways. Their meaning depends on whether they are on a line with an "if" or "elif" statement, or on a line with a "move" or "fire" statement.
If used on a line with an if/elif, then they mean "has" - e.g. "if aenemy has health more than 500" or "if nfriend has distance less than than 300". In if/elif commands, every single operator means "has", and therefore "nenemy" or other nearest type groups always refer to information about the very closest group of that type.
In this context, any of the following can appear on either side of a logical operator:
A specified piece of information about an any enemy/friend can appear only on the left hand side of a comparison.
It is also possible to use if statements to check whether two groups (e.g. saved groups) refer to the same actual group. See the AI scripting reference for details.
Ands (&&) and ors (||) can be used in if/elif statements to check whether multiple statements are true - e.g. "if aenemy health > 500 && nfriend speed < 10".
If used on a line with move, moveaway, patrol or fire then these operators behave very differently - in these cases, the logical operator is used not to check whether a condition is true, but instead to specify a target. In this context, they always mean "with", e.g. "Fire at the nenemy with health more than 500". As you are specifing a singular target you are only able to specify a "nearest" or "saved" type of group, not an "any" type group - it wouldn't be much of a strategy to "move towards any group" even if the interpreter let you.
Exactly what comes after a command for your group to perform an action depends on the action and the type of group the command is issued to - see the reference sections on move/moveaway, patrol and fire. In general, these commands are followed by a description of the sort of group you would like to target - which must be be one of:
It is possible to specify requirements for a target using the following:
In both if/elif contexts and fire/move/moveaway/patrol contexts you can specify multiple pieces of information that must all apply to the same group. In the statement "if aenemy health > 500 && aenemy smallpower < 200", we are testing two seperate conditions - whether any enemy has health more than 500, and whether any enemy has smallpower less than 200.
However, we may well want to find out if aenemy has health > 500 as well as smallpower < 200. To do this, we just use a space - e.g. "if aenemy health > 500 smallpower < 200".
* * * * * * *
A brief rundown on a few more features of the scripting language not yet mentioned follows. Full details on these and others can be found in the AI scripting reference guide.
* * * * * * *
main:
if aenemy health < 500 && aenemy distance < our bigrange
#do some stuff
else
@myfunction
return
myfunction:
#do some other stuff
return
The above demonstrates the principle of function calls. These allow you to make repeated use of a particular block of code, and also give your script a clear structure that makes it easy to make changes to, even if it becomes very large and complex.
Note that a group can process a maximum of 100 instructions before executing a final "return".
* * * * * * *
Arithmetic - +, -, /, *, %. This is fairly self explanatory - rather than writing "if $1 == nenemy health", you might for instance write "if $1 * 2 == nenemy health / 3".
* * * * * * *
Each group has 10 integer variables - $1 through $0 - that can have their value changed by you. These provide a mechanism for your groups to remember what they have done previously, as well as a variety of other uses. There are also $global1 through $global0 - these variables are global to your whole fleet and if one unit changes one of these, then it will be different for all the groups. These provide a simple mechanism for your groups to communicate with each other.
You can change the value of these variables using a single equals sign, e.g. "$1 = 5". These variables can then be used in "if"/"elif" comparisons just like any other values.
You also have access to another 20 variables of a rather different nature: $g1 ... $g0, and $globalg1 ... $globalg0. These are savegroup variables, which store a certain group rather than a certain value. So you might for instance write:
main:
$g1 = nenemy
move $g1
return
There are also a further 10 variables which are timers - $timer1 ... $timer0. An example of how they could used follows:
main:
if $1 == 0
starttimer 1
$1 = 1
if $timer1 < 40
move e
elif $timer1 < 80
move s
elif $timer1 < 120
move w
elif $timer1 < 160
move n
else
starttimer 1
move e
return
* * * * * * *
There are three ways in which GalaxyHack supports debugging of AI scripts:
1. When AI scripts are loaded before a battle starts the game checks for any obvious problems in the script. If it finds any then it writes what it has found to an error file, and the game will refuse to let you enter the battle.
2. Each fleet has an AI error report window. Some errors are caught by the game and displayed in this window. The first time a fleet causes an AI error in a battle a popup window will alert you. Only the first error for each group is reported to prevent the system being brought to a crawl by a flood of error reports.
3. You can open windows showing the current value of both global and per-group script variables and saved groups. As well as using variables to control your fleet, you can also use them as debug watches to see what is being triggered when.
4. You can open various windows displaying information about a group's AI decisions and status mid-battle, and take note of what they say to discover possible problems.