Post by Grubber on Aug 2, 2006 9:10:01 GMT -5
Foxbot Scripting Tutorial Author: DrEvil
Intro
I'll start by first saying that creating scripts for the bots is more difficult to first learn than waypointing or zoning. Once you get the basic idea it is pretty simple.
Why do we need scripts?
Simple, there are no bots that are smart. By this I mean that have complex goals or multiple goals, the bots don’t know what they need to do in what order. If you were to place simple flag location points at the button and flag in maps such as openfire or shutdown, the bots don’t know that they need to go to the button first then to the flag. The bots see the level as entities and waypoints. This is why scripts are important to the bots. Scripts tell the bots where to go and what to do by adjusting the availability of different goal locations based on events that happen in the map.
In order for a map to be “scriptable”, the events in the map that you want to script must have messages that you can use to trigger the events in a script.
How can you tell if there are scriptable events in a map?
Some of the indications that the map is scriptable are simple to see. Is there a message broadcasted when the event occurs? (Blue grate destroyed in well for example) Or is there a sound played when a certain event occurs? (captured points in samurai for example) Those are a couple indicators that you can script those events. The best way to find scriptable events are by looking in bot_debug mode, which I will talk about more shortly.
Key Bindings
The good news about scripting is that you don’t need any binds to do it. I would advise you to have a key already bound to take screenshots to make it easier.
I use:
bind f12 screenshot
Basic Scripting
First, I recommend that you have area and waypointing modes off, and no bots in the game. The reason for this is simple, you want as little going on in the map as possible, so that you don’t get a lot of console spam while in bot_debug mode looking for the messages you will need to create the script triggers.
Step 1: Setup
Before you start your script, you need to have your waypoints mostly done, and the goals in the map should have command points assigned to them.
Command point tags are the foundation of a script, and all events that are triggered adjust the availability of the waypoints that have a command point tag on it.
Example:
For the map cz2, all the command points have the appropriate command point tag on the waypoint flag goal locations, so command point 1 is on the flag goal for checkpoint1 and so on, so all 5 points have command point tags on the waypoints from 1 to 5 that make them unique and that makes them scriptable.
A waypoint without a command point tag is considered ALWAYS available to the bot.
You should place command points on any items that will need to be made unavailable at any point during the map.
Any items that are always available to the bots, don’t put a command point tag on them.
Example:
In the map openfire, for those that don’t know, there is a button that turns off security lasers, and that must be done before you can get the flag. In a map like this, you would need to place a flag waypoint at the button, and a flag waypoint at the flag for each team. You would then place different command point tags on each of them… so 1,2,3,4 to make them all independent of each other, and so you can manipulate them with the script.
Step 2: Setting up the on_start section
The first part of any script is the on_start section. This section is executed when the map first loads, and is used to set the initial states of all the command points, to available or unavailable. Now would be a good time to go through the available script commands, since they are the meat of any script.
The basic commands work like so:
color_available_pointx - pointx available to specified team
color_notavailable_pointx - pointx unavailable to specified team
color_available_only_pointx – pointx available to specified team AND makes all other points unavailable.
color would be of course for whatever team, blue, red, yellow, green. And the x at the end would be for whatever command point.
Example:
on_start
{
blue_available_point1
red_available_point2
}
So a section like this would begin the map with all waypoints with command point 1 on them available to blue team, and all waypoints with command point 2 on them available to red team. The default for all points is unavailable, so you don’t have to declare unavailable waypoints in the on_start section, though I usually do. You want to set all points available that you want the bots to be able to go to when the map is loaded. This will all depend on the map and waypoint setup.
Step 3: Adding the on_msg triggers
The on_msg triggers are the main part of any script. This is where you will put in the messages that the script will respond to. All triggers need to be part of an on_msg. Here is an example of an on_msg trigger taken from the script for cz2:
on_msg(#cz_bcap1)
{
blue_notavailable_point1
red_available_point1
}
Notice it looks a lot like the on_start section, but this time you have some parenthesis after on_msg and inside those is where you put the message that you want the script to look out for. This particular message is broadcasted in the cz2 map when blue team captures point1.
How do you find out what the messages are in a map?
Easy, bring down the console and type : bot_debug on and hit enter. And you should see the following message in the console.
When you are in bot_debug mode, you will start to see many new messages in the console that look like : msg (some nuts in here)
The messages that are in the parenthesis in the console are the messages that you will need to use in your script.
Lets do an example of this. If you wanted to script something to happen when the grate in well is blown you would first enter bot_debug on to turn on debug mode, then you would go and perform the event yourself… remember to have noone else in the game including bots when you do this. As you place the detpack and as it counts down you should be seeing the following messages when it detonates:
There are quite a few scriptable messages in this situation, the hardest thing about creating a script for a map is deciding what message you are going to script. The messages you are looking for are messages that make that particular situation unique. You wouldn’t want to use the #detpack_countdown message because it would be triggered any time someone set a detpack. You wouldn’t use any of the msg (1), msg (2), msg (0), or the msg (#FITH) to trigger the event either, because again these would trigger any time someone sets a detpack.
At the bottom of the screen, you see msg (#well_bgrate_destroyed). Any time you see messages that begin with # you can see what the message is by opening the file called titles.txt in notepad and finding the entry. So if you opened titles.txt and did a search for well_bgrate_destroyed (without the #), you would see that the message matches up to “Blue's GRATE has been destroyed.” This makes that message unique to that situation. By unique I mean that the msg (#well_bgrate_destroyed) only happens when blues grate has been destroyed and no other time.
Now that you have found a unique message for the event you want to script you need to determine what you want to happen. Since this trigger involves blues grate being destroyed you might want to make a new point available to red team to go to, that started out as unavailable.
NOTE: Not all maps have scriptable messages, there are some maps that show no unique messages in the console when you perform the actions. Sometimes det-packable paths aren’t scriptable or in the case of paths that can be opened and closed repeatedly (warpath & rock2) there isn’t a message every time the paths are opened or closed, so you cant write the script with the ability to toggle on and off a point each time its opened or closed. This will be addressed in the future as the scripting system expands.
Scripting Buttons
Another point to address, is that if you hit buttons, sometimes you will see messages in the console that can indicate that a button is scriptable. If you were to have bot_debug on when you hit the button in the map openfire you would see this in the console:
Since this map requires the button to be pushed to turn off the security lasers, you would start the map off so that both teams have only the button waypoints available, but you want their goal to change when they hit the button. The most important thing to check when scripting buttons is that the button toggles back at the same time the event turns back on. For instance in the case of openfire, you want to check to make sure that you see another button toggle message when the lasers come back on. In a lot of cases, you will notice that when you push a button, it immediately toggle back to its other state after a second or two, and not when the event it controls turns back. An example of this is the front doors in well, when you push the button you will notice that you will see the button toggle on and off quickly, and it is not synched with the door closing, so you couldn’t use it in a script to control bot goals because the button toggle doesn’t accurately represent the door closing again. Hope that’s clear.
So how do you check it? Simple, in openfire I push the buttons, then keep an eye on the lasers and the console. If I see the button message toggle back to 1 in the console at the same time that the lasers come back on, then I can use that for my script. Here is a screen of everything that happens when a button is pushed in openfire:
You see the top line shows the message when I hit the button to turn off the lasers. msg (target rtrigger2, toggle 0). I then went and waited by the lasers until they turned back on. Right as the lasers turned back on I see the msg (target rtrigger2, toggle 1) which tells me the button is toggling back right as the lasers come back on. All this means is that the button presses are synched with the events it controls. When it is synched, then you can use it in your script because it accurately represents the state of the lasers. So you can now script the bots to go for the flag when the lasers are down, and when the lasers are back up they will go for the button again.
Scripting Sounds
You might have noticed in the screenshot above that there are messages about sounds that are being played. You will probably rarely use sounds as triggers because they are almost always not very specific. Sounds were added to be scriptable because a map called samurai used unique sounds when each command point was captured, and there was no other messages that could be used. Scripting sounds works just like messages, you would use an on_msg(buttons/spark3,wav) or whatever the specific sound was that you wanted to script. Best advice is to only use sounds as triggers when they are specific enough to use, and when they are the last option, meaning If there is no text messages to use.
Other script commands
There are several other commands that you can use in your scripts to control triggers. One of them is here:
If_color_pointx
{
commands here
}
This line checks to see if pointx is available to the specified color. Look at the following example:
if_blue_point7
{
red_notavailable_point6
blue_available_point6
}
In this case, it checks to see if point7 is currently available to the blue team. If it is, then it will execute the commands afterwards. If not, the commands won’t be executed.
NOTE: It is important to keep in mind that ALL commands must be within an on_msg statement. Also, there can only be 1 if statement in an on_msg and it must be at the end. Here is an example from the avanti script.
on_msg(#italy_you_secure_cp3)
{
blue_notavailable_point1
blue_notavailable_point2
blue_notavailable_point3
blue_available_point4
red_notavailable_point1
red_notavailable_point2
red_notavailable_point3
red_available_point4
if_blue_point7
{
red_notavailable_point6
blue_available_point6
}
}
Notice how everything here is nested within the brackets for the on_msg. Also notice how there is only 1 if statement and its at the end after all the other commands. Any time an if statement is performed, it will not execute any commands after it, which is why you can only put 1 of them in a script, and also why you need to put it at the end of the on_msg before the close bracket.
Step 4: Testing the script
There is a couple tools you will use to test your script to make sure it is working. The first is a simple command. If you type available in the console, you will see a list generated in the console for all 4 teams of which points are available for them at that exact moment. You may need to page up to see them all, this will be improved later.
The other thing you are going to use when testing your script is the bot_debug mode. When you have a script loaded, you can test and see if it is working if you see the message followed by *** followed by the message again. Look back at the openfire screenshot.
See the line that says no if target rtrigger2, toggle 1 *** target rtrigger2 toggle 1 ?
Just the fact that you see the command twice, separated by the *** means that the script has intercepted that command, and performed whatever actions that were associated with that trigger.
If you just see the msg (whatever message) and not see the line with the *** in it, that means you have probably mistyped the message in the script.
SCRIPTS ARE CASE SENSITIVE! Remember to put the message in the script exactly as it appears in the console.
When testing your scripts, the thing to do first is verify that the script is intercepting the messages you want it to. Once you have verified that, then you will be inserting whatever commands needed to manipulate the command points to make them available or unavailable.
Basically in a script you are specifying a message you want the script to look out for. When the script sees each message, it is going to perform whatever actions go with that message. These actions change the states of command points, resulting in getting the bots to go to whatever command points are available and not pick an unavailable point as a destination.
Common Errors when scripting
Q: My script isn’t loading!
A: If you get a message on the intro that says your script isn’t loading it could be one of several problems.
1) Make sure the script is located in halflife\foxbot\tfc\scripts
2) It won’t load if you are missing brackets or have too many. There should be a close bracket for every open bracket.
3) Remember theres no space after on_msg in the script.
4) Don’t forget the on_start section at the top of the script.
5) Double check your spelling in the commands.
6) Remember that scripts, just like waypoints, are loaded when the map starts, so if you are in-game while making the script, you will need to save the script file and restart the map in order to load it.
Q: The script isn’t intercepting the message!
A: Remember to put the messages in the script exactly as they appear in the console. This includes capitalization if it has it in the console. Also, some messages appear more than 1 line. You will need to script these as more than one line as well. You can see an example of this in the script for shutdown2 and several other maps that have been done. My advice is to play with it till it works, as shown by the ***.
Conclusion
The best way to get into scripting after reading this tutorial is by looking at the scripts that have been done. It's really not all that hard with a little effort.
If you don't see console messages ingame (Upper Left).. Type in console developer 1
OR right click in Steam Games Menu "Team Fortress Classic / Properties / Set Launch Options.. And add -dev ...........
Then you should see messages in upper left being displayed.
Intro
I'll start by first saying that creating scripts for the bots is more difficult to first learn than waypointing or zoning. Once you get the basic idea it is pretty simple.
Why do we need scripts?
Simple, there are no bots that are smart. By this I mean that have complex goals or multiple goals, the bots don’t know what they need to do in what order. If you were to place simple flag location points at the button and flag in maps such as openfire or shutdown, the bots don’t know that they need to go to the button first then to the flag. The bots see the level as entities and waypoints. This is why scripts are important to the bots. Scripts tell the bots where to go and what to do by adjusting the availability of different goal locations based on events that happen in the map.
In order for a map to be “scriptable”, the events in the map that you want to script must have messages that you can use to trigger the events in a script.
How can you tell if there are scriptable events in a map?
Some of the indications that the map is scriptable are simple to see. Is there a message broadcasted when the event occurs? (Blue grate destroyed in well for example) Or is there a sound played when a certain event occurs? (captured points in samurai for example) Those are a couple indicators that you can script those events. The best way to find scriptable events are by looking in bot_debug mode, which I will talk about more shortly.
Key Bindings
The good news about scripting is that you don’t need any binds to do it. I would advise you to have a key already bound to take screenshots to make it easier.
I use:
bind f12 screenshot
Basic Scripting
First, I recommend that you have area and waypointing modes off, and no bots in the game. The reason for this is simple, you want as little going on in the map as possible, so that you don’t get a lot of console spam while in bot_debug mode looking for the messages you will need to create the script triggers.
Step 1: Setup
Before you start your script, you need to have your waypoints mostly done, and the goals in the map should have command points assigned to them.
Command point tags are the foundation of a script, and all events that are triggered adjust the availability of the waypoints that have a command point tag on it.
Example:
For the map cz2, all the command points have the appropriate command point tag on the waypoint flag goal locations, so command point 1 is on the flag goal for checkpoint1 and so on, so all 5 points have command point tags on the waypoints from 1 to 5 that make them unique and that makes them scriptable.
A waypoint without a command point tag is considered ALWAYS available to the bot.
You should place command points on any items that will need to be made unavailable at any point during the map.
Any items that are always available to the bots, don’t put a command point tag on them.
Example:
In the map openfire, for those that don’t know, there is a button that turns off security lasers, and that must be done before you can get the flag. In a map like this, you would need to place a flag waypoint at the button, and a flag waypoint at the flag for each team. You would then place different command point tags on each of them… so 1,2,3,4 to make them all independent of each other, and so you can manipulate them with the script.
Step 2: Setting up the on_start section
The first part of any script is the on_start section. This section is executed when the map first loads, and is used to set the initial states of all the command points, to available or unavailable. Now would be a good time to go through the available script commands, since they are the meat of any script.
The basic commands work like so:
color_available_pointx - pointx available to specified team
color_notavailable_pointx - pointx unavailable to specified team
color_available_only_pointx – pointx available to specified team AND makes all other points unavailable.
color would be of course for whatever team, blue, red, yellow, green. And the x at the end would be for whatever command point.
Example:
on_start
{
blue_available_point1
red_available_point2
}
So a section like this would begin the map with all waypoints with command point 1 on them available to blue team, and all waypoints with command point 2 on them available to red team. The default for all points is unavailable, so you don’t have to declare unavailable waypoints in the on_start section, though I usually do. You want to set all points available that you want the bots to be able to go to when the map is loaded. This will all depend on the map and waypoint setup.
Step 3: Adding the on_msg triggers
The on_msg triggers are the main part of any script. This is where you will put in the messages that the script will respond to. All triggers need to be part of an on_msg. Here is an example of an on_msg trigger taken from the script for cz2:
on_msg(#cz_bcap1)
{
blue_notavailable_point1
red_available_point1
}
Notice it looks a lot like the on_start section, but this time you have some parenthesis after on_msg and inside those is where you put the message that you want the script to look out for. This particular message is broadcasted in the cz2 map when blue team captures point1.
How do you find out what the messages are in a map?
Easy, bring down the console and type : bot_debug on and hit enter. And you should see the following message in the console.
When you are in bot_debug mode, you will start to see many new messages in the console that look like : msg (some nuts in here)
The messages that are in the parenthesis in the console are the messages that you will need to use in your script.
Lets do an example of this. If you wanted to script something to happen when the grate in well is blown you would first enter bot_debug on to turn on debug mode, then you would go and perform the event yourself… remember to have noone else in the game including bots when you do this. As you place the detpack and as it counts down you should be seeing the following messages when it detonates:
There are quite a few scriptable messages in this situation, the hardest thing about creating a script for a map is deciding what message you are going to script. The messages you are looking for are messages that make that particular situation unique. You wouldn’t want to use the #detpack_countdown message because it would be triggered any time someone set a detpack. You wouldn’t use any of the msg (1), msg (2), msg (0), or the msg (#FITH) to trigger the event either, because again these would trigger any time someone sets a detpack.
At the bottom of the screen, you see msg (#well_bgrate_destroyed). Any time you see messages that begin with # you can see what the message is by opening the file called titles.txt in notepad and finding the entry. So if you opened titles.txt and did a search for well_bgrate_destroyed (without the #), you would see that the message matches up to “Blue's GRATE has been destroyed.” This makes that message unique to that situation. By unique I mean that the msg (#well_bgrate_destroyed) only happens when blues grate has been destroyed and no other time.
Now that you have found a unique message for the event you want to script you need to determine what you want to happen. Since this trigger involves blues grate being destroyed you might want to make a new point available to red team to go to, that started out as unavailable.
NOTE: Not all maps have scriptable messages, there are some maps that show no unique messages in the console when you perform the actions. Sometimes det-packable paths aren’t scriptable or in the case of paths that can be opened and closed repeatedly (warpath & rock2) there isn’t a message every time the paths are opened or closed, so you cant write the script with the ability to toggle on and off a point each time its opened or closed. This will be addressed in the future as the scripting system expands.
Scripting Buttons
Another point to address, is that if you hit buttons, sometimes you will see messages in the console that can indicate that a button is scriptable. If you were to have bot_debug on when you hit the button in the map openfire you would see this in the console:
Since this map requires the button to be pushed to turn off the security lasers, you would start the map off so that both teams have only the button waypoints available, but you want their goal to change when they hit the button. The most important thing to check when scripting buttons is that the button toggles back at the same time the event turns back on. For instance in the case of openfire, you want to check to make sure that you see another button toggle message when the lasers come back on. In a lot of cases, you will notice that when you push a button, it immediately toggle back to its other state after a second or two, and not when the event it controls turns back. An example of this is the front doors in well, when you push the button you will notice that you will see the button toggle on and off quickly, and it is not synched with the door closing, so you couldn’t use it in a script to control bot goals because the button toggle doesn’t accurately represent the door closing again. Hope that’s clear.
So how do you check it? Simple, in openfire I push the buttons, then keep an eye on the lasers and the console. If I see the button message toggle back to 1 in the console at the same time that the lasers come back on, then I can use that for my script. Here is a screen of everything that happens when a button is pushed in openfire:
You see the top line shows the message when I hit the button to turn off the lasers. msg (target rtrigger2, toggle 0). I then went and waited by the lasers until they turned back on. Right as the lasers turned back on I see the msg (target rtrigger2, toggle 1) which tells me the button is toggling back right as the lasers come back on. All this means is that the button presses are synched with the events it controls. When it is synched, then you can use it in your script because it accurately represents the state of the lasers. So you can now script the bots to go for the flag when the lasers are down, and when the lasers are back up they will go for the button again.
Scripting Sounds
You might have noticed in the screenshot above that there are messages about sounds that are being played. You will probably rarely use sounds as triggers because they are almost always not very specific. Sounds were added to be scriptable because a map called samurai used unique sounds when each command point was captured, and there was no other messages that could be used. Scripting sounds works just like messages, you would use an on_msg(buttons/spark3,wav) or whatever the specific sound was that you wanted to script. Best advice is to only use sounds as triggers when they are specific enough to use, and when they are the last option, meaning If there is no text messages to use.
Other script commands
There are several other commands that you can use in your scripts to control triggers. One of them is here:
If_color_pointx
{
commands here
}
This line checks to see if pointx is available to the specified color. Look at the following example:
if_blue_point7
{
red_notavailable_point6
blue_available_point6
}
In this case, it checks to see if point7 is currently available to the blue team. If it is, then it will execute the commands afterwards. If not, the commands won’t be executed.
NOTE: It is important to keep in mind that ALL commands must be within an on_msg statement. Also, there can only be 1 if statement in an on_msg and it must be at the end. Here is an example from the avanti script.
on_msg(#italy_you_secure_cp3)
{
blue_notavailable_point1
blue_notavailable_point2
blue_notavailable_point3
blue_available_point4
red_notavailable_point1
red_notavailable_point2
red_notavailable_point3
red_available_point4
if_blue_point7
{
red_notavailable_point6
blue_available_point6
}
}
Notice how everything here is nested within the brackets for the on_msg. Also notice how there is only 1 if statement and its at the end after all the other commands. Any time an if statement is performed, it will not execute any commands after it, which is why you can only put 1 of them in a script, and also why you need to put it at the end of the on_msg before the close bracket.
Step 4: Testing the script
There is a couple tools you will use to test your script to make sure it is working. The first is a simple command. If you type available in the console, you will see a list generated in the console for all 4 teams of which points are available for them at that exact moment. You may need to page up to see them all, this will be improved later.
The other thing you are going to use when testing your script is the bot_debug mode. When you have a script loaded, you can test and see if it is working if you see the message followed by *** followed by the message again. Look back at the openfire screenshot.
See the line that says no if target rtrigger2, toggle 1 *** target rtrigger2 toggle 1 ?
Just the fact that you see the command twice, separated by the *** means that the script has intercepted that command, and performed whatever actions that were associated with that trigger.
If you just see the msg (whatever message) and not see the line with the *** in it, that means you have probably mistyped the message in the script.
SCRIPTS ARE CASE SENSITIVE! Remember to put the message in the script exactly as it appears in the console.
When testing your scripts, the thing to do first is verify that the script is intercepting the messages you want it to. Once you have verified that, then you will be inserting whatever commands needed to manipulate the command points to make them available or unavailable.
Basically in a script you are specifying a message you want the script to look out for. When the script sees each message, it is going to perform whatever actions go with that message. These actions change the states of command points, resulting in getting the bots to go to whatever command points are available and not pick an unavailable point as a destination.
Common Errors when scripting
Q: My script isn’t loading!
A: If you get a message on the intro that says your script isn’t loading it could be one of several problems.
1) Make sure the script is located in halflife\foxbot\tfc\scripts
2) It won’t load if you are missing brackets or have too many. There should be a close bracket for every open bracket.
3) Remember theres no space after on_msg in the script.
4) Don’t forget the on_start section at the top of the script.
5) Double check your spelling in the commands.
6) Remember that scripts, just like waypoints, are loaded when the map starts, so if you are in-game while making the script, you will need to save the script file and restart the map in order to load it.
Q: The script isn’t intercepting the message!
A: Remember to put the messages in the script exactly as they appear in the console. This includes capitalization if it has it in the console. Also, some messages appear more than 1 line. You will need to script these as more than one line as well. You can see an example of this in the script for shutdown2 and several other maps that have been done. My advice is to play with it till it works, as shown by the ***.
Conclusion
The best way to get into scripting after reading this tutorial is by looking at the scripts that have been done. It's really not all that hard with a little effort.
If you don't see console messages ingame (Upper Left).. Type in console developer 1
OR right click in Steam Games Menu "Team Fortress Classic / Properties / Set Launch Options.. And add -dev ...........
Then you should see messages in upper left being displayed.