User:CS:GO Bot Behavior Trees


Remember to check for any notes left by the tagger at this article's talk page.
In Template:Game name, bots can be given a Behavior Tree to follow. A behavior tree dictates how the bot senses things (vision, hearing, damage sensing), moves, attacks, and does other actions.
They use Valve's proprietary KeyValues3 format (.kv3
), which is a text-based format with somewhat strict syntax. They typically use the bt_
prefix, to signify that file is a Behavior Tree. They are stored in csgo/scripts/ai
. One can create and use his own behavior trees, see below.
Officially, behavior trees are used for the game modes Co-op Strike,
Guardian and
Deathmatch.
Behavior trees were first added to the game on September 16, 2019. Since September 1, 2020, behavior trees can be packed into BSP files.
Using a Behavior Tree
The ConVar mp_bot_ai_bt
can assign a behavior tree to all bots on the server. Its value is a string representing the path to a .kv3 file, starting from csgo/
. For example, the following line is used for official Deathmatch and can be found in csgo/cfg/gamemode_deathmatch.cfg
:
mp_bot_ai_bt "scripts/ai/deathmatch/bt_default.kv3"
For the Co-op game mode, info_enemy_terrorist_spawn entities have the KeyValue behavior_tree_file
that can be used to specify a behavior tree only for bots spawning at this entity.
Related Console Commands
ConVar | Default Value | Description |
---|---|---|
cv_bot_ai_bt_debug_target
|
-1 | Draw the behavior tree of the given bot. |
cv_bot_ai_bt_hiding_spot_show
|
0 | Draw hiding spots. |
cv_bot_ai_bt_moveto_show_next_hiding_spot
|
0 | Draw the hiding spot the bot will check next. |
mp_bot_ai_bt
|
"" | Use the specified behavior tree file to drive the bot behavior. |
mp_bot_ai_bt_clear_cache
|
ConCommand | Clears the cache for behavior tree files. |
Format
The first line of a .kv3
file is always a header specifying the KV3 version. For CS:GO, use this header:
<!-- kv3 encoding:text:version{e21c7f3c-8a33-41c5-9977-a76d3a32aa0d} format:generic:version{7412167c-06e9-4698-aff2-e63eb59037e7} -->
Now define general bot configuration. Use "config" key, which should contain full path to that file, including file extension:
<!-- kv3 encoding:text:version{e21c7f3c-8a33-41c5-9977-a76d3a32aa0d} format:generic:version{7412167c-06e9-4698-aff2-e63eb59037e7} -->
{
config = "scripts/ai/<path to bt_config>/<bt_config_name>.kv3"
}
Behavior trees always start with root. Define it with "root" key. Every behavior node should be inside it.
<!-- kv3 encoding:text:version{e21c7f3c-8a33-41c5-9977-a76d3a32aa0d} format:generic:version{7412167c-06e9-4698-aff2-e63eb59037e7} -->
{
config = "scripts/ai/<path to bt_config>/<bt_config_name>.kv3"
root =
{
<Behavior Node>
}
}
Behavior Node format depends on its type and parameters:
<!-- kv3 encoding:text:version{e21c7f3c-8a33-41c5-9977-a76d3a32aa0d} format:generic:version{7412167c-06e9-4698-aff2-e63eb59037e7} -->
{
config = "scripts/ai/<path to bt_config>/<bt_config_name>.kv3"
root =
{
type = <Node Type>
<parameter> = <value>
...
child =
{
<Behavior Node>
}
}
}
Some nodes allows to define new global variables. Their input name should contain both double and single quotes:
type = "action_set_global_counter"
input_name = "'Test'" // Note those quotation marks.
input_value = 1
Configuration
- Explain parameters in bt_config
These parameters define general bot reaction and combat behavior for every bot skill ( low, fair, normal, tough, hard, very_hard, expert, default ), like a botprofile.db.
Default format is:
<!-- kv3 encoding:text:version{e21c7f3c-8a33-41c5-9977-a76d3a32aa0d} format:generic:version{7412167c-06e9-4698-aff2-e63eb59037e7} -->
{
<skill level>
{
<Variables from table below>
attack = <Attack table>
}
}
List of parameters
Variable | Description |
---|---|
aim_target_acquisition_lerp_time
|
|
aim_target_acquisition_lerp_time_deviation
|
|
aim_target_acquisition_angle_penalty
|
|
aim_target_acquisition_angle_penalty_deviation
|
|
aim_target_acquisition_angle_penalty_reduction_ratio
|
|
aim_target_acquisition_angle_tolerance
|
|
aim_target_acquisition_angle_lerp_bias
|
|
aim_target_tracking_lerp_time
|
|
aim_target_tracking_lerp_time_deviation
|
|
aim_target_tracking_focus_interval
|
|
aim_target_tracking_focus_interval_deviation
|
|
aim_target_tracking_angle_lerp_bias
|
|
aim_new_target_angle_tolerance
|
|
aim_max_duration
|
|
aim_max_duration_deviation
|
|
aim_punch_angle_reaction_chance
|
|
look_around_awareness_yaw_range
|
Max angle to horizontal rotate viewcamera from this viewpoint. |
look_around_awareness_pitch_range
|
Max angle to vertical rotate viewcamera from this viewpoint. |
look_around_focus_interval
|
Delay between next viewcamera rotation. |
look_around_focus_interval_deviation
|
|
look_around_lerp_time
|
Time to rotate viewcamera to next position. |
look_around_lerp_time_deviation
|
|
look_around_lerp_bias
|
Smooths viewcamera movement. |
reaction_time
|
Delay before reaction on event. |
combat_crouch_chance
|
|
combat_dodge_command_duration
|
|
combat_dodge_command_duration_deviation
|
Attack Table
Attack table defines handling of different weapon types.
Example:
attack =
[
// duration, duration deviation, cadence, cooldown, cooldown deviation
// KNIFE PISTOL SUBMACHINEGUN
[ -1.0, -1.0, -1.0, -1.0, -1.0 ],[ 0.95, 0.25, 0.5, 0.15, 0.05 ],[ 0.42, 0.07, 0.0, 0.15, 0.05 ],
// RIFLE SHOTGUN SNIPER_RIFLE
[ 0.22, 0.07, 0.0, 0.45, 0.15 ],[ 0.3, 0.0, 0.0, 0.95, 0.25 ],[ 0.22, 0.07, 0.0, 2.0, 0.0 ],
// MACHINEGUN C4 TASER
[ 0.75, 0.15, 0.0, 0.3, 0.1 ],[ -1.0, -1.0, -1.0, -1.0, -1.0 ], [ -1.0, -1.0, -1.0, -1.0, -1.0 ],
// GRENADE EQUIPMENT STACKABLEITEM
[ -1.0, -1.0, -1.0, -1.0, -1.0 ],[ -1.0, -1.0, -1.0, -1.0, -1.0 ],[ -1.0, -1.0, -1.0, -1.0, -1.0 ],
// FISTS BREACHCHARGE BUMPMINE
[ -1.0, -1.0, -1.0, -1.0, -1.0 ],[ -1.0, -1.0, -1.0, -1.0, -1.0 ],[ -1.0, -1.0, -1.0, -1.0, -1.0 ],
// TABLET MELEE SHIELD
[ -1.0, -1.0, -1.0, -1.0, -1.0 ],[ -1.0, -1.0, -1.0, -1.0, -1.0 ],[ -1.0, -1.0, -1.0, -1.0, -1.0 ],
// WEAPONTYPE_ZONE_REPULSOR UNKNOWN
[ -1.0, -1.0, -1.0, -1.0, -1.0 ],[ -1.0, -1.0, -1.0, -1.0, -1.0 ]
]
Nodes
This is a list of all nodes on November 9, 2021.
- Complete node parameters and descriptions, check for inaccuracies.
- Define variable types for parameters.
- Explain all parameters.
Combinators
Type | Parameters | Description |
---|---|---|
parallel
|
Executes all child functions in one script tick. | |
selector
|
Executes child functions as sequence until meeting child with true condition. | |
sequencer
|
Executes child functions as sequence until meeting child with false condition. | |
subtree
|
string file, string name, array params (goes in "key" "value" format in brackets. e.g. key = "ThrowUtility" value = 1)
|
Executes behavior tree from file. |
Decorators
Type | Parameters | Description |
---|---|---|
decorator_bot_service
|
array memory_to_expire(variable? domain (GroupID or AllBots), flag key (ShortTermAttackMemory, ShortTermDamageMemory, ShortTermAreaDamageMemory, ShortTermInvestigateMemory, LongTermMemory, DamageThroughSmokeMemory, Threats), int time, int distance), array tagged_entities_to_expire, int_flag? basic_chatter_enable, vector? input_chatter_enemies, int chatter_outnumbered_threshold
|
Kinda main bot behavior function? Usually contains all subtree routines. |
decorator_buy_service
|
array output
|
Returns array of items that bot will buy, then executes function. |
decorator_dec_global_counter
|
variable input_name
|
Decreases input variable by 1, then executes function? |
decorator_find_utility_strat
|
vector input_location, int distance_threshold, vector output_location, vector output_angles, string output_weapon
|
Unused. |
decorator_game_event
|
![]() | |
decorator_hiding_spot_service
|
variable? domain (GroupID or AllBots), vector output_hiding_spot, int distance_threshold, int expiration_time
|
Keeps track of visible hiding spots. Used in conjunction with "action_move_to" to make a bot check hiding spots as he moves throughout the level. ![]() |
decorator_invert
|
Unused. Valve scripts usually use negated = 1 flag in node parameters.
| |
decorator_maybe
|
float chance
|
Executes child functions with specified chance (1 - 100%, 0.7 - 70% etc). |
decorator_memory
|
vector? input, memory? output, string output_domain
|
Saves input in specified memory buffer? |
decorator_need_healing
|
int health_threshold
|
Executes child functions if bot health is lower that input threshold. |
decorator_picker_blocked_by_smoke
|
vector? input, int distance_threshold
|
Removes entities from the "input" array that are not covered by smokes. |
decorator_picker_dedup
|
vector? input, memory? against, int distance_threshold
|
Removes entities from the "input" array that are within "distance_threshold" to entities in "against" array. |
decorator_picker_grenade_type
|
array input, array types (EXPLOSIVE, FLASH, FIRE, DECOY, SMOKE, SENSOR, SNOWBALL)
|
Removes entities from the "input" array that are not in "types" array. |
decorator_picker_max_score
|
array input
|
??? |
decorator_picker_nearby
|
array input, int cutoff_distance
|
Removes entities from the "input" array beyond "cutoff_distance". |
decorator_picker_random_by_distance
|
array input, int distance_min, int distance_max
|
Removes entities from the "input" array based on the distance distribution between "distance_min" and "distance_max". |
decorator_picker_reaction_time
|
variable? input_domain (GroupID or AllBots), memory? input, vector? output
|
Executes child functions after delay, that depends of bot skill reaction time? |
decorator_picker_visible
|
array input, int_flag? check_fov
|
Removes obscured entities from "input" array. |
decorator_picker_weight_as_distance
|
array input
|
Removes the entities whose distance to the bot running the tree is greater than the entities "weight". "weight" is an internal notion mostly used for hearing sounds. It's not very well designed yet for general purpose use and should only be used when sensing "NOISE". |
decorator_random_approach_point
|
vector output
|
Returns a random point in navmesh that the bot can see, ideally a point where enemies can come from. ![]() |
decorator_random_int
|
int min, int max, int output
|
Returns a random int the range of min to max. |
decorator_ranker_dist
|
array input
|
Sorts entities depending on distance? |
decorator_remove
|
variable? input_domain (GroupID or AllBots), memory? input, array? remove
|
Removes selected entities from input memory. |
decorator_remove_key
|
variable? input
|
Removes input variable from script scope. |
decorator_repeat
|
Executes child functions in loop. | |
decorator_route_service
|
array config (array routes, array strategies), vector? output_waypoint, string output_waypoint_name, string output_domain
|
Unused. |
decorator_run_once
|
int max_attempts = 1, variable? domain (e.g. domain = "'CoordinatedBuy'")
|
Executes child functions limited amount of times? "domain" can be set to make only one bot run it globally. |
decorator_sensor
|
flag entity_type_filter (ALL, PLAYERS, HUMAN_PLAYERS, NOISE, DAMAGE, AREA_DAMAGE, CLASSNAME, GRENADE), function? shape(flag type (sensor_shape_fov, sensor_shape_sphere), int radius), flag team_filter (ANY, CT, TERRORIST, SAME, OPPOSITE, ENEMY), int_flag orphan_only, int_flag priority, string class_name, vector? output
|
Returns entity detected by sensor and executes child functions. ![]() |
decorator_set_barrier
|
Unused. | |
decorator_set_reaction_time
|
array? input
|
Executes child functions on input after delay, that depends of bot skill reaction time? |
decorator_succeed
|
Node succeeds even if child functions failed. | |
decorator_tag_entity
|
array input, array output, flag operation_type (BT_DECORATOR_TAG_ENTITY_CLEAR, BT_DECORATOR_TAG_ENTITY_SET), int expiration_time
|
Adds or removes the first entity in "input" array to "output" array for specified amount of seconds. |
decorator_tag_threshold
|
array entity_input, array tagged_entities_input, int amount, flag check_type (BT_DECORATOR_TAG_THRESHOLD_AT_MOST, BT_DECORATOR_TAG_THRESHOLD_AT_LEAST)
|
Compares entities in "entity_input" against entities in "tagged_entities_input" using "check_type". If it passes, executes the child functions. (e.g. If at least 2 entities from "entity_input" are in "tagged_entities_input" execute child function) |
decorator_token_service
|
variable? domain, string output_token_name, string output_token_domain, function config(array tokens, array assignments)
|
In Guardian Mode: defines bot GroupID, then executes child functions. |
decorator_try_lock
|
variable? domain (e.g. domain = "'DefuseIfCovered'")
|
Locks the domain for the duration of executing the child function, meaning only one bot at a time will be executing this. |
decorator_wait_success
|
int timeout
|
Executres child functions for the specified amount of time. Fails if the child function doesn't end before the timeout. |
Conditions
Type | Parameters | Description |
---|---|---|
condition_barrier
|
Unused. | |
condition_distance_less
|
vector input, int distance_threshold_min, int distance_threshold_max
|
Returns true, if distance to input position is less than distance_threshold? |
condition_has_parachute
|
Returns true, if bot has parachute in inventory. | |
condition_inactive
|
array input(memory? key), int round_start_threshold_seconds, int sensor_inactivity_threshold_seconds
|
Returns true, if bot doesn't have any memory and sensor input within timing. |
condition_is_airborne
|
Returns true, if bot is mid-air. | |
condition_is_at_bomb_site
|
Returns true, if bot is at bombsite zone. | |
condition_is_empty
|
int_flag? global, any input
|
Returns true, if input variable is empty or doesn't exist. |
condition_is_equal
|
any source, any destination
|
Returns true, if source variable is equal to "destination" input. |
condition_is_greater
|
any source, any destination
|
Unused. Returns true, if source variable is greater than "destination" input. |
condition_is_greater_equal
|
any source, any destination
|
Unused. Returns true, if source variable is equal or greater than "destination" input. |
condition_is_inv_slot_empty
|
flag slot (KNIFE, PISTOL, RIFLE, GRENADES)
|
Returns true, if input equipment slot is empty. |
condition_is_less
|
any source, any destination
|
Unused. Returns true, if source variable is less than "destination" input. |
condition_is_less_equal
|
any source, any destination
|
Unused. Returns true, if source variable is equal or less than "destination" input. |
condition_is_reloading
|
Unused. Returns true, if active weapon is in reloading state. | |
condition_is_weapon_equipped
|
string weapon
|
Returns true, if bot has active weapon with input classname. |
condition_is_weapon_suitable
|
string weapon
|
Unused. |
condition_out_of_ammo
|
Returns true, if active weapon is out of ammo. | |
condition_owns_item
|
string weapon
|
Returns true, if bot has item with input classname. |
Actions
Type | Parameters | Description |
---|---|---|
action_acquire_items
|
array items, int_flag? remove_all_items
|
Equips bot with items from array. |
action_aim
|
vector input, int_flag? acquire_only, flag? ready
|
Rotates bot towards input point. Uses aim penalties set in the bot config. Can overshoot the target. Sets "ready" flag when aiming at the input target. |
action_aim_projectile
|
vector input, vector output
|
Calculates angles for throwing at input position? |
action_assign_guardian_loadout
|
string input_token_name, array assignments(string token, array loadout(array items, array wave_numbers, int wave_numbers_min, int wave_numbers_max, int weight))
|
In Guardian mode: Chooses bot spawn loadout. |
action_attack
|
vector input, flag? output (e.g. output = "Attacking"), flag? ready (e.g. ready = "AimReady")
|
Forces bot to fire when "ready" flag is set. ![]() |
action_buy
|
Bot buys weapons. | |
action_choose_bomb_site_area
|
int input, navzone? output
|
Gets bombzone nav position from index. Supports convars. |
action_choose_guardian_bomb_plant_location
|
vector? output
|
Chooses plant position in navmesh? Guardian mode only? |
action_choose_random_waypoint
|
navzone? input, vector output
|
Chooses a random tile from the input navzones and returns its center as a vector position. |
action_choose_random_waypoint_within_radius
|
vector origin, vector output, float radius
|
Chooses a random navmesh tile within specified origin and radius and returns a random point within it as a vector position. |
action_choose_team_spawn_area
|
navzone? output
|
Gets all navzones with spawnpoints? |
action_combat_positioning
|
vector input, flag? is_attacking
|
When "is_attacking" is set bot side steps to dodge enemy attacks. When "is_attacking" is not set bot tries to close distance on input entity. ![]() |
action_commit_suicide
|
Kills bot. | |
action_compare_global_counter
|
variable? input_name (e.g. input_name = "'Test'"), int input_value
|
Compares value from variable "input_name" to input value. |
action_coordinated_buy
|
flag team_filter (ANY, CT, TERRORIST, SAME, OPPOSITE, ENEMY), int save_threshold, flag? id_no_purchase (e.g. id_no_purchase = "DidNotPurchase"), array purchases(array items, string id)
|
If there's enough bots to fulfill purchases in "purchases" array and all of them are above "save_threshold", assign the "id"s to bots and buy their respective items from "purchases" array. Bots that do not make a purchase are assigned with "id_no_purchase". ![]() ![]() |
action_crouch
|
Forces bot to crouch. | |
action_custom_buy
|
array item_aliases
|
Unused. |
action_drop_active_weapon
|
Unused. Forces bot to drop active weapon. | |
action_equip_item
|
string item, array items_one_of
|
Forces bot to select item with classname from input. |
action_equip_weapon
|
string weapon (classname or BEST)
|
Force bot to select item with classname from input or "best" weapon in inventory. |
action_flee_area_damage
|
vector? input, vector output, int max_search_range, int threat_min_keep_distance
|
Returns safe spot from that position within search radius. |
action_hide
|
float max_range, vector output
|
Unused. Returns a random hiding spot within search radius. ![]() |
action_inspect_current_weapon
|
Unused. Forces bot to play inspect animation. | |
action_jump
|
Forces bot to jump. | |
action_look_at
|
vector input_angles, vector input_location
|
Rotates bot at a specified angle or location. Ignores aim penalties set in the config file. Always aims precisely at the target. |
action_move_to
|
vector destination, flag movement_type (BT_ACTION_MOVETO_RUN, BT_ACTION_MOVETO_WALK), flag route_type (BT_ACTION_MOVETO_FASTEST_ROUTE,BT_ACTION_MOVETO_SAFEST_ROUTE), vector? hiding_spot, vector? threat, int damaging_areas_penalty_cost, int nearest_area_distance_threshold, int hiding_spot_check_distance_threshold, int arrival_epsilon, float additional_arrival_epsilon_2d, int_flag? auto_look_adjust
|
Forces bot to move at destination point. ![]() |
action_parachute_positioning
|
Forces bot to move diagonally ignoring the navmesh. Changes direction every few seconds. | |
action_pull_trigger
|
int ratio
|
Forces bot primary attack. |
action_reload
|
Forces bot to reload weapon. | |
action_say
|
string phrase, flag? high_priority
|
Forces bot to say radio command phrase. List of phrases is located in botchatter.db
|
action_secondary_attack
|
Unused. Forces bot secondary attack. | |
action_select_areas_within_radius
|
vector input, float radius, navzone? output
|
Returns navzones within specified origin and radius? |
action_set_global_counter
|
variable? input_name, int input_value
|
Sets input value to variable "input_name". |
action_set_global_flag
|
variable? name, int expiration_time_min, int expiration_time_max
|
Sets global variable "name" to 1 for specified time? |
action_set_value_float
|
variable? key, float value
|
Sets float value to variable "key". |
action_set_value_vector
|
variable? key, vector value
|
Sets vector value to variable "key". |
action_standup
|
Unused. Forces bot to uncrouch. | |
action_teleport
|
vector destination
|
Teleports bot to destination position. |
action_use
|
Forces bot "+use" | |
action_wait
|
int wait_time_min, int wait_time_max
|
Freezes bot AI and script execution for defined amount of time. |
Reserved Variables
Those variables are defined in game code. They can be used to get some information about game mode and bot and as conditions.
Variable | Description |
---|---|
int NumberOfTerrorists
|
Number of players in T team. |
int NumberOfAliveTerrorists
|
Number of alive players in T team. |
int NumberOfCounterTerrorists
|
Number of players in CT team. |
int NumberOfAliveCounterTerrorists
|
Number of alive players in CT team. |
int GuardianWaveNumber
|
Wave number in Guardian Mode. |
int AccountBalance
|
Amount of player money. |
float? BlindnessPercentage
|
Amount of blindness applied by flash grenade. |
??? BombIsBeingDefused
|
Returns ??? when bomb is being defused. |
variable? LastCoopSpawnPointName
|
Targetname of last spawn point spawned that bot in Co-op Strike. |
Vector LastCoopSpawnPointLocation
|
Origin point of last spawn point spawned that bot in Co-op Strike. |
int AmmoCount/weapon_name
|
Remained amount of ammo in weapon with classname "weapon_name" (clip + reserve). |
int AmmoCount/current
|
Remained amount of ammo in active weapon (clip + reserve). |
Examples
Default Deathmatch Behavior Tree
Found in csgo/scripts/ai/bt_default.kv3
.
<!-- kv3 encoding:text:version{e21c7f3c-8a33-41c5-9977-a76d3a32aa0d} format:generic:version{7412167c-06e9-4698-aff2-e63eb59037e7} -->
{
config = "scripts/ai/deathmatch/bt_config.kv3"
root =
{
type = "decorator_bot_service"
memory_to_expire =
[
{
key = "ShortTermAttackMemory"
time = 0.7
distance = 0
},
{
key = "LongTermMemory"
time = 10
distance = 500
},
{
key = "ShortTermInvestigateMemory"
time = 3
distance = 200
}
]
child =
{
type = "decorator_buy_service"
output = "ShouldBuy"
child =
{
type = "parallel"
children =
[
{
type = "decorator_repeat"
child =
{
type = "parallel"
children =
[
// memorize enemies through vision
{
type = "subtree"
file = "scripts/ai/modules/bt_memorize_enemies_vision.kv3"
name = "MemorizeEnemiesVision"
},
// memorize noises happening right now
{
type = "subtree"
file = "scripts/ai/modules/bt_memorize_noises.kv3"
name = "MemorizeNoises"
},
// record the nearest memorized event to investigate
{
type = "subtree"
file = "scripts/ai/modules/bt_memorize_nearest_investigation.kv3"
name = "MemorizeNearestInvestigation"
}
]
}
},
{
type = "decorator_repeat"
child =
{
type = "selector"
children =
[
// Buy if we have to
{
type = "condition_is_empty"
input = "ShouldBuy"
negated = 1
child =
{
// sequencer: evaluate first to last child, in order
type = "sequencer"
children =
[
{
type = "action_wait"
wait_time_min = 3
wait_time_max = 3
},
{
type = "action_buy"
},
{
type = "decorator_remove_key"
input = "ShouldBuy"
}
]
}
},
// Else: face the damage source if we're taking damage
{
type = "decorator_sensor"
entity_type_filter = "DAMAGE"
output = "Damage"
priority = 0
child =
{
type = "condition_is_empty"
input = "Damage"
negated = 1
child =
{
type = "action_aim"
input = "Damage"
acquire_only = 1
}
}
},
// Else: attack if we see an enemy
{
type = "subtree"
file = "scripts/ai/modules/bt_attack.kv3"
name = "Attack"
},
{
type = "subtree"
file = "scripts/ai/modules/bt_heal_if_needed.kv3"
name = "HealIfNeeded"
},
// Else: investigate the closest memorized event
{
type = "subtree"
file = "scripts/ai/modules/bt_investigate_closest_memorized_event.kv3"
name = "InvestigateClosestMemorizedEvent"
},
// Else: hunt
{
// sequencer: evaluate first to last child, in order
type = "sequencer"
children =
[
{
type = "action_equip_weapon"
weapon = "BEST"
},
{
type = "decorator_random_int"
min = 0
max = 1
output = "BombSiteIndex"
child =
{
type = "action_choose_bomb_site_area"
input = "BombSiteIndex"
output = "HuntAreas"
}
},
{
type = "action_choose_team_spawn_area"
output = "HuntAreas"
},
{
type = "action_choose_random_waypoint"
input = "HuntAreas"
output = "TargetHuntArea"
},
{
type = "action_move_to"
destination = "TargetHuntArea"
movement_type = "BT_ACTION_MOVETO_RUN"
route_type = "BT_ACTION_MOVETO_FASTEST_ROUTE"
}
]
}
]
}
}
]
}
}
}
}