This document is intended to introduce mappers to ThieveryUT's AI. By the end of this guide, you will be able to place AI characters into your levels and get them to carry out tasks.
This tutorial assumes that you can already make an Unreal level. You'l also need a fully-pathnoded map to play with. For help on pathnoding your levels, read Epic's "Unreal Tournament AI and Gameplay for Level Designers" document, found here somewhere.
Browse the Actor hierarchy for this class:
Actor>Pawn>TBaseBot>TBot>TSoldier>TGuard>TKnight.
Select the class, and then go back to your level's 3D view. Right clikc where you want the bot to be and select "Add TKnight here". The bot will be placed where you right-clicked. If the bot doesn't appear, make sure that the place you clicked as enough room for the bot to be spawned.
Give the Bum a Job (making bots patrol)
We'll make this bot Patrol, so open up the bot's properties (right-click, select "Properties..." and open up the TBot menu in the properties dialog. Scroll down to Orders, and type in 'Patrol'. The bot will now patrol, but he needs a TPatrolPoint to patrol to. Patrol points need to be named (using their Tag property), so into the bot's OrdersTag field, enter the name of the patrol point you would like the bot to patrol to. For this guide, we'll use TPP1_1 - the notation I used here defines patrol point 1 in patrol route 1. In the real world, you'd make it easier for yourself by giving the patrol points better names, e.g. FrontYard1, FrontYard2, ousePerimiter1, etc.
So now the bot has been told to patrol to the patrol point with the Tag 'TPP1_1', so we'll have to add this patrol point in somewhere. In the Actor Class Browser, find this class:
Actor>NavigationPoint>TPatrolPoint
Add one of these actors into your level where you want the first patrol point to be. Bring up the properties of the new patrol point, and set the patrol point's Tag to 'TPP1_1'. While your at it, set it's Event to 'TPP1_2' - the Event property defines the next point in the patrol route. Open up the TPatrolPoint menu. Seeing as this is the first point in a route, set the PatrolRouteName to "My First Patrol Route" (or something equally stupid). This is what the patrol route will be called when you frob a bot in-game and tell him to patrol - you will be presentd with a menu of all named patrol routes in the level. Note that you only need to do this once pre patrol route (that is, you should only name a patrol route once).
When the bot reaches this patrol point, let's make him look at something. In the LookAtTag, enter 'LookAtMe'; in PatrolAction, select 'ETPA_Wait'; and in ActionTime, enter 2. This will make the bot stop and look at towards the actor with Tag 'TheTree' for 2 seconds. Now that we've told the bot to look at something, we need to actually give him something to look at. Add in a decoration actor (e.g. a book or bush or something) and set it's Tag to 'LookAtMe'.
That's the first point done with. Once the bot has finished doing the action, he will move on to the next point, so we'd better put it in. Stop and have a think about where you want your bot to walk when he patrols your level, and plan out a route.
Add in the second patrol point, and set it's Tag property to 'TPP1_2'. Set it's PatrolAction to ETPA_Nothing, which will make the bot immediately carry on to the next point when he reaches this point. Speaking of the next point, add that in too, and the one after that, and as many as you want (though not too many - baby steps for beginners). When you have placed your last point, set it's Event property to the Tag of the first patrol point we placed, namely 'TPP1_1'. This will make the bot walk this route in a loop.
These are the different settings for PatrolAction - what a bot does when he reaches this point (usually for ActionTime seconds):
bDirectional (under Advanced) lets you set the patrol point's rotation in UnrealEd. If a bot reaches a patrol point that is bDirectional, he will look in the same direction that the point 'faces' when he reaches that point. Note that this is overridden by LookAtTag.
Whenever a bot reaches a patrol point, the point's ArriveEvent will be triggered (with the bot as the trigger instigator), but only for a maximum of TriggerCount times.
BotAnimation makes a bot play an animation when he reaches the patrol point, and must be used in conjunction with PatrolAction, i.e. set PatrolAction to ETPA_Animate. Set BotAnimation to the name of the animation you want the bot to play.
BotSpeed makes bots travel to this patrol point at the desired speed. By default, it is ETPPS_NoChange, which doesn't alter the bot's speed.
LookAroundFovDegrees defines the arc that the bot will 'look around' when PatrolAction is set to ETPA_LookAround. Specifically, the bot will turn LookAroundFovDegrees/2 degrees to the left, look around, then turn LookAroundFovDegrees to the right and look around. The 'origin', i.e. the original angle the bot bases these turnings on depends on the patrol point's Rotation / LookAtTag.
NewOrders and NewOrdersTag let you change a bot's orders when they reach this point, if PatrolAction is set to ETPA_NewOrders. They work in exactly the same manner as the bot's own Orders and OrdersTag properties. This basically tells the bot to 'do something else' when he reaches this patrol point.
PatrolRouteName lets you give names to your patrol routes. These names show up in the menu when you tell a friendly bot to Patrol. Only name one point in each route - you are naming the route, not each individual point.
By default, the bots come with a loadout pre-defined in their code. This loadout is the 'standard' bot loadout for Thievery. If you look at the bot's DefaultLoadoutClass property, you will see that it is set to Class'ThieveryAI.TBotLoadoutInfo'. This means that this bot automatically gets this class' loadout when he starts the game. If you browse the Actor Class Browser for...
Actor>Info>TInfo>TBotLoadoutInfo
...you will be able to select a different default loadout (you can even make one of your own, though that is beyond the scope of this quick guide). You can also set the property to nothing, which means the bot doesn't have a default loadout.
Another way to give bots a loadout at the start of a level, which is much easier, is by placing a TBotLoadoutInfo actor into the level somewhere (anywhere, it doesn't atter - the actor is invisible in-game). You can edit this actor's properties (under the TBotLoadoutInfo menu in the properties dialog), adding up to 64 loadout items. Expand the BotLoadout submenu, and expand the first submenu under that.
Click the InvClass property's "..." button, and browse to an Inventory item that you want to give to the bot. You can give the bot non-Thievery items, but it's best to only give them Thievery items, i.e. items under:
Inventory>Pickup>ThieveryPickup
and
Inventory>Weapon>TournamentWeapon>ThieveryWeapon
Select the item you want and go back to the loadout actor's properties. In the Quantity field, enter the number of these items you want to give to the bot. The actual number given to the bot will depend on the Type setting - select ETIIT_Absolute to give the bot exactly Quantity numer of the item, or ETIIT_ScaleQuantityBySkill to scale the Quantity by the bot's BotSkill property, and give the bot the number ofitems in the result. Give the Loadout actor a unique Tag, something like 'MyLoadout'.
Now that you have defined a new loadout, give it to some bots. Find a bot and bring up his properties. Under the TBot menu, enter 'MyLoadout' into the LoadoutActorTag field.
When the bot enters the level, he will be given loadouts from two sources - the class defined by his DefaultLoadoutClass property (which you can clear so the bot doesn't have a default loadout); and the in-level TBotLoadout actor identified by the bot's LoadoutActorTag property (which can also be nothing).
Here's a useful bunch of properties, and what they do.
TBaseBot->fInhabitPriority
This is used to determine the order in which bots are inhabited by human players. A higher priority means the bot isl be likely inhabited before other bots with lower priorities.
TBaseBot->bPlayerCanInhabit
Whether or not this bot can be inhabited by human players.
TBaseBot->bTakesOrders
Whether or not this bot takes orders from friendly players.
TBot_Debug->bVerbose
Set this to true and the bot will spit out lots of spam to the message window and log. Useful for debugging your maps.
TBot_Advanced->fSightRadius
How far the bot can see, in Unreal Units. To aquire an enemy, it must be within approximately 75% of this distance.
TBot->BotTorchLightClass
Set this to a valid Class (under Light->TBotTorchLight), and the bot will have a light that shines where he is looking. Defaults to None, i.e. no torch.
TBot_Advanced->fHearingRadius
How far a bot hears. Note that even though a bot might hear a far way, the further away the sound's source is, the less he will hear it. Bot's ignore sounds that are heard at low volumes, e.g. sounds towards the extents of their hearing radius.
TBot->MaxHealth
The bot's maximum health.
TBot->DamageScale
Bots use varius factors to determine how much damage they take, and this factor is applied to the damage amount last. So for a tougher than normal bot, set this to a value less than 1.0, e.g. set it to 0.5 and the bot will take half as much damage as normal.
TBot_Voice->VoicePackage and VoiceSet
Determines a bot's voice - if this is left blank, the bot will choose a random voice (TSoldiers only). See the documentation on bot voice sets for information abotu voice sets.
TBot_Triggers
There are a certain Triggers sent out when a bot receives various events. these events are listed below:
TBot->Orders and OrdersTag
See the information on orders, above.
TBot->bDelayedStart
At level start, bot will stand in position until seen by a PlayerPawn, and then do it's orders.
TBot->HelmetProbability
The bot's probability of getting a helmet when a bot enters the level. 0.0 = no helmet, 1.0 = always get a helmet. Set to -1.0 to use the bot's BotSkill as the probability (i.e. higher skilled bots will have a greater chance of getting a helmet).
TBot->BotSkill
The bot's skill, from 0.0 (crap) to 1.0 (better, but still crap). Determines lots of stuff, such as how fast the bot moves, how long it takes him to respond to suspicious events, how well he aims when attacking, etc.
TBot->BotName
You can name your bots by typing the name into this field. Leave at blank to have a name randonly chosen.
TBot->bStickWithEnemy
If true, a bot will stick with one enemy, instead of breaking off one attack to engane another hostile.
TBot->bActivateAlarmBeforeEngaging
Set this to true and the bot will activate the alarm, then come back and beat you up. False, and he'll beat you up until he deems the fight over (he kills you or you pummel him so hard that he tries to flee), and then he'll run to raise the alarm.
TBot->bFlees and fFleeFactor
bFlees determines whether or not the bot flees when he gets damaged. He will flee when his Health gets lower than his MaxHealth*fFleeFactor, e.g. the default fFleeFactor of 0.25 means the bot flees if his health gets below 35% of full.
TBot_Combat->bAttacksMelee and bAttacksRanged
Whether or not the bot engages in the two forms of combat. There's also lots of other properties under the TBot_Combat that determine the bot's combat capabilities.
TBot->bNoInvestigate
If true the bot will not wander off to investigate suspicious events.
TBot->AlarmTag
Set this to the Tag of the TAlarmSystem that you want this bot to activate when he sees an enemy. The bot will run to the nearest button and raise the alarm.
TBot->bHeedsAlarm
Whether or not this bot will respond to raised alarms.
For descriptions of the rest of the properties, right-click TBot in the actor class browser and select 'Edit Script'. Do a search for the name of the property you want until you find the place where it is defined in the code - it will look something like:
var() name Orders; // Orders a bot is carrying out
The part after the double slash is a description of the property.
Listed below are the different types of orders you can give to bots. Normally you'd set a bot's Orders and OrdersTag properties in UnrealEd, but you can also change a bot's orders using TPatrolPoints and TOrdersChangers.
The bot will patrol the route defined by OrdersTag. Set OrdersTag to the Tag of one of the patrol points in the route you want the bot to patrol.
The bot will move to the actor identified by the OrdersTag property. Similar to using a finite (i.e. non-looping) patol route, but with less features.
The bot will wander on the spot. Handy for creatures, such as rats and spiders. When wandering, a bot does not use the path network, therefore it is severely liited in it's navigation abilities, and will stay in the same part of the level.
Roam is similar to Wander, but the bot uses the path network to navigate the level. The bot picks a random destination somewhere in the level and heads for it. When the bot reaches it's goal, it picks another random destination in the level and heads for that, and so forth.
The bot will stand on the spot. If the bot is moved from this spot (i.e. runs off to chase an enemy or is bumped by a friendly player), the bot will not return to his original spot. If you need the bot to return to his 'guard' location, either tell him to Patrol on a route with only one point (he will move to and stay at that point), or give him GuardHere orders.
The bot will move to and guard the actor defined by OrdersTag. If the other actor is a player, the bot will protect it, getting suspicious if the 'Guard Object' gets damaged. Multiple bots told to guard the same player will also stand and walk in formation. The formation they choose is defined by the 'Lead' guarding bot's Formation property, and can be set to any Object>TBotFormation subclass. The 'Lead' bot is always the 'oldest' bot - Unreal gives it's actors ordered names like TKnight0, TKnight1, etc, depending on the order they were added into the level. Therefore, the oldest bot will be the bot with the lowest number.
The bot will follow the actor identified by OrdersTag around. Very similar to the Guard orders, but the bot doesn't 'protect' it's object.
Similar to Stand orders, but the bot will return to it's original location if it moves for some reason. The bot will ignore suspicous things that aren't in it's immediate vicinity, and will not chase enemies too far.
The bot will sleep at his location, changing his orders to 'Stand' if he is woken up.
The bot will investigate his present location, or if an OrderObject is supplied, he wil investigate that object's location.
Not really 'orders', but anybot told to do this will become totally unalert and resume his present orders. Used to calm bots down.
Bots with Defense orders will perform acts that help defend their objective, i.e. place mines, repair broken whistlers, etc. You need to define areas to place items in your maps, using TSuggestedItemLocation actors, if you want bots to place items.
Bots will write warnings to the log file if they can't reach their goal destination from their current location. This usually means your path network needs tweaking, so note down where the bot is, and where he wants to get to, and try to manually 'walk' this path in UnrealEd. Look for pathnodes that are close to walls, or too high off the ground. If you open up a viewport's menu (by right-clicking in it's top border) and select "View>Show Paths", you will be able to visually inspect the links between path nodes. Blue lines is good, red lines is bad.
Note: bots will not write bad path warnings to the log if you don't have this line in System/ThieveryAI.ini, under the "[ThieveryAI.TVoiceSet]" section:
bWriteBadPathWarnings = True
If you start a map using the Thievery AI Debug gamrtype, you will be able to view extended information on the bots. Once in the game, use the console command 'hudon' to activate a debug HUD that will show some information about you, as well as extended information on the last bot you looked directly at. Use 'hudoff' to turn off this info, or 'togglehud' to toggle it between on and off.
The current bot that is 'active', ie. the last bot you looked at (and who's information you are viewing) will output information on his actions to the message window, console and log. This can be used to see what the bot is thinking. You can turn this off by typing 'verbose' in the console. Use the same command, or just look at another bot, to turn it back on.
You can also use the console command 'cheatview tbot' to follow a bot in chasecam mode. Doing this also sets the viewed bot as the 'active' bot.
When moving from one point to the next, a bot will always use the shortest path. If you find your bot taking an unintended path from one point to the next, add an intermediary path in between the original two, somewhere on the path you want the bot to take.
The pathfinding doesn't work through areas with overhanging ledges, such as at the bottom of a ramped tunnel. Give the bot a bit of extra overhead clearance when designing your level. Give the bots a bit of clearance to the sides, too. The pathfinding can be very finicky at times.
If a bot is given bad orders (misspelt or an invalid OrderObject), he set his orders to Roam. If one of your bots seems to wander off and do his own thing, check that his orders are still what you set them to, andcheck the log for warnings. Generally, if a bot isn't doing what you want him to do, check the log for warnings.
Thievery bots use Thievery's TPatrolPoints, not Unreal's PatrolPoints. Many tears of frustration have been shed due to this simple fact.
Bots can't swim. If they fall in water, they will eventually drown. Try to position your pathnodes so they stay as far away from water as you can get them, without sacrificing the path's usefulness.