Bot Optimization Guide

by Cardigan

So far, the few bot tutorials that I've seen have seemed to consist entirely of:

Run BSPC on your compiled .bsp to create a bot navigation (.aas) file.

The End.

Ah, if only it were that simple.....

Unless you are extremely lucky or your map is one box with a rocket launcher and a spawn point in it, the bots will probably play really dumb. Worse still, you may encounter 'bot stutter' - an uneven framerate caused by CPU overload on the bot AI. Now its very easy to say "well, this map is designed for human players anyway so I'll leave it" but the sad fact of the matter is that its quite unlikely that your map will end up on any servers, so its worth making the botplay as good as possible. Happily there are several things that can be done to improve matters, and this tutorial is here to tell you what they are.

However, before we start there are a few things bots will never, or hardly ever, do:

a) Bots will not usually shoot at a shootable trigger or button.

b) Bots will not press a button voluntarily (although you can make them using an item_botroam - but these are not conditional, so the bot will carry on trying to activate the button even if it isn't necessary, and/or won't go for it above anything else when it is necessary)

c) Bots are pretty rubbish at working out jumps and even worse at working out rocket jumps and strafe jumps. If an area of your map can only be reached by jumping don't be surprised if you can't get the bots to use it.

d) Bots will only try to get floating items (those flagged as 'suspended') by using jump-pads and launch-ramps. They won't jump or deliberately fall off a ledge to get a suspended item.

OK, now that's out of the way, download a copy of Q3ME if you haven't already got it (makes compiling the .aas file self-explanatory) and let's get on with the optimisations:

1. Simplify the collision hull with playerclip, weaponclip and botclip.

Bots like simple blocky shapes to maneouvre round. They especially like blocks which are axial (parallel to the gridlines). Of course, you could just build your map out of axial blocks, but it would probably look a bit pants. This is where our various kinds of clip come in.

Weaponclip blocks the movement of players, bots and weaponfire. Playerclip blocks players and bots, but allows weaponfire through. Botclip only blocks bots.

Important note: Bots will fire through botclip, but seem to view playerclip as impenetrable.

The good thing about botclip is that it does not affect a human player in any way, so you can stick great big huge axial botclip brushes round more complicated architecture and no-one will ever know. Except the bots, who will like you and your map a whole lot better. Oh, and BSPC which will compile a whole lot faster too.

Remember that the only way a player will notice a botclip brush is if it stops a bot from being thrown through an empty space by an explosion, or if it is really in the way of a normal route round the level. Otherwise, the bots will just navigate round it and nobody will be any the wiser.

Stick botclip brushes everywhere you can get away with it to simplify the collision hull that the bots see.

Prime contenders for clip intervention are:

a) Empty spaces above the players that the bots will never be able to get to can be botclipped - for example, in Q3DM4 there's a lot of this because the ceilings are so high.

b) Walls/floors/ceilings with lots of architectural detail - this kind of thing should usually be flattened with playerclip because it will probably get in the way of human players as well. Playerclip also acts as botclip - you don't need an overlapping botclip brush.

c) Curvy pipes and suchlike - any complex patchmeshes can complicate the .aas file unnecessarily. Make them non-solid and encase them in simplified weaponclip brushes as far as possible.

d) Any space which cannot be reached in the normal course of play - doesn't matter if it is just about possible to get there, if the bots aren't likely to, botclip it off! Look out for small areas under ledges which the players cannot fit into and things like that.
Botclip can also be used to stop the bots doing stupid things like jumping off the edge of a map, or not giving themselves enough forward thrust to make a fall from a platform without landing in some hazard. The latter is acheived by placing a botclip brush next to the edge of the platform as shown below - now the bots will slide down it (as long as it's steeper than 45 degrees) and over the hazard, rather than into it.

Sometimes, you can use botclip to make an area that the bots keep killing themselves in more hazardous, so that the bots will realise it's dangerous and avoid it. For example, bots often think that they can land on very small or narrow bits of architecture over hazards, when in actual fact 9 times out of 10 they miss it and fall to their doom. However, you don't want to stop human players being able to attempt it. In this case you can use another steeply angled bit of botclip that makes it impossible for the bots to land on the offending brush - they would simply slide off. Now the bots should see the danger and stop acting like lemmings.

2. Where you can't use botclip, use botdonotenter.

If after all your botclipping efforts the bots still insist on going places you don't want them too you can try using botdonotenter brushes instead. In theory, these create an area which the bots will avoid unless they are pushed into it or there is a worthwhile goal, such as an item or flag within it. In practice, the bots sometimes completely ignore them, so it's just trial and error really. I used a botdonotenter brush just taller than a player to stop the bots loitering over the trapdoors in my first map:

I think they thought they could get down through the trapdoor to the item_botroam I had placed on the jump-pad below, even though the trapdoor was one-way and only triggered from below. Luckily, my fix worked, and didn't stop them using the trapdoor from below and shooting up through the botdonotenter brush (I guess a trigger_push counts as being pushed into the area...?)

3. What to do if the bots won't use certain parts of your map.

First check that there isn't an error in the .aas file which is causing the bots to see that area as solid. To do this, load up your map in devmap mode and type \bot_testsolid 1 into the console. Now you should see a readout at the top of the screen which says either EMPTY or SOLID. Go to the part of the map where the problem is and see if the .aas file is reporting any empty space as solid. If it is, you will either need to simplify the collision hull in that part of the map or use the -forcesidesvisible commandline switch when compiling your .aas file. This should fix any errors but will take a lot longer and is not recommended.

Another way to test for this kind of problem is to load up the map in a teamplay mode and tell one of your team-mate bots to follow you as you go to the problematic area. If they make it OK, then there probably isn't an error, and its just the bots being stupid.

If there are no errors of this type, try placing item_botroam entities in the area. Item_botroams attract bots in the same way as any other item would, and you can control how much they attract the bots as compared to other items by setting the 'weight' key. It's suggested that you keep the value under 400, but for testing purposes you can go higher than this, so make it 800 or something like that. Then fire up the map and see whether the bots go to the area. If they do, then adjust the weight key so that the bots don't use that area too much - if the weight is too high then the bots may keep trying to 'collect' the item_botroam over and over again, because unlike a regular item it never actually gets picked up.

Important note: Just got this tip from [AF]haste - if the bots refuse to use a jump-pad it may be because the target_position at the end of the jump-pad's trajectory is too close to the floor. On his map, increasing the gap from 64 to 96 units did the trick.

If they still don't, and you have already balanced your cluster portals (see 5, below) then it is probably because they don't see how they can get there at all (remember they are very stupid), or they think that the item_botroam is impossible to get to without dying. Jump-pads which propel the player along a curved surface, like in Flying Plutonians by nunuk and Scorpion by me, are particular culprits - especially if they are over a fatal drop. Even placing an item_botroam on the jump-pad itself will not always persuade the bots to use it. In my case, I actually had to drop two really cool double curve jumps from Scorpion because the bots simply wouldn't use them, no matter what I did. As mentioned before, you may get similar problems with areas only reachable by jump or rocketjump.

4. How to 'fake it' with buttons and triggered doors

I was originally going to write this bit saying that bots are not clever enough to work out when an item that is, for example, behind a triggered door, or over a fatal drop with a triggered bridge, is actually available and as a general rule will not go for an item that is sometimes inaccessible. In my experience (which isn't that much admittedly) this has seemed to be the case. I was then going to suggest some pretty crude workarounds. (eg hidden trigger_pushes which are covered with a triggered trapdoor and propel the bots through the triggered door when it is open. I used this trick in Scorpion to get the bots through the tail doors)

However, I put together a small testmap to test the default behaviour and found some interesting and surprising results:

The testmap consisted of an empty room with spawnpoints in connected by either triggered door or bridge over a fatal drop to another room with loads of goodies in. I tested it both with and without an item_botroam by the button.

First I tested the door without an item_botroam - all the bots knew that the goodies were behind the door and loitered around it acting like idiots. None of them went anywhere near the button to open it. However, when I opened it for them they all bundled in and got the goodies.

Next, I tested the bridge without an item_botroam - all the bots completely ignored the goodies and ran around shooting each other with machine guns and ignoring the button. When I raised the bridge for them they continued to ignore the goodies.

Next I tested the door with an item_botroam and it worked tolerably well - bots went for the button and went for the door, and the two coincided quite a lot allowing the bots to get the goodies, although I don't think the bots were actually aware of the link between the button and the door. They were still prone to loiter round the door when it wasn't open.

Finally, and strangest of all, I tested the bridge with an item_botroam. Now when the bridge wasn't there the bots avoided the fatal drop like they had before, but when they were attracted to the button by the item_botroam and activated it, they realised that they could now go across the bridge and get the goodies. This perplexes me, because simply by adding the item_botroam to the button we seem to have gained a level of intelligence from the bots regarding the bridge and the fatal drop. They were now aware of whether it was safe or not to cross the gap, although again I don't think they were aware of the link between the button and the bridge. They also didn't exhibit the loitering behaviour that they had with the door, making this the most successful test.

Having said all this, I've yet to see this happen in a custom map, although it does seem to work in Q3DM7 with the button opening the trapdoor to the red armor room. I always assumed this was a bit of a coding hack, but perhaps not. I do vaguely remember reading that one point release had updated the bots 'button intelligence', so maybe that explains it. Whether it would still work outside of the very basic axial architecture of my testmap is, ahem, left to the reader as an exercise ;)

5. Clusterportals

Ah, clusterportals. Now we get to the fun part. If your idea of fun is staying up into the small hours repeatedly recompiling your .aas file. It's worth noting at this point that you only need to run the BSPand BSPC stages of the compile to test bot stuff - you can omit VIS and LIGHT altogether.

First off, you'll need to know what a cluster is, so here goes....

When BSPC creates a bot navigation file for your map, it splits the map up into very small 'reachability areas'. Each reachability area is essentially a single surface which a bot can move upon during play. Using the clipping methods described above will reduce the number of reachability areas in your map and hence reduce the complexity of the in-game AI calculations. However, if the map is of a reasonable size and/or geometric complexity there will still be too many areas to consider at any one time, so BSPC simplifies the calculations further by dividing the areas into groups called clusters. The place where two clusters meet is known as a clusterportal. In an ideal situation, the clusters should be balanced (that is, each should have approximately the same number of areas) and there should be under 500 areas in each cluster. This isn't always possible, especially on very open maps, but the closer you can get to it, the faster the bot calculations will be, the better the bots will play, and the less likely it will be that your map will suffer from the evil that is bot stutter.

Problem is, BSPC doesn't always split up the clusters very well, unless your map is a mostly horizontal room-corridor-room-corridor-etc map. When there are lots of overlapping vertical layers the chances of BSPC working out the clusters properly are pretty small.

So, what can be done? First you'll need to see what BSPC has done with your map by default, so after compiling the .aas file open up the bspc.log file in your Quake3 root folder. You'll probably see quite a few warning messages like WARNING: CM_AddFacetBevels... invalid bevel or AAS_GetFace: face 21271 had degenerate edge 3-4 but don't be alarmed - more than likely they're just harmless non-fatal warnings that you don't need to worry about. Scroll down to near the bottom of the logfile and you should see something like this:

cluster 1 has 301 reachability areas
cluster 2 has 5 reachability areas
cluster 3 has 736 reachability areas
cluster 4 has 10 reachability areas
cluster 5 has 17 reachability areas
cluster 6 has 3 reachability areas
1072 total reachability areas

(this is from compiled without clusterportals)

Unsurprisingly, this is a list of all the clusters and the number of reachability areas in each. The trick is to balance them up so that each cluster contains roughly the same number of areas. In the above example we should be aiming to get rid of some of the very small clusters and have about 6 clusters containing about 160 reachability areas each, or 4 clusters containing about 200 areas. But at the moment you don't even know which cluster refers to which part of your map, so fire up your map with the devmap command and type \bot_testclusters 1 into the console. Lo and behold you now have a readout saying which cluster you are in at the top left of the screen. A minus number indicates you are inside a working clusterportal. Zero indicates that you are on a trigger_push trajectory.

What you are looking for are places where you could manually force a clusterportal to even up the numbers. You do this by using a brush textured on all sides with the common/clusterportal shader. In room-corridor-room maps like Q3DM7 the obvious place for clusterportals is in doorways. In more complex maps you'll have to be a little more creative. However you can't just stick them in anywhere - there are quite a few conditions that have to be met before BSPC will accept your forced clusterportals as valid and include them in its calculations. Stick to the rules below and you should be OK.

Clusterportals must completely seal off a section of the map to make that section a cluster in its own right.

Taking a tip from this tutorial on areaportals by Jon Eriksson, I think the best way to explain this is to look at the section of the map that you want to become a separate cluster and imagine that you are filling it completely with water. (Hide any entities, models and non-solid brushes from the view first as they will not block our virtual water. Unlike with areaportals, detailbrushes (as long as they are solid) will block the water)

Now, if any water can escape into another section of the map without going through a clusterportal then the cluster will not be created. Take a look at the screenshots below and imagine we want the corridor to be cluster 1 and the room to be cluster 2. (The ceiling has been removed so you can see what's going on)

of course, in reality it's rarely this simple. But if you understand the principle you should be able to apply it to more complex spaces. An important point to remember is that the virtual water will be able to flow through a teleport, so if we had a teleport in the room above which led to a destination in the corridor, cluster 2 would no longer be watertight. A possible solution to this is to encase the teleport in botclip as far as possible and then make a clusterportal 'entrance' the bots will have to go through to get to it. In the above example, this would cause the room, cluster 2, to be 'watertight' again and cluster 1 would consist of the corridor and the small botclip box round the teleport.

Clusterportals will not function if they are crossed by a trigger_push trajectory.

This is a little known fact (it's not in the Radiant manual) which caused me no end of headaches when trying to clusterportal Scorpion. As far as the manual said, I had everything right, but my clusterportals still weren't working. Thanks to Quakin' for setting me right on this one... :)

Clusterportals will not work properly if they can be fallen, rather than walked, through.

In other words, clusterportals will only work horizontally. And, yes, that is rubbish. Strangely, a vertical clusterportal will still split clusters, but it makes the bots even stupider than they usually are, so don't do it!

Clusterportals will not work properly if they have any other brushes intersecting them.

This is even worse than no clusterportal, because it may cause the clusterportal to alternately fail and work in game. Euughhh....

Clusterportals should be axial as far as possible, and made from a single brush.

If you have an arched doorway for example, clip the arch with botclip to make the doorway rectangular, then fill that rectangle with a clusterportal.

Clusterportals should always have identically shaped and sized 'entrances' and 'exits'.

For example, a doorway in a sloped hall should not be approached like this:

But like this:

Clusterportals should always be surrounded on all sides by solid geometry or clip.

Well, except the front and the back of course... All but two sides is more accurate perhaps.

If a door is already sealed with an areaportal brush, a clusterportal is not necessary there.

BSPC uses areaportals as clusterportals. The reverse is not true.

Clusterportals should not contain less than 10 areas.

This is taken from the Radiant manual, but is often very hard to acheive - even the id sample maps have some tiny 'phantom' clusters which do not seem to appear anywhere in the map. It doesn't seem to affect things too badly, but is worth bearing in mind. What you should be looking out for is small areas which can be botclipped off - say a gap above a ceiling beam or something like that....

Clusterportals should be 16 units thick, or 32 if absolutely necessary.

Clusterportals must separate no more and no less than 2 clusters.

Clusterportals should never extend into the void.


6. Clusterportals in space

This is such an awkward problem that I thought it deserved its own special section. In a large space map with lots of jump-pads, placing clusterportals can be nigh-on impossible, as most of the map is cris-crossed with trigger_push trajectories, 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. This is what id did with Q3DM17 - its just one big cluster with 4 little 'phantom' clusters creeping in there too. However, once you start adding any fancy architecture (and let's face it - Q3DM17 looks like a dog, even though it plays like a work of art) you'll have too many areas to get away with this. So, its clusterportal time for you...

The only way (as far as I know) to get clusterportals working properly in space comes courtesy of Raven, who helped me out with this on Scorpion (Thanks and sorry I forgot you in the readme!) Here goes...

1. Split the map into approximately equal sized sections using huge botclip walls, 16 units thick, which go all the way across the skybox and so completely seal the areas they divide. You'll probably only need two or three walls, but remember that you cannot have a trigger_push trajectory going through any of them. Don't worry about teleports for the moment.

2. Use the clipper tool to make rectangular 'windows' in these walls where the bots will need to go through them.

3. Fill the 'windows' with clusterportal brushes.

4. If there are any teleports which have a destination in another cluster, make a botclip box round the teleport and put in a clusterportal 'door' for the bots to use.

5. Cross your fingers and compile the .aas

6. Repeat until it works. :)

Here's the two walls I ended up with in Scorpion - I've selected the botclip and left the clusterportals unselected to make it clearer. (Whoever it was at id who decided to make botclip and clusterportals almost the same colour should be remonstrated with most severely. I hope you're listening Mr. Carmack)

By doing this I managed to reduce the number of areas in each of the two main clusters to about 800 - still too high, but it seemed to fix the bot stutter problem, so I was reasonably happy with it.

Typically enough, I've just figured out a way I could have split it into 3 and reduced the number of areas in each.... oh well, it's too late now, and I wasn't lucky enough to have such a useful bot optimisation tutorial to hand at the time... so now there's no excuse for any of your spacemaps to have clusters with more than 500 areas in, OK? ;)


Well, if you haven't gone to sleep by now, you are probably:

a) on some kind of amphetamine and

b) a bot optimisation expert

So go whip those unruly bots into shape! Good luck!


Thanks to Raven, Quakin' and Snickelfritz for help and advice on this topic!
If you have any corrections or additions to this tutorial, please go right ahead and email them to me at: