Created
January 14, 2021 05:06
-
-
Save sigsegv-mvm/020363706ec8673a88972d5c5572840a to your computer and use it in GitHub Desktop.
A dense and probably horrendously difficult-to-understand description of how the bot_generator and bot_action_point entities work
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
CTFBotGenerator / bot_generator | |
================================================================================ | |
bool m_bSuppressFire = false ; kv "suppressFire" | |
bool m_bDisableDodge = false ; kv "disableDodge" | |
bool m_bUseTeamSpawnpoint = false ; kv "useTeamSpawnPoint" | |
bool m_bRetainBuildings = false ; kv "retainBuildings" | |
int m_iOnDeathAction = 1 ; kv "actionOnDeath" | |
int m_spawnCount = 0 ; kv "count" | |
int m_maxActiveCount = 0 ; kv "maxActive" | |
float m_spawnInterval = 0.0f ; kv "interval" | |
char* m_className = "" ; kv "class" | |
char* m_teamName = "" ; kv "team" | |
char* m_actionPointName = "" ; kv "action_point" | |
char* m_initialCommand = "" ; kv "initial_command" | |
int m_difficulty = -1 ; kv "difficulty" | |
bool m_bSpawnOnlyWhenTriggered = false ; kv "spawnOnlyWhenTriggered" | |
================================================================================ | |
InputEnable(void) ; kv "Enable" | |
InputDisable(void) ; kv "Disable" | |
InputSetSuppressFire(bool) ; kv "SetSuppressFire" | |
InputSetDisableDodge(bool) ; kv "SetDisableDodge" | |
InputSetDifficulty(int) ; kv "SetDifficulty" | |
InputCommandGotoActionPoint(char*) ; kv "CommandGotoActionPoint" | |
InputSetAttentionFocus(char*) ; kv "SetAttentionFocus" | |
InputClearAttentionFocus(char*) ; kv "ClearAttentionFocus" | |
InputSpawnBot(void) ; kv "SpawnBot" | |
InputRemoveBots(void) ; kv "RemoveBots" | |
================================================================================ | |
COutputEvent m_onSpawned ; kv "OnSpawned" | |
COutputEvent m_onExpended ; kv "OnExpended" | |
COutputEvent m_onBotKilled ; kv "OnBotKilled" | |
================================================================================ | |
CTFBotGenerator::Activate | |
- checks and caches whether class name is "auto" | |
- finds action_point named entity and saves a handle to it if found | |
CTFBotGenerator::GeneratorThink | |
- if game is in waiting-for-players mode or in any roundstate besides GR_STATE_PREROUND or GR_STATE_RND_RUNNING, delays for a bit | |
- otherwise: if !m_bSpawnOnlyWhenTriggered, calls SpawnBot | |
CTFBotGenerator::SpawnBot | |
- removes any invalid bot handles or valid handles to bots on spectator team | |
- if the number of bot handles in the vector is >= m_maxActiveCount, reschedules the think and returns | |
- attempts to get an available bot from the "pool" | |
- note that the separate tf_bot_quota logic also grabs bots from the "pool" (though with a lot of extra quota enforcement stuff) | |
- the "pool" is defined as all true TFBot players currently on the server who are on TEAM_UNASSIGNED or TEAM_SPECTATOR | |
- if there is at least one bot meeting those requirements, it has TFBot attribute QuoteManaged removed and is picked | |
- if no bots are available from the "pool", then an attempt will be made to create a new TFBot | |
- this could fail for reasons of e.g. maxplayers | |
- if a bot cannot be created, the SpawnBot function simply gives up and returns | |
- the bot, picked from the pool or newly created, has its handle added to the vector of bot handles | |
- if the generator is set not to use the team spawn point, the bot's spawn point will be set to the generator entity itself | |
- if the generator has suppress fire set, the bot will have TFBot attribute SuppressFire added to it | |
- if the generator has retain buildings set, the bot will have TFBot attribute RetainBuildings added to it | |
- if the generator has disable dodge set, the bot will have TFBot attribute DisableDodge added to it | |
- the bot's skill level will be set based on the generator's difficulty value | |
- 0 thru 3 correspond to the 4 difficulty levels | |
- negative 1 means the bot's skill level won't be messed with (so presumably it'll default to tf_bot_difficulty) | |
- TODO: m_nIgnoreMask / m_spawnflags stuff | |
- the bot's attributes will be modified based on the generator's on-death action setting: | |
- if 1: TFBot attribute RemoveOnDeath is added to the bot | |
- if 2: TFBot attribute BecomeSpectatorOnDeath is added to the bot | |
- else: neither attribute is added to the bot | |
- the bot's m_hMovementGoal is set to the generator's action point entity | |
- the bot is assigned to a team based on the generator's team setting | |
- normal team names are recognized: "unassigned", "spectator", "red", "blue" | |
- the string "spectate" is specially recognized | |
- the string "auto" is also specially recognized and will choose a team based on the game's usual auto-team-selection logic | |
- if the team name provided doesn't match anything recognized, it falls back to the equivalent of "auto" | |
- the bot is assigned a class based on the generator's class setting | |
- the string "auto" is specially recognized and uses the same semi-smart bot auto-class-selection logic seen elsewhere | |
- otherwise, the string given is passed directly into CTFPlayer::HandleCommand_JoinClass... so if it's invalid, dunno what happens | |
- if the bot is not alive, it is force-respawned | |
- the bot's aim angles are snapped to be equivalent to the orientation angle of the generator entity | |
- if the generator has an initial command string specified, it is passed along to CTFBotTacticalMonitor::OnCommandString | |
- the generator's OnSpawned output is fired | |
- if the generator has spawned the number of bots it was asked to, it will fire the OnExpended output and stop thinking | |
- otherwise, the generator will schedule another think for the future based on the spawn interval setting | |
CTFBotGenerator::OnBotKilled | |
- fires output OnBotKilled | |
CTFBotGenerator::InputEnable | |
- sets m_bEnabled | |
- if !m_bExpended: | |
- starts GeneratorThink | |
- if m_iSpawnsPendingBeforeExpended == 0: | |
- sets m_iSpawnsPendingBeforeExpended to m_spawnCount | |
- schedules an immediate think | |
CTFBotGenerator::InputDisable | |
- unsets m_bEnabled | |
- unschedules thinks | |
CTFBotGenerator::InputSetSuppressFire | |
- sets m_bSuppressFire to input value | |
CTFBotGenerator::InputSetDisableDodge | |
- sets m_bDisableDodge to input value | |
CTFBotGenerator::InputSetDifficulty | |
- sets m_difficulty to input value; clamped to range [-1,3] | |
CTFBotGenerator::InputCommandGotoActionPoint | |
- attempts to find bot_action_point entity with name equal to input value; if no matching entity is found, does nothing | |
- removes any invalid bot handles or valid handles to bots on spectator team | |
- for all valid bot handles: | |
- sets bot's m_hMovementGoal to the entity named by the input value | |
- invokes NextBot command string "goto action point" on the bot | |
CTFBotGenerator::InputSetAttentionFocus | |
- attempts to find entity with name equal to input value; if no matching entity is found, does nothing | |
- removes any invalid bot handles or valid handles to bots on spectator team | |
- for all valid bot handles: sets m_hAttentionFocus to the entity named by the input value | |
CTFBotGenerator::InputClearAttentionFocus | |
- IGNORES input data | |
- removes any invalid bot handles or valid handles to bots on spectator team | |
- for all valid bot handles: clears m_hAttentionFocus | |
CTFBotGenerator::InputSpawnBot | |
- calls SpawnBot if generator is enabled | |
CTFBotGenerator::InputRemoveBots | |
- for all valid bot handles: | |
- calls UTIL_Remove on them | |
- executes ServerCommand "kickid <userid_of_the_bot>" | |
- removes all bot handles from the vector | |
NOTE: logic for function CTFBotTacticalMonitor::OnCommandString: | |
- "cloak": if bot is a spy and is not cloaked, makes the bot press mouse2 | |
- "uncloak": if bot is a spy and is cloaked, makes the bot press mouse2 | |
- "disguise": if bot is a spy and is allowed to disguise, chooses a random class on the enemy team and disguises the bot | |
- "despawn": causes a SUSPEND_FOR transition to action CTFDespawn | |
- "taunt": causes a SUSPEND_FOR transition to action CTFBotTaunt | |
- "goto action point": causes a SUSPEND_FOR transition to action CTFGotoActionPoint | |
- "attack sentry at next action point": causes a SUSPEND_FOR transition to action CTFTrainingAttackSentryActionPoint | |
- "build sentry at nearest sentry hint": | |
- ignored if bot is not an engineer | |
- searches for the nearest bot_hint_sentrygun entity to the bot that is available: | |
- same teamnum as the bot | |
- not currently owned by another bot | |
- not disabled | |
- etc | |
- if no suitable hint entities are found, gives up | |
- gives bot ownership of the hint entity and causes a SUSPEND_FOR transition to action CTFBotEngineerBuilding | |
NOTE: logic for AI action CTFDespawn: | |
- if bot entity is a player, executes ServerCommand "kickid <userid_of_the_bot>" | |
- otherwise, calls UTIL_Remove | |
NOTE: logic for AI action CTFGotoActionPoint: | |
- if m_hMovementGoal is not a valid bot_action_point entity, the action does a DONE transition | |
- if bot is not within the "desired range" of the action point entity m_hMovementGoal, then path toward it | |
- note that at any time, the CTFBotTacticalMonitor AI action running concurrently might decide to SUSPEND_FOR CTFBotUseTeleporter | |
- once within range: | |
- if the action point has a command associated with it, that gets passed along to CTFBotTacticalMonitor::OnCommandString | |
- fires OnReachedActionPoint output of the action point | |
- waits for the action point's "stay time" as necessary | |
- once done: | |
- updates m_hMovementGoal to the action point's next action point (if it has one) | |
- will CHANGE_TO a new instance of CTFGotoActionPoint | |
- so, you go back to the start of this AI logic tree | |
- and if there was no next action point, m_hMovementGoal will be invalid, and so the action chain finally ends | |
NOTE: logic for AI action CTFTrainingAttackSentryActionPoint: | |
- if bot is not within the "desired range" of the action point entity m_hMovementGoal, then path toward it | |
- once within range, aim toward entity m_hTargetSentry and press mouse1 | |
TODO: | |
- find all refs to 0x2AD8 NextBotPlayer::m_hSpawnPoint | |
- find all refs to 0x2B20 CTFBot::m_hMovementGoal | |
- find all refs to 0x2B28 CTFBot::m_hGenerator | |
- find all refs to 0x2B34 CTFBot::m_hTargetSentry | |
- find all refs to 0x2BE0 CTFBot::m_hAttentionFocus | |
- find all refs to 0x2BC8 CTFBot::m_nIgnoreMask |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment