How
to write an AI script
This part explains how to create a small Protoss AI script step by step
with ScAIEdit or PyAI. It doesn't explain all the commands. You may
check the advanced scripting part to get more information.
General recommendations:
- Try to keep your code simple.
- Put comments by starting a line with ;
- Make backups of your different code versions.
- Choose your own coding conventions. Here are the ones I
try to follow.
Overview:
A bit of vocabulary I will use later.
- The AI runs the different commands line by line. Starting by the
first line.
- Some commands are "blocking", meaning the AI won't go to the next
line until a condition is verified. e.g. It's possible to make the AI
waiting to have 2 barracks before starting marines training.
- Some commands allow "jumps", it's possible to do loops with them.
e.g. AI do an attack with 10 zealots, wait 2 minutes, do another attack
with 10 zealots, wait 2 minutes and so on...
- Some commands allow parallelism execution. e.g. AI will build in
the main base and in the expansion simultaneously.
- Some commands have a priority parameter. The exact functionment
of priority is still unknown as far as I know. High priority commands
can block the low priority ones.
Now choose the compiler you use:
Script with PyAI
Note: The script editor integrated in
PyAI is not completely stable when this part was written - 8 May 2008 -
it's recommend to often save the script with another text editor
regularly - as a .txt file for example.
You will see all basic commands in this script. You can choose a
particular section too.
Header commands:
These commands are put at the very beginning of the script. Their
effects is not always well known.
#
stat_txt.tbl entry 1343: Protoss Expansion Custom Level<0>
PMCx(1343, 101, aiscript):
# This line and the following are
comments
# Starting headers
start_town()
transports_off()
farms_notiming()
- PMCx(1343, 101,
aiscript), this line is for the default Protoss Expansion custom AI, do
not modify it.
- start_town: command to
start a new town, generally used when creating a new expansion.
- farms_notiming: disable
automatic pylon/supply depot/overlords building.
- transports_off: command
used for ground maps. The AI won't create automatically transports.
Now we define the maximum number for the different units. This is
generally done just after header commands but that's not an obligation.
# Maximum number of units
define_max(80, Protoss Probe)
define_max(20, Protoss Zealot)
define_max(20, Protoss Dragoon)
define_max(6, Protoss High Templar)
define_max(10, Protoss Dark Templar)
define_max(6, Protoss Archon)
define_max(2, Protoss Dark Archon)
define_max(1, Protoss Shuttle)
define_max(255, Protoss Reaver)
define_max(6, Protoss Observer)
define_max(255, Protoss Scout)
define_max(15, Protoss Carrier)
define_max(4, Protoss Arbiter)
define_max(4, Protoss Corsair)
define_max: the number is
the maximum number of this unit the AI can have at the same time. 255
stands for 0 units, here the AI won't have any reaver.
Debugging command:
We will greet our opponent with a message.
# Debugging
used to display messages
debug(g_MainBuilding,
Hello world I'm a new born Protoss AI)
--g_MainBuilding--
debug: this command is supprted
only with ScAIEdit. It displays a message and jumps to the label
"g_MainBuilding"
--name--: this is the
definition of a label, it must be defined only in one place. But
different commands can jump to the same label. Labels are not used only
by debug, they are used by all jumping commands. We will see more of
them later.
Now it's time to build our base. We will start with probes and a pylon.
Building commands:
# Main start
building
build(7, Protoss Probe, 80)
wait_buildstart(7, Protoss Probe)
build(1, Protoss Pylon, 80)
wait_buildstart(1, Protoss Pylon)
build(13, Protoss Probe, 80)
wait_buildstart(13, Protoss Probe)
build: The first
parameter is the total number of buildings (or workers) we want, the
last parameter is the priority. In this example, the first line won't
build 7 additional probes, it will build probes until the 7th is in
construction.
wait_buildstart: This command
is blocking. wait_buildstart(7, Protoss Probe): AI will wait until the
7th probe is in construction before going to the next line. Without
this line, the AI may start building the pylon instead of training
probes.
wait_build: This command
is blocking too. It's similar to the wait_buildstart except that it
will wait until the buiding is finished. Warning, if it's used with
Terran and a worker is killed while building the AI will be locked
until the unfinished building is destroyed.
Note: In earlier versions of BroodWar
a new worker was sent.
We should have enough minerals to build a new Nexus in another place.
Expanding command:
# Main start
expanding
expand(99, e_FastExpand)
expand: This command is used to
start a new expansion. It's a jumping command and the expansion is run
in parallel. The first parameter is the maximal number of expansions:
if the AI has more expansions than this number, the expand command will
be ignored. It probably acts has some kind of priority too, I nearly
always use 99. The second parameter is the label correponding to the
new expansion.
We will see what to build in this expansion later.
We continue to build our main base by placing a forge, an assimilator
and a gateway.
build(14, Protoss Probe, 80)
wait_buildstart(14, Protoss
Probe)
build(1, Protoss Forge, 80)
wait_buildstart(1, Protoss
Forge)
build(15, Protoss Probe, 80)
wait_buildstart(15, Protoss
Probe)
build(1, Protoss Assimilator,
80)
wait_buildstart(1, Protoss
Assimilator)
build(16, Protoss Probe, 80)
wait_buildstart(16, Protoss
Probe)
build(1, Protoss Gateway, 80)
wait_build(1, Protoss Gateway)
Now it's time to get some zealots to defend our base.
Training command:
# Main start training
train(2, Protoss Zealot)
train: This
command is used to train non-worker units. This command is blocking.
For example train(15, Protoss Zealot) will train zealots until 15
Zealots are alive or in training at the same time and next commands
will wave to wait. That's why I generally put it in a parallel branch
instead of the main part. But for this script sample we will put train
in the main part to keep it simple.
Now we will make buildings to get our carriers and
discover some useful commands. We tell the AI to use zealots and
carriers in defense.
build(1, Protoss Cybernetics Core,
80)
build(2, Protoss Pylon, 80)
farms_timing()
defensebuild_gg(1, Protoss Zealot)
defenseuse_gg(1, Protoss Zealot)
# Main start researching
multirun(r_Global)
build(1, Protoss Stargate, 80)
wait_build(1, Protoss Stargate)
build(1, Protoss Fleet Beacon, 80)
wait_buildstart(1, Protoss Fleet Beacon)
build(2, Protoss Stargate, 80)
build(2, Protoss Photon Cannon, 80)
defenseuse_gg(1, Protoss Carrier)
defenseuse_ag(1, Protoss Carrier)
defenseuse_ga(1, Protoss Carrier)
defenseuse_aa(1, Protoss Carrier)
train(4, Protoss Carrier)
wait(400)
build(3, Protoss Stargate, 80)
wait_buildstart(3, Protoss Stargate)
train(10, Protoss Carrier)
defenseuse_ag:
The first parameter is the number of units (second parameter) to use,
when a ground (
g) unit is
attacked by an air (
a) unit. It
doesn't train them only use those available. Similar command exists for
ground-ground (
gg), ground-air (
ga) and air-air (
aa)
defensebuild_ag: This command
tell to train unit (second parameter) when ground units are attacked by
air units. The number of units that will be trained is not well
determined, the AI often build many of them.
farms_timing: This command
tells the AI to build farms - pylons for a Protoss - automatically,
it's only needed once in a script. This functionnality is desactivated
at the beginning by farms_notiming because the AI would build farms too
soon otherwise.
multirun: This command is used
quite often in my scripts, it creates a parallel branch. In this code
example the new branch - starting at label "r_Global" - will be used
for the upgrades, we will see how later.
wait: This command makes the AI
waiting the time given as parameter before doing the next command. It
only makes it waiting in the branch where this command is placed. This
command is not really useful here. See here for time conversion.
We have our huge fleet of 10 carrier, let's how our opponent will
handle that.
Attacking commands:
# Main start attacking
attack_add(10, Protoss Carrier)
wait(1000)
debug(s_MainStep1, Let's try these brand new spaceships)
--s_MainStep1--
attack_do()
attack_add:
Unlike most of the other commands, this command is cumulative. If you
put 2 lines with "attack_add(5, Protoss Carrier)" the result will be an
attack with 10 carriers. "attack_clear" resets the count. This command
allows you to make attacks using different types of units.
attack_do: Attack with all the
units added before. The units will make a group at the entrance of the
enemy base and then attack. If some units are not trained yet, AI will
train them and use them in the battle.
After this attack our enemy should be dead or we are in
trouble. This is a loop I often use to close my main part, the AI
expands and attacks regularly. The final training is missing in this
script example.
# Main Final Loop
--l_FinalLoop--
wait(4500)
send_suicide(0)
wait(500)
expand(99, e_FastExpand)
goto(l_FinalLoop)
send_suicide:
This command take all the units and send them in the enemy base, it's
rather a disorganized assault. If the parameter is set to
1 instead of
0 workers will go in the fight too.
goto: Jumping command, the
execution will be continued from the label in parameter. Here it makes
a loop going to "l_FinalLoop". All loops must have at least a wait(
time) command, otherwise the AI
will crash.
Now let's see how the parallel parts are made. An
expansion starts with the start_town command. Then we need a Nexus. The
building count is not shared with the main base, for instance a
wait_build(1, Protoss Cybernetics Core) in expansion part will be
blocking if we only build one in the main part.
# Expanding part
--e_FastExpand--
start_town()
build(1, Protoss Nexus, 80)
wait_buildstart(1, Protoss Nexus)
wait(500)
build(1, Protoss Pylon, 80)
wait_buildstart(1, Protoss Pylon)
wait_build(1, Protoss Nexus)
build(6, Protoss Probe, 80)
wait_buildstart(6, Protoss Probe)
build(2, Protoss Photon Cannon, 70)
build(9, Protoss Probe, 70)
wait_buildstart(9, Protoss Probe)
build(2, Protoss Pylon, 70)
wait_buildstart(2, Protoss Pylon)
build(1, Protoss Assimilator, 70)
build(13, Protoss Probe, 70)
wait_buildstart(13, Protoss Probe)
build(6, Protoss Photon Cannon, 70)
stop()
stop: This
command ends a branch, it can be used in the main branch too.
Here the researches are done in 2 branches, one for the
cybernetics core and one for the fleet beacon. This is not mandatory,
research can be placed in the main part too.
# Researching part
--r_Global--
multirun(r_Cyber)
goto(r_Fleet)
# Research in cybernetics core
--r_Cyber--
wait_build(1, Protoss Cybernetics Core)
upgrade(1, Protoss Air Weapons, 30)
# This is not the right research time
wait(2500)
upgrade(1, Protoss Plating, 30)
stop()
# Research in cybernetics core
--r_Fleet--
wait_build(1, Protoss Fleet Beacon)
upgrade(1, Carrier Capacity, 30)
# This is not the right research time
wait(2500)
tech(Disruption Web, 20)
stop()
upgrade: This command upgrades
the second parameter to the level of the first parameter at the
priority of the third parameter. I use a 30 priority because upgrades
are often less needed than new buildings.
tech: This command research
the first parameter at the priority of the second parameter. Here I put
a 20 priority because we don't need disruption web in this script. This
command is used for casted abilities such as psionic storm, recall,
stimpacks, siege mode, burrowing, plague...
That's all, now you can create your own script or test this one. Check
the following sections to get additional information.
Script with ScAIEdit
Header commands:
These commands are put at the very beginning of the script. Their
effects is not always well known.
script_name Protoss Expansion Custom
Level
script_id PMCx
; This line and the following are
comments
; #### Starting headers ####
start_town
farms_notiming
transports_off
- script_name: name of the
script, use Protoss Expansion Custom Level, Terran Expansion Custom
Level and Zerg Expansion Custom Level for the standard BroodWar AI.
- script_id: script
identifier, use PMCx, TMCx and ZMCx for the standard BroodWar AI.
- start_town: command to
start a new town, generally used when creating a new expansion.
- farms_notiming: disable
automatic pylon/supply depot/overlords building.
- transports_off: command
used for ground maps. The AI won't create automatically transports.
Now we define the maximum number for the different units. This is
generally done just after header commands but that's not an obligation.
; ####
Maximum number of units ####
define_max
80 probe
define_max
20 zealot
define_max
20 dragoon
define_max
6 high_templar
define_max
10 dark_templar
define_max
6 archon
define_max
2 dark_archon
define_max
1 shuttle
define_max
255 reaver
define_max
6 observer
define_max
255 scout
define_max
20 carrier
define_max
4 arbiter
define_max
4 corsair
- define_max: the number is
the maximum number of this unit the AI can have at the same time. 255
stands for 0 units, here the AI won't have any reaver.