While a compiled map (.bsp file) allows human players to play, an additional element is necessary, to be able to add bots to the map: an .aas file. Bots try to mimic human players, but they have limitations mappers should consider.
Reasons to care for botplay Edit
There are many reasons to care for bot play.
First, you may make your map so humans can play, but it's very unlikely for your map to end in every real server map rotation, as servers have the tendency to restrict the allowed gametypes and maps to very few of each; this is something called Complacent Gaming Syndrome.
And even if your map gets included into official OA releases or popular mappacks, good botplay is also mandatory there: consider players waiting for some other human to join the server: they may play with bots in the meanwhile. Also, not even OA official maps are safe from the above.
Plus, a map with bot support enables offline play, so players can play the map even if they can't get online.
Also, getting rid of the current AI system or changing it with a different system such as waypoints falls outside of the scope of OpenArena, as each map should always have its own AAS file for compatibility reasons.
All in all, there's no reason for your maps to lack bot support.
Now let's take a look at what BSPC is, how it works and where to get it.
Partially taken from the BSPC readme, the BSPC tool is used to create the AAS (Area Awareness System) files from BSP files.
The process of AAS file creation is basically the same as the process used by the VIS stage: the map is subdivided in many small nodes called "areas" instead of "leaf nodes", and every area is a visibility section from where other areas can be seen. Areas are then regroupped into bigger zones called Clusters.
There are a few differences, though: the only brushes taken in account for the calculation of the areas are the solid, clip, liquid, clusterportal and donotenter ones. This means that structural, detail, patches and areaportals will be taken in account, but hints are not. Clip brushes include clip, botclip, weaponclip and full_clip. Clipping is important for BSPC, as it allows the simplification of the map without modifying the world's geometry. Likewise, clusterportals act as areaportals in the regard that a bot may see an area or not.
The latest "official" version of BSPC (created by Mr. Elusive, the creator of the AAS system) is 2.1. BSPC comes bundled with many editors, mainly GTKRadiant, but for editors such as NetRadiant or older versions of *Radiant, however, a newer BSPC must be taken from somewhere else. There are various BSPC "forks" around the net.
- BSPC 2.1i (Special version of BSPC created for SimonOC's Pyramid of the Magician) (Internet Archive)
- BSPC @ bnoordhuis' GIT
- BSPC @ ttimo' GIT
A few examples of BSPC usage:
bspc -bsp2aas -forcesidesvisible yourmap.bsp
The command above creates the .aas file for your map.
bspc -grapplereach -forcesidesvisible -optimize -threads 4 -bsp2aas yourmap.bsp
This command also calculates reachabilities for the grappling hook, optimizes the aas filesize and uses four threads to make compiling faster.
Please read the considerations below, which also include explanations for those parameters.
For your comfort, you can place the command into a batch file/shell script.
See Mapping manual/Compiling and packaging#BSPC for a list of BSPC parameters.
Clip brushes: bot clip, player clip and weapon clip Edit
The first and most basic optimization is to clip your map. Clipping helps a lot to the compilation of AAS file, by making bot navigation around the map a lot easier without the need to change the world's geometry.
Use brushes texturized in all of their faces with the invisible texture common/weapclip, common/clip or common/botclip to specify collisions around geometry.
- Weapclip (weapon clip) means that weaponfire, players and bots won't be able to pass through it.
- Clip (player clip) means that players and bots won't pass through it, but weaponfire will do.
- Botclip (bot clip) means that only bots will not be able to pass through it. Botclip can be used to clip walls with uncommon shapes or things incrusted in them.
These three are the most commonly used "clip" brushes. Some other variants are available, e.g. to emit "metalsteps" sounds instead of standard footsteps sounds while walking on them. You can even create your own variants of these shaders -e.g. "textures/my_own_map/clip_flesh" shader- if needed.
Forcing paths with DoNotEnter Edit
As botclip blocks the bot from accessing a determined area, in deathpits and other hazard zones like lava/slime pits you should use brushes texturized with common/donotenter ("bot do not enter") instead. Donotenter acts as a "hint" to not enter a certain area, opposite to botclip which "physically forbides" them to go to a certain area.
DoNotEnter does not risk to show bots walking mid-air, as botclip does in case the top of the brush is accessible.
DoNotEnter can also be used to control bot navigation along corridors and around corners to prevent wayward access when the use of botclip is not possible or impractical. Encasing areas in donotenter means that we can direct or force navigation without physically restricting it with invisible walls of botclip.
However do not exceed with their usage if not necessary, considering a "donotenter" creates an extra "area" that bot logic has to consider.
The importance of the NoDrop brush Edit
Alongside to the above, place at the bottom of the hazardzone a brush texturized in all its faces with the common/nodrop brush. This makes items and flags to disappear at the zone in question. Otherwise, bots would ignore botdonotenter and try to get these items/flags by entering in the hazard/death zone.
This is not only important for bots, but also for humans: think about recovering a flag which is dropped in a lava pit or in space void... "Nodrop" allows to prevent such problems.
Bot play entities Edit
There are two botplay-dedicated entities supported in the game: info_camp and item_botroam
- info_camp allows to suggest bots places adapt for camping. Bots may have more or less "campy" attitude: sometimes they may stop in a certain place and look around, waiting for other players to enter their visual field.
- item_botroam attracts bots to an area they don't go often.
This atttracts bots which have a camping preference in their A.I. characteristics. It should be placed at least 32 units away from any brush surface.
- range: number of units that the bot can move away from camp entity while camping on it.
- weight: number that is compared against the weight assigned to all the other camp spots in the map to determine if a bot chooses to camp there. The value is normalized against all other weight values.
An invisible entity that attracts a bot to it. Used to move bots to parts of a map that might otherwise not be used.
- weight: non-zero floating point value, most often in the range 0 to 400. Very low values are unlikely to attract a bot to that area, since most bots have "desires" that attract them to other game entities. Higher values are allowed but keep in mind that the bot should also be attracted by normal items. Don't make the weight value too high. Don't forget to set this key.
Notes about these entities Edit
- Info_Camp entities should be reachable by "normal" means, including relatively non-complex rocket jumps.
- The item_botroam entity can be used when a bot does not roam the whole level or prefers to go to only specific areas. But don't confuse these items with "way points". They are more like magnets. This (invisible) item can be placed in a map just like regular items. Nobody can actually pick up the item it's only used to attract bots to certain places of the map. The value is the weight of the roam_item is relative to the weight assigned other items in the map (each bot has its own weights). The bot character specific item weights are stored with the bot characters in the botfiles/bots/ sub-folder in the .pk3 file.
- When a bot should never go for a specific item the key "notbot" with value "1" can be used for that item. This key with value can be used for every available item in OpenArena.
- Wait to place these items until you've done a significant amount of live play testing on the final map against bots. Observe a bot-only match (/timescale <n.n> may help you. It requires /devmap <mapname>.). See which parts of the map they DON'T use frequently. Use bot roam entities to encourage the bots to follow more paths through the map.
If your map is big enough (for instance, lots of levels and Z-axis action) or if it has a lot of complex geometry, try using brushes with common/clusterportal in all of their faces to split the map into different "clusters". Optimization through these invisible and non-solid brushes may allow to prevent bot-related hitches (bot stutter). Some considerations to bear in mind:
- Clusterportals MUST seal completely the sections these divide.
- You have to be careful with teleporters: sections won't be sealed if there's a teleporter going from one cluster to another, resulting in both clusters merged as one, no matter if the teleport is a one-way one. A solution can be isolating the teleporter (or its surrounding area) from the rest of the map with botclip and placing clusterportal entrances.
- Clusterportals won't work if a trigger_push trajectory is crossing it.
- Clusterportals MUST be walked to get pass on them, they won't work if the only way to get through it is by falling, it doesn't matter if the clusters get divided succesfully. In other words, you can use clusterportal to seal vertical doors, but not horizontal hatches.
- Clusterportals' entrances and exits should be identically shaped.
- Clusterportals should be as axial as possible. If you're going to place a clusterportal in an arched door, botclip it to make a rectangular passing, and fill that hole with a clusterportal.
- Clusterportals should be surrounded by solid geometry or clip. (No matter if it's a normal clip, botclip or weapclip)
- Clusterportals MUST be 16 units thick.
- Clusterportals should only separate 2 clusters.
As a rule of thumb, it's better to try to keep every cluster under 500 areas. Also, careful clipping usage may allow to get fewer areas.
While in-game, /bot_testclusters 1 tells you the number of the cluster you are in. /Bot_testclusters works only if the map has got its .aas file, and does not work while spectating.
Space maps Edit
This is a very touchy issue, so it deserves its own section.
In a large space map with lots of jump-pads, placing clusterportals can be a very daunting task, as most of the map is crossed with trigger_push trajectories and teleporters, there are no obvious door-type structures which seal off any area, and there are usually vertical access points to almost every single part of the map. If the map is simple enough, you can get away with not adding clusterportals. But the problem arises with more complex architecture.
The only way to get clusterportals working properly in space is to split the map into approximately equal sized sections using huge botclip walls, 16 units thick, which go all the way across the skybox and seal completely the areas they divide. Then, use the clipper tool to make rectangular 'windows' in these walls where the bots will need to go through them, and filling these windows with clusterportals.
Like said above, you should be aware of trigger_push trajectories, and surround teleporters with botclip brushes and clusterportal entrances in order to avoid any kind of inconveniences.
- There's no need to use a clusterportal if there's an areaportal on it.
- Bots won't go to areas where special tricks such as strafe jumps are required, however sometimes they may perform rocketjumps, if the height is not excessive. You may wish to botclip or botdonotenter such areas.
- Use "suspended" flag on items with caution, and avoid using it with objective items: bots will try to get "suspended" items only if they can be reached by using an accelerator pad/bounce pad; they will not jump down from a platform to reach a suspended item. They can reach items "suspended" in water.
- Clip brushes are very useful to make geometry simpler, helping humans and mostly bots to navigate the map. However consider that they are invisible walls on which characters may impact against if pushed by explosions or accelerator pads, or may jump on their tops and then apparently walk mid-air.
- Be extremely careful with using the "gametype" or "!gametype" key in func_static entities or any brush-based entity: they cannot be used to make real changes in map flow. AAS file is the same for all gametypes: bot minds do consider func_static brushes as existing even in gametypes where they do not appear, with potential enormous problems. See Mapping manual/Additional gametype support#The "gametype" and "!gametype" keys for more infos.
- Bot support for offhand grapple, at the moment, is incomplete and buggy. Bots would use it only if bot_grapple variable is set to 1 (enable it for testing purposes only; default value is 0) and the .aas file has been previously compiled specifying the -grapplereach BSPC option. You may wish to set that BSPC switch anyway, in case future OA versions may complete bot grapple support; enabling it would cause BSPC tool "reachability" phase to take a bit longer time, and the resulting .aas file would be slightly larger.
- Bots do not use light informations: they can locate their target also in a pitch-black room.
- Important to know about BSPC usage:
- If you compiled your map with BSP -meta switch (something nowadays recommended), it's a MUST to use BSPC -forcesidesvisible switch when compiling its AAS file then. Otherwise, your bots won't go anywhere, but will see everything as solid space.
- Everytime the BSP is recompiled, the AAS file must be recompiled as well, or else bot paths are lost. In case only entities were modified, it's possible to only recalculate reachabilties by using bspc -reach mymap.bsp, to save a little time; in every other case, a full AAS re-compiling is required.
- For your public release, don't forget the -optimize BSPC switch, to compact AAS filesize. It's a very quick option.
- BSPC tool can take advantage of multithreading for faster AAS compiling, but you have to manually set the number of threads (-threads <n> parameter). In short: for fastest compiling, set to the number of the logical "cores" of your CPU; in case this crashes bspc, try another bspc version or stick with a single thread. Please read Multithreaded map compiling for more infos.
Error messages on BSPC Edit
Taken from Id's documentation about BSPC:
Level designers should not worry too much about the following messages and/or warnings. The things reported are non fatal and won't cause any major problems. Some of the messages are just debug left overs.
- AAS_CheckArea: area %d face %d is flipped
- AAS_CheckArea: area %d center is %f %f %f
- AAS_CheckFaceWindingPlane: face %d winding plane unequal to face plane
- AAS_CheckFaceWindingPlane: face %d winding reversed
- area %d face %d flipped: front area %d, back area %d
- area %d face %d is tiny
- face %d and %d, same front and back area but flipped planes
- AAS_SplitFace: tiny back face
- AAS_SplitFace: tiny back face
- AAS_SplitArea: front area without faces
- AAS_SplitArea: back area without faces
- gsubdiv: area %d has a tiny winding
- AAS_TestSplitPlane: tried face plane as splitter
- found %d epsilon faces trying to split area %d
- AAS_SplitArea: front area without faces
- AAS_GetFace: face %d had degenerate edge %d-%d
- AAS_GetFace: face %d was tiny
- WARNING: huge winding
- bogus brush after clip
- split removed brush
- split not on both sides
- two tiny brushes
- possible portal: %d
- portal %d: area %d
- WARNING: CM_GridPlane unresolvable
- WARNING: CM_AddFacetBevels... invalid bevel
- WARNING: CM_SetBorderInward: mixed plane sides
- WARNING: bevel plane already used
- trigger_multiple model = "%s"
- trigger_teleport model = "%s"
- found a trigger_push with velocity %f %f %f
- AAS_TraceBoundingBox: stack overflow
- AAS_TraceAreas: stack overflow
- AAS_LinkEntity: stack overflow
- MergeWindings: degenerate edge on winding %f %f %f
- Warning: MergeWindings: front to back found twice
- FindPlaneSeperatingWindings: winding1 non-convex
- FindPlaneSeperatingWindings: winding2 non-convex
When one of the following messages, errors or warnings is found then there is often something to be fixed.
- WARNING! HashVec: point %f %f %f outside valid range. This should never happen!: While storing the AAS file some vertex was found outside the valid map bounds. When this happens some part of the map is likely to have badly aligned brushes or weird shaped curves. Clipping off or rebuilding complex shapes often helps.
- trigger_push start solid: The trigger_push start point is in solid. Try making the trigger_push brush a bit larger or move it around a bit.
- trigger_push without target entity %s: Could not find the target entity of the trigger_push with the target field %s.
- trigger_push without time: trigger_push entity found without "time" field.
- trigger_multiple not in any jump pad area: A trigger_push entity was found not to be in any valid jumppad area. (the message states trigger_multiple but it should have been trigger_push) Try making the trigger_push brush a bit larger or move it around a bit.
- trigger_multiple at %1.0f %1.0f %1.0f without target: A trigger multiple was found at the given coordinates without a "target" field.
- target_teleporter without target: A target_teleporter entity was found without target field.
- trigger_teleport at %1.0f %1.0f %1.0f without target: A trigger_teleport entity was found at the given coordinates without "target" field.
- teleporter without misc_teleporter_dest (%s): The destination of a teleporter with target field %s could not be found.
- teleporter destination (%s) without origin: A teleporter destination with the target name %s was found without origin field.
- teleporter destination (%s) in solid: A teleporter destination with the targetname %s was found to be in solid.
- teleported into slime or lava at dest %s: A player would be pushed into slime or lave at the teleporter destination with the targetname %s.
- trigger_multiple not in any area: A teleporter trigger was found not to be in any valid area. Try moving the trigger around a bit.
- func_plat without model: A func_plat entity was found without model field.
- func_plat with invalid model number: A func_plat entity was found with the model field set to some invalid number.
- func_bobbing without model: A func_bobbing entity was found without model field.
- func_bobbing with invalid model number: A func_bobbing entity was found with the model field set to some invalid number.
- %s in solid at (%1.1f %1.1f %1.1f): An item with classname %s was found to be in solid at the given coordinates.
- empty aas link heap: Some part of the map has some rather complex clipping. Reduce the geometric complexity or use clip brushes to reduce the clipping complexity.
- too many entities in BSP file: There are too many entities in the bsp file.
- error opening %s: Could not create a new AAS file. Hard disk might be full.
- error writing lump %s: Could not write an AAS lump to file. Hard disk might be full.
- ↑ 1.0 1.1 BSPC readme
- ↑ 2.0 2.1 2.2 Bot Optimization Guide by Cardigan
- ↑ Bots do prefer simple, axial geometry. Enclosing strange shapes into simpler and XYZ oriented "clipped" brushes makes bots life more easy.
- ↑ Example of usage: you may include a "mapmodel" .md3 3D model in your map, for example a statue. That 3D model will be "incorporeal", unless you add some clipping: you may want to enclose it into a single "player clip" or "bot clip" box, and to place some smaller "weapon clip" brushes a bit closer around the statue (roughly following its shape). That way, players and shots will seem to be blocked by the statue. See also Mapping manual/Mapmodels.
- ↑ "Player clip" is also often used in big brushes to create an "invisible ceiling" lower than actual sky, to prevent spectators from reaching too much high places which would show some glitches due to viewing parts of the map which should not be viewed from above.
- ↑ The BotDonotEnter brush at Kat's Bits
- ↑ "Do Not Enter" Areas in GTK Radiant Bot Navigation Appendix
- ↑ GTKR Manual, Appendix B4
- ↑ GTKR Manual, Appendix B5
- ↑ Clusters with too many areas may sometimes cause the game to require too much time to determine where a certain bot will go next, hence causing a short "freeze": splitting that huge cluster into smaller clusters should fix the problem.
- ↑ You can compare it with the output of bspc command -in bspc.log- to find out which are the clusters with too many areas, and that may need to be further divided.
- ↑ Bot navigation files: how high bots would jump, and much more.
- ↑ With gametype objectives, it's advisable to perfectly align their "origin" point with the ground.
- ↑ If you seal a corridor for a certain gametype, bots will never try to pass through that corridor also in all other gametypes; if you set a bridge, a box or a ledge for certain gametypes only, bots may try to step over it also when it does not appear, goofy falling down repeatedly. Also usage with trigger brushses, such as teleporters or accelerator pads, may cause problems to bots, while usage with func_door and func_button should work well enough: please check actual bots behavior anyway. You can order a team-mate of yours bot to follow you, in team-based modes, to see how it behaves in such places. Usage with nonsolid decorations should be safer. Gametype key is often used with standard entities such as items to pickup, however try do to not make excessive use of it.
- ↑ If an AAS file has not already been optimized, it's possible to use "-aasopt" mode to optimize it later... however, there is no reason for not optimizing at creation time. Unless you are still developing the map and you wish to use one of the few debugging features of the game which do not work with optimized aas.
- The Quake III Arena Bot: detailed guide about how the Q3A bots work. Can be useful for bot and map development.
- LevelDK 6: clipping and bot play, clusterportals
- Cardigan's bot optimization tips
- GTKR Manual Bot navigation. Very useful document about BSPC and bot infos such as maximum step height, maximum obstacle/jump height, aas testing.