Map Scripting Enemy Territory
From Omni-bot Wiki
| ET Main Page | Map Scripting | Archives |
Standard Format
All official map scripts share a common layout. Having a standard for map scripts has several benefits; ease of documentation, debugging, and implementation of scripted goals are among those benefits. A typical ET map script will consist of one Map table and two functions that are automatically called by Omni-Bot:
global Map =
{
};
global OnMapLoad = function()
{
};
global OnBotJoin = function( bot )
{
};
Using makegm will ensure that a map script is in a standard format.
Map Table
The Map Table has become an important part of an ET map script as some scripted goals rely on its existence. It also provides a 'safe' place to store map specific information. Typically it will consist of map variables, triggers / functions, and in some cases additional tables:
global Map =
{
SomeGoal = "BUILD_some_construct",
someVar = true,
someTable =
{
someVar = false,
},
some_trigger = function(trigger)
{
print("some_trigger");
},
};
It is important to note that when you add to a table you use a comma and not a semi-colon. Calling functions or referencing variables within the example table is done like this:
Map.someVar = false; //changes the value of someVar to false print(Map.SomeGoal); //will print BUILD_some_construct Map.someTable.someVar = true; //changes the value of someTable.someVar to true
The key thing to note is that you need to put Map. in front of whatever you want to call or reference within the Map table.
OnMapLoad
The OnMapLoad function is used to initialize settings for the map. It is automatically called by Omni-Bot whenever a map loads (i.e. /map_restart). Setting up triggers, goal availability, and goal bias' are the most common jobs performed by this function:
global OnMapLoad = function()
{
OnTrigger( "Some Team did Something!", Map.some_trigger );
SetAvailableMapGoals( TEAM.AXIS, false, Map.SomeGoal );
SetGoalPriority( Map.SomeGoal, 1.1 );
};
OnBotJoin
The OnBotJoin function is automatically called by Omni-Bot when a bot joins. Typical usage for OnBotJoin is for setting specific properties on the bot that you want to be map specific. View distance and breakable object distance are the two most commonly used:
global OnBotJoin = function( bot )
{
bot.MaxViewDistance = 2500;
bot.TargetBreakableDist = 150.0;
};
Note that it is not necessary to loop through the BotTable every time this is called as this function is called each time a bot joins.
Triggers
A trigger is an event that is recognized by Omni-Bot in game. With map scripting, triggers can be set up to perform operations when a map event occurs. There are two steps to setting up triggers; defining the trigger and setting up the trigger function.
Triggers are most commonly defined in OnMapLoad using the OnTrigger function:
global OnMapLoad = function()
{
OnTrigger("string", function);
};
The "string" parameter is usually found using the wm_announce messages seen during the game. This must be matched exactly including capitalization, punctuation, and color codes (if any). To see the wm_announce message requires the waypointer to either play through the map and perform the objectives or look through the map script that is included inside a map's pk3 file.
If the wm_announce messages appear in non-standard color, the latter method is often more convenient. The map's native script (not to be confused with the Omni-bot map script) is usually the file <mapname>.script in the /maps/ folder inside the pk3 file. Open the pk3 file with some archive utility, e.g. IZArc.
Another method of finding the string parameter is using the command /bot debugtriggers. This command will output to console everytime a recognized event occurs. The syntax will be similar to:
<---> Trigger: TagName: The Tank has been repaired! Action: announce Entity: 0x7016dd8c Activator: 0
The string just after TagName: is what the OnTrigger function will expect as the string parameter. For additional information about debugtriggers see the Omni-bot_Command_Reference#debugtriggers page. This method is required for maps that may not have wm_announce messages that correspond to recognized map events.
Once you've collected the triggers you need, the contents of the console can be written to a plain text file by using the command /condump mytextfile. The file will be located in the omnibot folder under the game installation folder. By copying the trigger names from that file instead of typing them, the risk of typing errors is greatly reduced.
The function parameter of the OnTrigger function is the name of a function that the waypointer creates for the particular trigger. These can be named anything the waypointer wants, but should be somewhat intuitive.
Once the string parameter has been identified and a function name has been determined, the trigger definition will look something like this:
global OnMapLoad = function()
{
OnTrigger("The Tank has been repaired!", Map.tank_repaired );
};
The last part of the setup is to create the trigger function that will contain code for the game to process each time the event occurs. In all official map scripts, this is done inside the Map table:
global Map =
{
tank_repaired = function( trigger )
{
//things to do when this event occurs
print("tank_repaired");
},
};
It is important to note is that the function is inside the map table and should have a comma outside the closing bracket and not a semi-colon. The print statement inside the trigger function is not necessary, but is a good way to test that the trigger is working. As an additional service to the users, you can comment these print statements out when you're done testing, so their console isn't flooded with information that doesn't mean much to them.
Supported Triggers
Most events in ET will fall into the following Omni-Bot recognized categories:
- allied_complete
- allied_default
- allied_failed
- announce
- announce_icon
- axis_complete
- axis_default
- axis_failed
- defused
- dynamited
- exploded
- faceangle
- mover_goto x y z
- moving
- opened
- closed
- opening
- closing
- repair_mg42
- returned
- round end
- stolen
- team_announce
- thirty second
- two minute
If you are unsure if the event you want to set up a trigger for falls into one of these categories, use /bot debugtriggers in game.
NOTE: For the returned trigger (i.e. documents returned) use /bot debugtriggers output for when the flag is returned by expiring (no player returns it). If the regular wm_announce message is used, the event that occurs when the flag expires will not be used. It is recommended to manually steal the flag, /kill and wait for them to be automatically returned. An example can be found in radar.gm. Most of the time it will be something like "Flag returned flag!"
Native Functions
This section consists of Omni-Bot functions specifically designed for use in map scripts.
ChangeSpawnPoint
syntax: bot.ChangeSpawnPoint(int spawnptid); example: bot.ChangeSpawnPoint(1); note: the number of the spawn point is map dependant and may require either searching for spawn selection configs or testing the numbers.
GetGameTimeLeft
syntax: GetGameTimeLeft(); returns: Time left in the game in seconds example: can be used in maps where you may want the bots to focus on major objectives if there isn't much time left.
GetGameType
syntax: GetGameType(); returns: The current game type
GetReinforceTime
syntax: bot.GetReinforceTime(); returns: Time left before the bots next spawn example: can be used in maps where you may want to exec a command if the bot is close to a new respawn.
MaxViewDistance
syntax: bot.MaxViewDistance = <distance>; example: bot.MaxViewDistance = 2500; note: typically set in OnBotJoin as this sets the property individually
SetAvailableMapGoals
syntax: SetAvailableMapGoals( Team, true / false, goalname );
example: SetAvailableMapGoals( TEAM.AXIS, true, "MAP_FLAG_someflag" );
example: SetAvailableMapGoals( TEAM.ALLIES, false, Map.Flag );
example: SetAvailableMapGoals( TEAM.AXIS, false, "DEFEND.*" );
note: the goalname parameter supports expressions
note: this command is the simpler alternative to getting a goal, then setting the availabilty. it's not necessary to do something like this:
somevar = GetGoal("SOMEGOAL")
if (somevar)
{
somevar.SetAvailable( TEAM.ALLIES, true );
}
SetGoalPriority
syntax: SetGoalPriority( goalname, priority, team, class, <optional persistent> ); example: SetGoalPriority( Map.Flag, 1.0, 0, 0 ); //all teams and all classes example: SetGoalPriority( "DEFUSE_somedyno.*", 0.0, TEAM.AXIS, CLASS.ENGINEER, true ); //the persistent parameter is used for dynamic goals that may not have been created yet
SetMapGoalProperties
syntax: SetMapGoalProperties( Goal, table )
example: SetMapGoalProperties( "ATTACK_.*", {mincamptime=15, maxcamptime=30} );
note: see OnMapLoad in goldrush.gm for example usage
TargetBreakableDist
syntax: bot.TargetBreakableDist = <distance>; example: bot.TargetBreakableDist = 100; note: typically set in OnBotJoin as this sets the property individually note: used to allow bots to target breakables like windows. should be set to a relatively low number.
Utility Functions
The functions listed in this section are custom functions created to support specific scenarios in game. They are located in ~/omni-bot/et/scripts and ~/omni-bot/global_scripts respectively.
ETUtilities
ET utility functions are located in the ~/omni-bot/et/scripts/et_utilities.gm file.
ETUtil.ChangeClass
syntax: ETUtil.ChangeClass( team, originalclass, newclass, revert, maxbots )
example: ETUtil.ChangeClass( TEAM.ALLIES, CLASS.SOLDIER, CLASS.COVERTOPS, false, 1 );
usage: used in braundorf_b4 to change one bot to covert ops for satcheling the side gate.
Once satcheled, the function is called again with the revert flag set to true to
have the bot change back to it's original class.
ETUtil.ChangeSpawn
syntax: ETUtil.ChangeSpawn(team, spawnpoint, numbots) usage: used to force bots to use a given spawn point. optionally limiting the number of bots to use the spawn example: ETUtil.ChangeSpawn(TEAM.AXIS, 3); //all axis will spawn at location 3 example: ETUtil.ChangeSpawn(TEAM.ALLIES, 4, 3); //three allies will spawn at location 4
ETUtil.ClearMainGoals
syntax: ETUtil.ClearMainGoals(); usage: This function will deactivate all main goals for both teams. goals deactivated: AMMOCAB, CHECKPOINT, HEALTHCAB, BUILD, PLANT, FLAG, MOUNTMG42, MOVER
ETUtil.ClearSecondaryGoals
syntax: ETUtil.ClearSecondaryGoals(); usage: This function will deactivate all secondary goals for both teams. goals deactivated: AMMO, HEALTH, ARTILLERY, MOBILEMG42, REPAIRMG42, PLANTMINE
ETUtil.CountClass
syntax: ETUtil.CountClass( team, class ) example: ETUtil.CountClass( TEAM.ALLIES, CLASS.ENGINEER ); usage: can be used to determine if a team has enough of a critical class for the map
ETUtil.CountTeam
syntax: ETUtil.CountTeam( team )
example: ETUtil.CountClass( TEAM.ALLIES );
usage: used to count the number of bots on a give team. used in maps like et_ice
in a conditional statement for setting max users attacking / defending.
ETUtil.DisableGoal
syntax: ETUtil.DisableGoal(goalname, <optional true>);
example: ETUtil.DisableGoal("FLAG_someflag");
usage: disables the goal for both teams. the optional true parameter is used to disable all
goals except for ROUTE goals.
ETUtil.EnableGoal
syntax: ETUtil.EnableGoal(goalname);
example: ETUtil.EnableGoal("FLAG_someflag");
usage: enables the goal for both teams.
ETUtil.LimitToClass
syntax: ETUtil.LimitToClass(goalname, team, class1, class2, class3);
usage: used to limit specific goals to a specific class or classes
example: ETUtil.LimitToClass("CHECKPOINT.*", TEAM.ALLIES, CLASS.SOLDIER) //only soldiers on the allied team
example: ETUtil.LimitToClass("CHECKPOINT.*", TEAM.ALLIES, CLASS.SOLDIER, CLASS.MEDIC) //only soldiers and medics
ETUtil.NoSnipe
syntax: ETUtil.NoSnipe(bot); usage: covert ops bots will not choose a garand or k43 note: this is typically called in OnBotJoin
ETUtil.RandomSpawn
syntax: ETUtil.RandomSpawn(team, spawnpoint); usage: used to have bots randomly choose to spawn at the given spawnpoint
ETUtil.SelectWeapon
syntax: ETUtil.SelectWeapon(bot, weapon); usage: the given bot will switch to the given weapon if it is the correct class for the weapon note: typically used in OnBotJoin to have soldiers choose a specific weapon example: ETUtil.SelectWeapon(bot, WEAPON.PANZERFAUST);
ETUtil.SetPrimaryGoals
syntax: ETUtil.SetPrimaryGoals(priority);
usage: used for setting priorities of common goals.
note: this is typically called in OnMapLoad and effects the following goals (in order of priority):
CAPPOINT FLAGRETURN PLANT CHECKPOINT FLAG
ETUtil.ShowActiveGoals
syntax: ETUtil.ShowActiveGoals(); usage: shows active goals for both teams note: should only be used for debugging
ETUtil.StopSniping
syntax: ETUtil.StopSniping(); usage: all bots currently using a mauser will switch to a different weapon note: this is typically called inside trigger functions
ETUtil.SwitchWeapon
syntax: ETUtil.SwitchWeapon(weapon); usage: all qualifying bots will switch to the given weapon example: ETUtil.SwitchWeapon(WEAPON.PANZERFAUST); //all soldiers will switch to panzer note: typically used in trigger functions
Utilities
Utility functions are located in the ~/omni-bot/global_scripts/utilities.gm file.
Util.AddInvVehicle
syntax: Util.AddInvVehicle( goalname )
usage: adds a vehicle to the Map.InvVehicle table
used for script goals in cases where the vehicle is invulnerable, but shows as "dead"
Util.AliveCount
syntax: Util.AliveCount( team, class ) usage: returns the number of bots alive on a team with a given class
Util.DisableGroup
syntax: Util.DisableGroup(groupname, team); example: Util.DisableGroup( "somegroupname", TEAM.SOMETEAM ); usage: used to disable a set of goals in the given group for a given team
Util.DistanceView
syntax: Util.DistanceView(<optional off|0>);
usage: /bot dist
/bot dist off
/bot dist 0
note: used for determining bot.MaxViewDistance settings. aim at a position as far as you can see and type /bot dist
Util.EnableGroup
syntax: Util.EnableGroup(groupname, team); example: Util.EnableGroup( "somegroupname", TEAM.SOMETEAM ); usage: used to enable a set of goals in the given group for a given team
Util.GetGroup
syntax: Util.GetGroup(groupname);
example: Util.GetGroup("somegroupname");
usage: this function will return a table of goals belonging to the given group name
Util.OnTriggerPosition
syntax: Util.OnTriggerPosition( goalname, wpname, tolerance, wpfunction ) example: Util.OnTriggerPosition( Map.Mover_train1, "depotyard", 200.0, Map.tug_depotyard ); note: used for setting up positional triggers for movers.
Util.RemoveGoal
syntax: Util.RemoveGoal( goalname ); example: Util.RemoveGoal( "MOVER_truck" ); note: this command will remove the goal from the map goal table
Util.SetGoalOffset
syntax: Util.SetGoalOffset( x, y, z, GoalName ); example: Util.SetGoalOffset( 0, 0, 30, "BUILD_construct" ) usage: the x y and z parameters are added to the origin of the goal to move the location of where the bots will look for the goal.
Util.SetGoalPosition
syntax: Util.SetGoalPosition( x, y, z, GoalName ); example: Util.SetGoalPosition( 4534, 2168, -199, "BUILD_construct" ) usage: used to give the goal a new origin. note: using /devmap to load the map and issuing the /viewpos command in console will give your origin in the map
Util.SetGroup
syntax: Util.SetGroup(goalname, groupname);
example: Util.SetGroup("somegoalname", "somegroupname");
usage: this function will add a given goal to a given groupname
Util.ShowGroup
syntax: Util.ShowGroup(groupname);
example: Util.ShowGroup("somegroupname");
usage: this function will list all goals in the given group in the console.
Util.SetMaxUsersInProgress
syntax: Util.SetMaxUsersInProgress( Users, GoalNames ); example: Util.SetMaxUsersInProgress( 15, "CHECKPOINT.*" ); usage: used to set the maximum number of bots going for a particular goal(s).
Util.SetPositionGoal
syntax: Util.SetPositionGoal( goalname1, goalname2 ); example: Util.SetPositionGoal( Map.Build_tank_construct, Map.Mover_tank ); usage: sets the origin of one goal to match the origin of another. useful for centering construct goals on movers
Util.ShowGoalInfo
syntax: Util.ShowGoalInfo(goalname);
command: /bot sgi 'goalname'
usage: used to print a goals current information in console including the goals health, status of the DEAD flag,
and the goals position
Util.ShowGoalName
syntax: Util.ShowGoalName(radius, showOffset);
command: /bot sgn <radius> <optional true>
usage: issue the command /bot sgn to find the goalname of any goals within 100 units. Optionally expand the radius and
find your current offset from the goal with /bot sgn 500 true
Util.ShowGoalOffset
syntax: Util.ShowGoalOffset(goalname);
command: /bot sgo 'somegoalname'
usage: used to determine a players current offset from a goal. the values given in console can be used for goals that
require positional offsets
Util.AddUsePoint
syntax: Util.AddUsePoint(goalname, position); example: Util.AddUsePoint( "somegoalname", Vector3(123, 456, 789) ); usage: used to add a Use Point for a goal at a given position.
Util.AddUseWp
syntax: Util.AddUseWp(goalname, waypointname); example: Util.AddUseWp( "somegoalname", "somewaypointname" ); usage: used to add a Use Point for a goal at a given waypoints position.
Conditionals
Enemy Territory is a complex game type. Maps are not linear and events do not necessarily happen in a specific order. Conditional statements are necessary in some cases to ensure that availability of goals is consistent with the waypointers idea of a map flow. A conditional statement begins with the 'if' function. In script, it is used to check given paramaters before executing some code:
if ( a == b )
{
//do something
}
In this example it checks if something is equal to something else before executing any code in the following brackets. If something does not equal something else, anything inside the brackets will be ignored. This conditional can be extended to make something happen if the first conditional was not met with the 'else' commamd:
if ( a == b )
{
//do something
}
else
{
//do something else
}
And finally, this can be extended even further using the 'else if' command:
if ( a == b )
{
//do something
}
else if ( a == c )
{
//do something else
}
else
{
//do something else
}
Conditionals can get more complex by adding additional checks The following example checks if both are true before executing the code in the example:
if ( a == b && c == d )
{
//do something
}
If a check is dependant on one of many checks being true, the 'or' operator is used:
if ( a == b || c == d )
{
//do something
}
To test if something is true or false, the syntax used is:
if ( !something )
{
//do something
}
The apostrophe in front of the parameter checks if something is false while a != checks if something doesn't equal something else:
if ( a != b )
{
a = b;
}
Checking if a value is greater or lesser than another value is done as follows:
if ( a > b || c < d )
{
//do something
}
In ET maps where the map flow is not pre-determined, it is important to add conditionals to some triggers in which goals are activated. While the bots order of objective completion can be set by the waypointer, the waypointer can not predict when a human player may complete a particular objective. So if goals are activated with a specific order in mind and a human player activates a goal out of turn, you may have goals available to bots earlier or later than intended; potentialy breaking the gameplay.
Case Study
Scenario: Map is Fueldump and goals are being activated or deactivated based on the Main Bridge status. When the bridge is built, attack and defend goals are activated and when it is destroyed, goals are deactivated. To add to the complexity, some of the same goals are activated / deactivated based on the status of the footbridge.
The first thing that needs to be done is to create some variables for use in the conditional statements. Official map scripts add these variables to the Map table:
global Map =
{
//conditional variables
BridgeStatus = 0, //not built
FootBridgeStatus = 0,
};
The next step is to set these variables in the appropriate triggers:
global Map =
{
//conditional variables
BridgeStatus = 0, //not built
FootBridgeStatus = 0,
footbridge_Built = function( trigger )
{
Map.FootBridgeStatus = 1; //built
},
footbridge_Destroyed = function( trigger )
{
Map.FootBridgeStatus = 0; //not built
},
bridge_Built = function( trigger )
{
Map.BridgeStatus = 1; //built
},
bridge_Destroyed = function( trigger )
{
Map.BridgeStatus = 0; //not built
},
};
Now that we have status' updating correctly, conditional statements can be added to help ensure goals are active at the appropriate time:
global Map =
{
//conditional variables
BridgeStatus = 0, //not built
FootBridgeStatus = 0,
footbridge_Built = function( trigger )
{
Map.FootBridgeStatus = 1; //built
SetAvailableMapGoals( TEAM.ALLIES, true, "ATTACK_Tunnel_Doors.*" );
},
footbridge_Destroyed = function( trigger )
{
Map.FootBridgeStatus = 0; //not built
//if both bridges destroyed, shift the defense back
if ( Map.BridgeStatus == 0 )
{
SetAvailableMapGoals( TEAM.ALLIES, false, "ATTACK_Tunnel_Doors.*" );
SetAvailableMapGoals( TEAM.ALLIES, true, "ATTACK_Bridge_.*" );
}
},
bridge_Built = function( trigger )
{
Map.BridgeStatus = 1; //built
SetAvailableMapGoals( TEAM.ALLIES, true, "ATTACK_Tunnel_Doors.*" );
SetAvailableMapGoals( TEAM.ALLIES, false, "ATTACK_Bridge_.*" );
},
bridge_Destroyed = function( trigger )
{
Map.BridgeStatus = 0; //not built
//if both bridges destroyed, shift the defense back
if ( Map.FootBridgeStatus == 0 )
{
SetAvailableMapGoals( TEAM.ALLIES, false, "ATTACK_Tunnel_Doors.*" );
SetAvailableMapGoals( TEAM.ALLIES, true, "ATTACK_Bridge_.*" );
}
},
};
All looks good at this point. At the beginning of the map, the allied bots will be shifting correctly based on both bridges status. There is a potential problem here though. What happens if someone builds or destroys a bridge after the tank is through the tunnel? The goals back by the bridge will be activated again. The solution is to pick a major event to check against and add that to our conditionals. In this case we will check the status of the Tunnel door before activating those goals:
global Map =
{
//conditional variables
BridgeStatus = 0, //not built
FootBridgeStatus = 0,
Tunnel_Doors = true, //doors intact
tunneldoors_Destroyed = function( trigger )
{
Map.Tunnel_Doors = false;
},
footbridge_Built = function( trigger )
{
Map.FootBridgeStatus = 1; //built
if ( Map.Tunnel_Doors )
{
SetAvailableMapGoals( TEAM.ALLIES, true, "ATTACK_Tunnel_Doors.*" );
}
},
footbridge_Destroyed = function( trigger )
{
Map.FootBridgeStatus = 0; //not built
//if both bridges destroyed and doors intact, shift the defense back
if ( Map.BridgeStatus == 0 && Map.Tunnel_Doors )
{
SetAvailableMapGoals( TEAM.ALLIES, false, "ATTACK_Tunnel_Doors.*" );
SetAvailableMapGoals( TEAM.ALLIES, true, "ATTACK_Bridge_.*" );
}
},
bridge_Built = function( trigger )
{
Map.BridgeStatus = 1; //built
if ( Map.Tunnel_Doors )
{
SetAvailableMapGoals( TEAM.ALLIES, true, "ATTACK_Tunnel_Doors.*" );
SetAvailableMapGoals( TEAM.ALLIES, false, "ATTACK_Bridge_.*" );
}
},
bridge_Destroyed = function( trigger )
{
Map.BridgeStatus = 0; //not built
//if both bridges destroyed and doors intact, shift the defense back
if ( Map.FootBridgeStatus == 0 && Map.Tunnel_Doors )
{
SetAvailableMapGoals( TEAM.ALLIES, false, "ATTACK_Tunnel_Doors.*" );
SetAvailableMapGoals( TEAM.ALLIES, true, "ATTACK_Bridge_.*" );
}
},
};
For a complete example of conditional usage, look through any of the map scripts released with version 0.65.
Scripting Tools
makegm
makemapgm is a command that autogenerates a skeleton map script. Usage of this command will ensure a standard format and save time. Using the command is fairly straight forward:
- Step 1: Load the map you want a script for
- Step 2: Type /bot makegm in console. It will display a message if executed correctly
- Step 3: Copy the mapname.gm file from ~/omni-bot/et/usr to ~/omni-bot/et/nav, Be sure to have backed up any mapname.gm file you may have been working on that exists in the nav folder.
The OnTriggers in OnMapLoad will need to be modified as makemap.gm does not find the information needed. Simply edit the "MISSING STRING" parameter of the OnTrigger function and the triggers should be working correctly.
Debugging Tools
debugbot
debugbot is a valuable tool to use if bots aren't behaving as expected. It will give information about the bots current goal.
syntax: /bot debugbot all fpinfo or: /bot debugbot <bot-name> fpinfo
It is recommended to have only one or two bots connected when issuing this command with the all parameter as it will give debug output for each bot.
ScriptDebug
Script debugging is crucial as a high percentage of errors are syntax related. There are two ways to enable script debugging:
- /bot script_debug 1
- EnableScriptDebug(true);
EnableScriptDebug(true); can be placed in et_autoexec.gm while /bot script_debug 1 will need to be executed in console each time the map loads. If an error in script occurs while script debugging is enabled, the error will be listed in console in red text with the line number of the error.
note: in the omnibot.log, script errors will be written whether script debugging is enabled or not.
GameMonkey interpreter
The GameMonkey download available at www.somedude.net/gamemonkey/ contains an interpreter for gm files (gme.exe) that can be used as a syntax checker. With this, you won't have to start the game only to find you forgot a closing bracket or a semicolon.
Ideally, use this with an editor that can run command line applications and capture their output, such as SciTE, PSPad or Notepad++.
print is a low level means of debugging a script. It can be used in cases where you want to test if a trigger is working correctly or if the map script has loaded:
global OnMapLoad = function()
{
print("OnMapLoad");
}
The print statement can also be used in-game via script_run if you want to inspect the value of a variable:
/bot script_run "print(variable)"
show_goals
syntax: /bot show_goals <optional expression> <optional p>
usage: the optional expression parameter can be used to display one or several goals. The optional p parameter is used to display any
priorities that may have been set with the SetGoalPriority function.
show_goals can be useful to test whether or not goals are available when they are expected to be and that they have the expected bias setting. The output from show goals is similar to:
HEALTHCAB_north_healthcabinet -> 0100 serial 2 priority 0.40 ALLIES AXIS MEDIC 0.00 HEALTHCAB_south_healthcabinet -> 0000 serial 5 priority 0.40 ALLIES AXIS MEDIC 0.00
The number just to the right of the arrow represents teams and status. 1 means it's available for that team while 0 means it is unavailable. With the optional p parameter given, the output will include any priorities set for individual teams and / or classes.
show_goalroutes
syntax: /bot show_goalroutes <optional> usage: used to list routes used for a give goal or goals
draw_goals
syntax: /bot draw_goals [on|1|off|0] <optional> usage: the optional parameter can be used to display one or several goals.
Note: the optional parameter supports regular expressions. /bot draw_goals .*BUILD.* will draw BUILD goals.
This will draw the location of goals to your screen. Useful to see where bots "think" an object is located.
draw_goalroutes
syntax: draw_goalroutes on/off <optional goal name expression> usage: used to draw the given goal(s) routes