2024-03-21 18:17:18 +00:00
# pragma once
# ifndef AVH_AI_CONSTANTS_H
# define AVH_AI_CONSTANTS_H
# include "DetourStatus.h"
# include "DetourNavMeshQuery.h"
# include "AvHHive.h"
# include "AvHEntities.h"
2024-04-05 14:53:19 +00:00
# include "AvHAIMath.h"
2024-03-21 18:17:18 +00:00
static const float commander_action_cooldown = 1.0f ;
static const float min_request_spam_time = 10.0f ;
constexpr auto MAX_AI_PATH_SIZE = 512 ; // Maximum number of points allowed in a path (this should be enough for any sized map)
static const int MAX_NAV_MESHES = 8 ; // Max number of nav meshes allowed. Currently 3 are used (one for building placement, one for the onos, and a regular one for everyone else)
// NS weapon types. Each number refers to the GoldSrc weapon index
typedef enum
{
WEAPON_INVALID = 0 ,
WEAPON_LERK_SPIKE = 4 , // I think this is an early NS weapon, replaced by primal scream
// Marine Weapons
WEAPON_MARINE_KNIFE = 13 ,
WEAPON_MARINE_PISTOL = 14 ,
WEAPON_MARINE_MG = 15 ,
WEAPON_MARINE_SHOTGUN = 16 ,
WEAPON_MARINE_HMG = 17 ,
WEAPON_MARINE_WELDER = 18 ,
WEAPON_MARINE_MINES = 19 ,
WEAPON_MARINE_GL = 20 ,
WEAPON_MARINE_GRENADE = 28 ,
// Alien Abilities
WEAPON_SKULK_BITE = 5 ,
WEAPON_SKULK_PARASITE = 10 ,
WEAPON_SKULK_LEAP = 21 ,
WEAPON_SKULK_XENOCIDE = 12 ,
WEAPON_GORGE_SPIT = 2 ,
WEAPON_GORGE_HEALINGSPRAY = 27 ,
WEAPON_GORGE_BILEBOMB = 25 ,
WEAPON_GORGE_WEB = 8 ,
WEAPON_LERK_BITE = 6 ,
WEAPON_LERK_SPORES = 3 ,
WEAPON_LERK_UMBRA = 23 ,
WEAPON_LERK_PRIMALSCREAM = 24 ,
WEAPON_FADE_SWIPE = 7 ,
WEAPON_FADE_BLINK = 11 ,
WEAPON_FADE_METABOLIZE = 9 ,
WEAPON_FADE_ACIDROCKET = 26 ,
WEAPON_ONOS_GORE = 1 ,
WEAPON_ONOS_DEVOUR = 30 ,
WEAPON_ONOS_STOMP = 29 ,
WEAPON_ONOS_CHARGE = 22 ,
WEAPON_MAX = 31
}
AvHAIWeapon ;
// Hives can either be unbuilt ("ghost" hive), in progress or fully built (active)
typedef enum
{
HIVE_STATUS_UNBUILT = 0 ,
HIVE_STATUS_BUILDING = 1 ,
HIVE_STATUS_BUILT = 2
} HiveStatusType ;
// All tech statuses that can be assigned to a hive
typedef enum
{
HIVE_TECH_NONE = 0 , // Hive doesn't have any tech assigned to it yet (no chambers built for it)
HIVE_TECH_DEFENCE = 1 ,
HIVE_TECH_SENSORY = 2 ,
HIVE_TECH_MOVEMENT = 3
} HiveTechStatus ;
typedef enum _AI_REACHABILITY_STATUS
{
AI_REACHABILITY_NONE = 0 ,
AI_REACHABILITY_MARINE = 1u < < 0 ,
AI_REACHABILITY_SKULK = 1u < < 1 ,
AI_REACHABILITY_GORGE = 1u < < 2 ,
AI_REACHABILITY_ONOS = 1u < < 3 ,
AI_REACHABILITY_WELDER = 1u < < 4 ,
AI_REACHABILITY_UNREACHABLE = 1u < < 5 ,
AI_REACHABILITY_ALL = - 1
} AvHAIReachabilityStatus ;
typedef enum
{
STRUCTURE_STATUS_NONE = 0 , // No filters, all buildings will be returned
STRUCTURE_STATUS_COMPLETED = 1 , // Structure is fully built
STRUCTURE_STATUS_ELECTRIFIED = 1 < < 1 ,
STRUCTURE_STATUS_RECYCLING = 1 < < 2 ,
STRUCTURE_STATUS_PARASITED = 1 < < 3 ,
STRUCTURE_STATUS_UNDERATTACK = 1 < < 4 ,
STRUCTURE_STATUS_RESEARCHING = 1 < < 5 ,
STRUCTURE_STATUS_DAMAGED = 1 < < 6 ,
STRUCTURE_STATUS_DISABLED = 1 < < 7 , // For marine turrets when there's no TF
STRUCTURE_STATUS_ALL = - 1
} AvHAIStructureStatus ;
typedef enum
{
STRUCTURE_NONE = 0 ,
STRUCTURE_MARINE_RESTOWER = 1u ,
STRUCTURE_MARINE_INFANTRYPORTAL = 1u < < 1 ,
STRUCTURE_MARINE_TURRETFACTORY = 1u < < 2 ,
STRUCTURE_MARINE_ADVTURRETFACTORY = 1u < < 3 ,
STRUCTURE_MARINE_ARMOURY = 1u < < 4 ,
STRUCTURE_MARINE_ADVARMOURY = 1u < < 5 ,
STRUCTURE_MARINE_ARMSLAB = 1u < < 6 ,
STRUCTURE_MARINE_PROTOTYPELAB = 1u < < 7 ,
STRUCTURE_MARINE_OBSERVATORY = 1u < < 8 ,
STRUCTURE_MARINE_PHASEGATE = 1u < < 9 ,
STRUCTURE_MARINE_TURRET = 1u < < 10 ,
STRUCTURE_MARINE_SIEGETURRET = 1u < < 11 ,
STRUCTURE_MARINE_COMMCHAIR = 1u < < 12 ,
STRUCTURE_MARINE_DEPLOYEDMINE = 1u < < 13 ,
STRUCTURE_ALIEN_HIVE = 1u < < 14 ,
STRUCTURE_ALIEN_RESTOWER = 1u < < 15 ,
STRUCTURE_ALIEN_DEFENCECHAMBER = 1u < < 16 ,
STRUCTURE_ALIEN_SENSORYCHAMBER = 1u < < 17 ,
STRUCTURE_ALIEN_MOVEMENTCHAMBER = 1u < < 18 ,
STRUCTURE_ALIEN_OFFENCECHAMBER = 1u < < 19 ,
2024-04-04 14:54:57 +00:00
SEARCH_ALL_MARINE_STRUCTURES = 0xFFF ,
2024-05-25 15:35:50 +00:00
SEARCH_ALL_ALIEN_STRUCTURES = ( STRUCTURE_ALIEN_HIVE | STRUCTURE_ALIEN_RESTOWER | STRUCTURE_ALIEN_DEFENCECHAMBER | STRUCTURE_ALIEN_SENSORYCHAMBER | STRUCTURE_ALIEN_MOVEMENTCHAMBER | STRUCTURE_ALIEN_OFFENCECHAMBER ) ,
2024-03-21 18:17:18 +00:00
SEARCH_ANY_RES_TOWER = ( STRUCTURE_MARINE_RESTOWER | STRUCTURE_ALIEN_RESTOWER ) ,
2024-04-04 14:54:57 +00:00
SEARCH_ALL_STRUCTURES = ( ( unsigned int ) - 1 & ~ ( STRUCTURE_MARINE_DEPLOYEDMINE ) )
2024-03-21 18:17:18 +00:00
} AvHAIDeployableStructureType ;
typedef enum
{
DEPLOYABLE_ITEM_NONE = 0 ,
DEPLOYABLE_ITEM_RESUPPLY = 1u , // For combat mode
DEPLOYABLE_ITEM_HEAVYARMOUR = 1u < < 1 ,
DEPLOYABLE_ITEM_JETPACK = 1u < < 2 ,
DEPLOYABLE_ITEM_CATALYSTS = 1u < < 3 ,
DEPLOYABLE_ITEM_SCAN = 1u < < 4 ,
DEPLOYABLE_ITEM_HEALTHPACK = 1u < < 5 ,
DEPLOYABLE_ITEM_AMMO = 1u < < 6 ,
DEPLOYABLE_ITEM_MINES = 1u < < 7 ,
DEPLOYABLE_ITEM_WELDER = 1u < < 8 ,
DEPLOYABLE_ITEM_SHOTGUN = 1u < < 9 ,
DEPLOYABLE_ITEM_HMG = 1u < < 10 ,
DEPLOYABLE_ITEM_GRENADELAUNCHER = 1u < < 11 ,
DEPLOYABLE_ITEM_WEAPONS = 0xF80 ,
DEPLOYABLE_ITEM_EQUIPMENT = 0x6 ,
DEPLOYABLE_ITEM_ALL = - 1
} AvHAIDeployableItemType ;
// Type of goal the commander wants to achieve
typedef enum _STRUCTUREPURPOSE
{
STRUCTURE_PURPOSE_NONE = 0 ,
2024-04-25 18:28:50 +00:00
STRUCTURE_PURPOSE_GENERAL = 1u ,
STRUCTURE_PURPOSE_SIEGE = 1u < < 1 ,
STRUCTURE_PURPOSE_FORTIFY = 1u < < 2 ,
STRUCTURE_PURPOSE_BASE = 1u < < 3 ,
STRUCTURE_PURPOSE_ANY = - 1
2024-03-21 18:17:18 +00:00
} StructurePurpose ;
typedef enum _AVHAICOMMANDERMODE
{
COMMANDERMODE_DISABLED , // AI Commander not allowed
COMMANDERMODE_IFNOHUMAN , // AI Commander only allowed if no humans are on the marine team
COMMANDERMODE_ENABLED // AI Commander allowed if no human takes charge (following grace period)
} AvHAICommanderMode ;
// Bot's role on the team. For marines, this only governs what they do when left to their own devices.
// Marine bots will always listen to orders from the commander regardless of role.
typedef enum _AVHAIBOTROLE
{
BOT_ROLE_NONE , // No defined role
// General Roles
BOT_ROLE_FIND_RESOURCES , // Will hunt for uncapped resource nodes and cap them. Will attack enemy resource towers
BOT_ROLE_SWEEPER , // Defensive role to protect infrastructure and build at base. Will patrol to keep outposts secure
BOT_ROLE_ASSAULT , // Will go to attack the enemy base. In combat mode, used for Fade-focus aliens
// Marine-only Roles
BOT_ROLE_COMMAND , // Will attempt to take command
BOT_ROLE_BOMBARDIER , // Bot is armed with a GL and wants to wreck your shit. In combat mode, used for Onos-focus aliens
// Alien-only roles
BOT_ROLE_BUILDER , // Will focus on building chambers and hives. Stays gorge most of the time
BOT_ROLE_HARASS // Focuses on taking down enemy resource nodes and hunting the enemy
} AvHAIBotRole ;
typedef enum _AVHAICOMBATSTRATEGY
{
COMBAT_STRATEGY_IGNORE = 0 , // Don't engage this enemy
COMBAT_STRATEGY_AMBUSH , // Set up an ambush for this enemy
COMBAT_STRATEGY_RETREAT , // Retreat and find health
COMBAT_STRATEGY_SKIRMISH , // Maintain distance, whittle down their health from range and generally be a pain the arse
COMBAT_STRATEGY_ATTACK // Attack the enemy
} AvHAICombatStrategy ;
typedef enum _AVHAINAVMESHSTATUS
{
NAVMESH_STATUS_PENDING = 0 , // Waiting to try loading the navmesh
NAVMESH_STATUS_FAILED , // Failed to load the navmesh
NAVMESH_STATUS_SUCCESS // Successfully loaded the navmesh
} AvHAINavMeshStatus ;
typedef struct _OFF_MESH_CONN
{
unsigned int ConnectionRefs [ 2 ] ;
unsigned int ConnectionFlags = 0 ;
unsigned int DefaultConnectionFlags = 0 ;
Vector FromLocation = g_vecZero ;
Vector ToLocation = g_vecZero ;
edict_t * TargetObject = nullptr ;
2024-04-16 16:39:23 +00:00
bool bBiDirectional = false ;
2024-03-21 18:17:18 +00:00
} AvHAIOffMeshConnection ;
typedef struct _STRUCTURE_OBSTACLE
{
unsigned int NavMeshIndex = 0 ;
unsigned int ObstacleRef = 0 ;
} AvHAITempObstacle ;
// Data structure used to track resource nodes in the map
typedef struct _RESOURCE_NODE
{
AvHFuncResource * ResourceEntity = nullptr ; // The func_resource edict reference
edict_t * ResourceEdict = nullptr ;
Vector Location = g_vecZero ; // origin of the func_resource edict (not the tower itself)
bool bIsOccupied = false ; // True if there is any resource tower on it
AvHTeamNumber OwningTeam = TEAM_IND ; // The team that has currently capped this node (TEAM_IND if none)
edict_t * ActiveTowerEntity = nullptr ; // Reference to the resource tower edict (if capped)
bool bIsBaseNode = false ; // Is this a node in the marine base or active alien hive?
edict_t * ParentHive = nullptr ;
unsigned int TeamAReachabilityFlags = AI_REACHABILITY_NONE ; // Who on team A can reach this node?
unsigned int TeamBReachabilityFlags = AI_REACHABILITY_NONE ; // Who on team B can reach this node?
bool bReachabilityMarkedDirty = false ; // Reachability needs to be recalculated
float NextReachabilityRefreshTime = 0.0f ;
} AvHAIResourceNode ;
// Data structure to hold information about each hive in the map
typedef struct _HIVE_DEFINITION_T
{
AvHHive * HiveEntity = nullptr ; // Hive entity reference
edict_t * HiveEdict = nullptr ; // Hive edict reference
Vector Location = g_vecZero ; // Origin of the hive
Vector FloorLocation = g_vecZero ; // Some hives are suspended in the air, this is the floor location directly beneath it
HiveStatusType Status = HIVE_STATUS_UNBUILT ; // Can be unbuilt, in progress, or fully built
AvHMessageID TechStatus = MESSAGE_NULL ; // What tech (if any) is assigned to this hive right now
bool bIsUnderAttack = false ; // Is the hive currently under attack? Becomes false if not taken damage for more than 10 seconds
float HealthPercent = 0.0f ; // If the hive is built and active, what its health currently is
AvHAIResourceNode * HiveResNodeRef = nullptr ; // Which resource node (indexes into ResourceNodes array) belongs to this hive?
unsigned int ObstacleRefs [ MAX_NAV_MESHES ] ; // When in progress or built, will place an obstacle so bots don't try to walk through it
float NextFloorLocationCheck = 0.0f ; // When should the closest navigable point to the hive be calculated? Used to delay the check after a hive is built
AvHTeamNumber OwningTeam = TEAM_IND ; // Which team owns this hive currently (TEAM_IND if empty)
unsigned int TeamAReachabilityFlags = AI_REACHABILITY_NONE ; // Who on team A can reach this node?
unsigned int TeamBReachabilityFlags = AI_REACHABILITY_NONE ; // Who on team B can reach this node?
2024-06-12 19:21:55 +00:00
char HiveName [ 64 ] = { ' \0 ' } ;
2024-03-21 18:17:18 +00:00
} AvHAIHiveDefinition ;
// A nav profile combines a nav mesh reference (indexed into NavMeshes) and filters to determine how a bot should find paths
typedef struct _NAV_PROFILE
{
int NavMeshIndex = - 1 ;
dtQueryFilter Filters ;
bool bFlyingProfile = false ;
AvHAIReachabilityStatus ReachabilityFlag = AI_REACHABILITY_NONE ;
} nav_profile ;
typedef struct _LOAD_NAV_HINT
{
unsigned int id = 0 ;
unsigned int hintType = 0 ;
float position [ 3 ] = { 0.0f , 0.0f , 0.0f } ;
} LoadNavHint ;
typedef struct _NAV_HINT
{
unsigned int hintType = 0 ;
Vector Position = g_vecZero ;
edict_t * OccupyingBuilding = nullptr ;
} NavHint ;
typedef struct _DEPLOYABLE_SEARCH_FILTER
{
unsigned int DeployableTypes = SEARCH_ALL_STRUCTURES ;
unsigned int IncludeStatusFlags = STRUCTURE_STATUS_NONE ;
unsigned int ExcludeStatusFlags = STRUCTURE_STATUS_NONE ;
unsigned int ReachabilityFlags = AI_REACHABILITY_NONE ;
float MinSearchRadius = 0.0f ;
float MaxSearchRadius = 0.0f ;
bool bConsiderPhaseDistance = false ;
AvHTeamNumber DeployableTeam = TEAM_IND ;
AvHTeamNumber ReachabilityTeam = TEAM_IND ;
2024-04-25 18:28:50 +00:00
unsigned int PurposeFlags = STRUCTURE_PURPOSE_ANY ;
2024-03-21 18:17:18 +00:00
} DeployableSearchFilter ;
// Pending message a bot wants to say. Allows for a delay in sending a message to simulate typing, or prevent too many messages on the same frame
typedef struct _BOT_MSG
{
char msg [ 64 ] ; // Message to send
float SendTime = 0.0f ; // When the bot should send this message
bool bIsPending = false ; // Represents a valid pending message
bool bIsTeamSay = false ; // Is this a team-only message?
} bot_msg ;
2024-05-02 19:53:25 +00:00
typedef struct _AVH_AI_GUARD_INFO
2024-03-21 18:17:18 +00:00
{
Vector GuardLocation = g_vecZero ; // What position are we guarding?
Vector GuardStandPosition = g_vecZero ; // Where the bot should stand to guard position (moves around a bit)
2024-04-14 19:50:26 +00:00
std : : vector < Vector > GuardPoints ; // All potential areas to watch that an enemy could approach from
2024-03-21 18:17:18 +00:00
int NumGuardPoints = 0 ; // How many watch areas there are for the current location
Vector GuardLookLocation = g_vecZero ; // Which area are we currently watching?
float GuardStartLookTime = 0.0f ; // When did we start watching the current area?
float ThisGuardLookTime = 0.0f ; // How long should we watch this area for?
float ThisGuardStandTime = 0.0f ; // How long should we watch this area for?
float GuardStartStandTime = 0.0f ; // How long should we watch this area for?
} AvHAIGuardInfo ;
// Data structure to hold information on any kind of buildable structure (hive, resource tower, chamber, marine building etc)
typedef struct _AVH_AI_BUILDABLE_STRUCTURE
{
AvHBaseBuildable * EntityRef = nullptr ;
2024-06-05 19:32:15 +00:00
int EntIndex = - 1 ;
2024-03-21 18:17:18 +00:00
edict_t * edict = nullptr ; // Reference to structure edict
Vector Location = g_vecZero ; // origin of the structure edict
float healthPercent = 0.0f ; // Current health of the building
float lastDamagedTime = 0.0f ; // When it was last damaged by something. Used by bots to determine if still needs defending
AvHAIDeployableStructureType StructureType = STRUCTURE_NONE ; // Type of structure it is (e.g. hive, comm chair, infantry portal, defence chamber etc.)
unsigned int StructureStatusFlags = STRUCTURE_STATUS_NONE ;
unsigned int TeamAReachabilityFlags = AI_REACHABILITY_NONE ;
unsigned int TeamBReachabilityFlags = AI_REACHABILITY_NONE ;
int LastSeen = 0 ; // Which refresh cycle was this last seen on? Used to determine if the building has been removed from play
vector < AvHAITempObstacle > Obstacles ;
vector < AvHAIOffMeshConnection > OffMeshConnections ; // References to any off-mesh connections this structure is associated with
Vector LastSuccessfulCommanderLocation = g_vecZero ; // Tracks the last commander view location where it successfully placed or selected the building
Vector LastSuccessfulCommanderAngle = g_vecZero ; // Tracks the last commander input angle ("click" location) used to successfully place or select building
2024-05-10 19:49:15 +00:00
StructurePurpose Purpose = STRUCTURE_PURPOSE_NONE ;
2024-03-21 18:17:18 +00:00
bool bReachabilityMarkedDirty = false ; // If true, reachability flags will be recalculated for this structure
2024-06-05 19:32:15 +00:00
bool bPlacedByHuman = true ; // This structure was placed by a human: AI commander will not recycle these unless it absolutely makes sense to
2024-03-21 18:17:18 +00:00
bool IsValid ( ) { return ! FNullEnt ( edict ) & & ! edict - > free & & ! ( edict - > v . flags & EF_NODRAW ) & & edict - > v . deadflag = = DEAD_NO ; }
bool IsCompleted ( ) { return ( StructureStatusFlags & STRUCTURE_STATUS_COMPLETED ) ; }
2024-06-05 19:32:15 +00:00
bool IsIdle ( ) { return ! ( StructureStatusFlags & STRUCTURE_STATUS_RESEARCHING ) ; }
2024-03-21 18:17:18 +00:00
} AvHAIBuildableStructure ;
// Any kind of pickup that has been dropped either by the commander or by a player
typedef struct _DROPPED_MARINE_ITEM
{
edict_t * edict = nullptr ; // Reference to the item edict
Vector Location = g_vecZero ; // Origin of the entity
AvHAIDeployableItemType ItemType = DEPLOYABLE_ITEM_NONE ; // Is it a weapon, health pack, ammo pack etc?
unsigned int TeamAReachabilityFlags = AI_REACHABILITY_NONE ;
unsigned int TeamBReachabilityFlags = AI_REACHABILITY_NONE ;
bool bReachabilityMarkedDirty = false ; // Reachability needs to be recalculated
int LastSeen = 0 ; // Which refresh cycle was this last seen on? Used to determine if the item has been removed from play
2024-05-30 12:44:46 +00:00
bool IsValid ( ) { return ! FNullEnt ( edict ) & & ! edict - > free & & ! ( edict - > v . flags & EF_NODRAW ) & & edict - > v . deadflag = = DEAD_NO ; }
2024-03-21 18:17:18 +00:00
} AvHAIDroppedItem ;
// How far a bot can be from a useable object when trying to interact with it. Used also for melee attacks. We make it slightly less than actual to avoid edge cases
static const float max_ai_use_reach = 55.0f ;
// Minimum time a bot can wait between attempts to use something in seconds (when not holding the use key down)
static const float min_ai_use_interval = 0.5f ;
// Minimum time a bot can wait between attempts to use something in seconds (when not holding the use key down)
static const float max_ai_jump_height = 62.0f ;
// Affects the bot's pathfinding choices
enum BotMoveStyle
{
MOVESTYLE_NORMAL , // Most direct route to target
MOVESTYLE_AMBUSH , // Prefer wall climbing and vents
MOVESTYLE_HIDE // Prefer crouched areas like vents
} ;
// The list of potential task types for the bot_task structure
typedef enum
{
TASK_NONE ,
TASK_GET_HEALTH ,
TASK_GET_AMMO ,
TASK_GET_WEAPON ,
TASK_GET_EQUIPMENT ,
TASK_BUILD ,
TASK_ATTACK ,
TASK_MOVE ,
TASK_CAP_RESNODE ,
TASK_DEFEND ,
TASK_GUARD ,
TASK_HEAL ,
TASK_WELD ,
TASK_RESUPPLY ,
TASK_EVOLVE ,
TASK_COMMAND ,
TASK_USE ,
TASK_TOUCH ,
TASK_REINFORCE_STRUCTURE ,
TASK_SECURE_HIVE ,
2024-05-02 19:53:25 +00:00
TASK_PLACE_MINE ,
2024-05-15 14:21:17 +00:00
TASK_ASSAULT_MARINE_BASE
2024-03-21 18:17:18 +00:00
}
BotTaskType ;
//
typedef enum
{
ATTACK_SUCCESS ,
ATTACK_BLOCKED ,
ATTACK_OUTOFRANGE ,
ATTACK_INVALIDTARGET ,
ATTACK_NOWEAPON
}
BotAttackResult ;
typedef enum
{
BUILD_ATTEMPT_NONE = 0 ,
BUILD_ATTEMPT_PENDING ,
BUILD_ATTEMPT_SUCCESS ,
BUILD_ATTEMPT_FAILED
} BotBuildAttemptStatus ;
typedef enum
{
MOVE_TASK_NONE = 0 ,
MOVE_TASK_MOVE ,
MOVE_TASK_USE ,
MOVE_TASK_BREAK ,
MOVE_TASK_TOUCH ,
MOVE_TASK_PICKUP ,
MOVE_TASK_WELD
} BotMovementTaskType ;
// Door type. Not currently used, future feature so bots know how to open a door
enum DoorActivationType
{
DOOR_NONE , // No type, cannot be activated (permanently open/shut)
DOOR_USE , // Door activated by using it directly
DOOR_TRIGGER , // Door activated by touching a trigger_once or trigger_multiple
DOOR_BUTTON , // Door activated by pressing a button
DOOR_WELD , // Door activated by welding something
DOOR_SHOOT , // Door activated by being shot
DOOR_BREAK // Door activated by breaking something
} ;
// Door type. Not currently used, future feature so bots know how to open a door
enum NavDoorType
{
DOORTYPE_DOOR , // No type, cannot be activated (permanently open/shut)
DOORTYPE_PLAT , // Door activated by using it directly
DOORTYPE_TRAIN // Door activated by touching a trigger_once or trigger_multiple
} ;
2024-06-05 19:32:15 +00:00
// The type of base a marine outpost could be. Used to help the AI establish and expand outposts across the map
enum MarineBaseType
{
MARINE_BASE_MAINBASE , // The main marine base, where the CC, infantry portals and stuff like arms labs go
MARINE_BASE_OUTPOST , // A permanent outpost designed to control an area of the map, but not the main marine base
2024-06-12 19:21:55 +00:00
MARINE_BASE_SIEGE , // A siege base designed to take down an enemy base
MARINE_BASE_GUARDPOST // A cut-down version of an outpost with just sentry turrets and an observatory
2024-06-05 19:32:15 +00:00
} ;
typedef struct _AI_MARINE_BASE
{
AvHTeamNumber BaseTeam = TEAM_IND ;
MarineBaseType BaseType = MARINE_BASE_OUTPOST ; // The purpose of the base. Determines what structures the commander will place
Vector BaseLocation = ZERO_VECTOR ; // Where the base should be located. The base will be grown around this location
2024-06-24 13:23:45 +00:00
Vector SiegeTarget = ZERO_VECTOR ; // For siege bases, this is where the siege base wants to blast stuff
2024-06-05 19:32:15 +00:00
vector < int > PlacedStructures ; // Which structures are part of this base.
2024-06-12 19:21:55 +00:00
int NumBuilders = 0 ; // How many potential builders are there, able to construct stuff?
int NumEnemies = 0 ; // How many enemies are in and around the base?
2024-06-05 19:32:15 +00:00
bool bRecycleBase = false ; // Should the commander pack up and remove this base?
2024-06-12 19:21:55 +00:00
bool bIsActive = true ; // Should the commander actively build and maintain this base?
2024-06-05 19:32:15 +00:00
bool bBaseInitialised = false ; // Has the commander started building this base? Will be true once a structure has been placed
2024-06-12 19:21:55 +00:00
bool bCanBeBuiltOut = false ; // Can this base be built out currently?
bool bIsBaseEstablished = false ; // Have enough key structures been placed to consider this "established", even if it's not finished yet?
2024-06-05 19:32:15 +00:00
} AvHAIMarineBase ;
2024-03-21 18:17:18 +00:00
// Bot path node. A path will be several of these strung together to lead the bot to its destination
typedef struct _BOT_PATH_NODE
{
Vector FromLocation = g_vecZero ; // Location to move from
Vector Location = g_vecZero ; // Location to move to
float requiredZ = 0.0f ; // If climbing a up ladder or wall, how high should they aim to get before dismounting.
unsigned int flag = 0 ; // Is this a ladder movement, wall climb, walk etc
unsigned char area = 0 ; // Is this a crouch area, normal walking area etc
unsigned int poly = 0 ; // The nav mesh poly this point resides on
} bot_path_node ;
// Represents a bot's current understanding of an enemy player's status
typedef struct _ENEMY_STATUS
{
2024-04-24 13:20:12 +00:00
AvHPlayer * PlayerRef = nullptr ; // Reference to the enemy AvHPlayer
edict_t * PlayerEdict = nullptr ; // Reference to the enemy player edict
Vector LastDetectedLocation = g_vecZero ; // Where the bot last detected the enemy, either through sight, motion tracking or sound
Vector LastVisibleLocation = g_vecZero ; // Last point the bot had visible confirmation of the enemy
Vector LastKnownVelocity = g_vecZero ;
Vector VisiblePointOnPlayer = g_vecZero ;
float AwarenessOfPlayer = 0.0f ; // How aware of this enemy the bot is
float LastDetectedTime = 0.0f ; // When the bot last saw the enemy or they pinged on motion tracking
float InitialAwarenessTime = 0.0f ; // When the bot first became aware of the enemy
float LastVisibleTime = 0.0f ; // Last time the bot actually saw the enemy
2024-04-25 18:28:50 +00:00
float EnemyThreatLevel = 0.0f ; // Generally, >=3.0 means actively fighting them, >=2.0 means visible and close, >=1.0 means not visible but close and <1.0 means they can be heard but not close
2024-04-24 13:20:12 +00:00
bool bHasLOS = false ; // Does the bot has LOS of the enemy?
bool bEnemyHasLOS = false ;
Vector LastLOSPosition = g_vecZero ;
Vector LastCoverPosition = g_vecZero ;
2024-03-21 18:17:18 +00:00
} enemy_status ;
// Tracks what orders have been given to which players
typedef struct _BOT_SKILL
{
float marine_bot_reaction_time = 0.2f ; // How quickly the bot will react to seeing an enemy
float marine_bot_aim_skill = 0.5f ; // How quickly the bot can lock on to an enemy
float marine_bot_motion_tracking_skill = 0.5f ; // How well the bot can follow an enemy target's motion
float marine_bot_view_speed = 1.0f ; // How fast a bot can spin its view to aim in a given direction
float alien_bot_reaction_time = 0.2f ; // How quickly the bot will react to seeing an enemy
float alien_bot_aim_skill = 0.5f ; // How quickly the bot can lock on to an enemy
float alien_bot_motion_tracking_skill = 0.5f ; // How well the bot can follow an enemy target's motion
float alien_bot_view_speed = 0.5f ; // How fast a bot can spin its view to aim in a given direction
} bot_skill ;
typedef struct _AVH_AI_BUILD_ATTEMPT
{
AvHAIDeployableStructureType AttemptedStructureType = STRUCTURE_NONE ;
Vector AttemptedLocation = g_vecZero ;
int NumAttempts = 0 ;
BotBuildAttemptStatus BuildStatus = BUILD_ATTEMPT_NONE ;
float BuildAttemptTime = 0.0f ;
AvHAIBuildableStructure * LinkedStructure = nullptr ;
} AvHAIBuildAttempt ;
// A bot task is a goal the bot wants to perform, such as attacking a structure, placing a structure etc. NOT USED BY COMMANDER
typedef struct _AVH_AI_PLAYER_TASK
{
BotTaskType TaskType = TASK_NONE ; // Task Type (e.g. build, attack, defend, heal etc)
Vector TaskLocation = g_vecZero ; // Task location, if task needs one (e.g. where to place structure for TASK_BUILD)
edict_t * TaskTarget = nullptr ; // Reference to a target, if task needs one (e.g. TASK_ATTACK)
edict_t * TaskSecondaryTarget = nullptr ; // Secondary target, if task needs one (e.g. TASK_REINFORCE)
AvHAIDeployableStructureType StructureType = STRUCTURE_NONE ; // For Gorges, what structure to build (if TASK_BUILD)
float TaskStartedTime = 0.0f ; // When the bot started this task. Helps time-out if the bot gets stuck trying to complete it
bool bIssuedByCommander = false ; // Was this task issued by the commander? Top priority if so
bool bTargetIsPlayer = false ; // Is the TaskTarget a player?
bool bTaskIsUrgent = false ; // Determines whether this task is prioritised over others if bot has multiple
bool bIsWaitingForBuildLink = false ; // If true, Gorge has sent the build impulse and is waiting to see if the building materialised
float LastBuildAttemptTime = 0.0f ; // When did the Gorge last try to place a structure?
int BuildAttempts = 0 ; // How many attempts the Gorge has tried to place it, so it doesn't keep trying forever
AvHMessageID Evolution = MESSAGE_NULL ; // Used by TASK_EVOLVE to determine what to evolve into
float TaskLength = 0.0f ; // If a task has gone on longer than this time, it will be considered completed
AvHAIBuildAttempt ActiveBuildInfo ; // If gorge, the current status of any recent attempt to place a structure
} AvHAIPlayerTask ;
typedef struct _DOOR_TRIGGER
{
CBaseEntity * Entity = nullptr ;
CBaseToggle * ToggleEnt = nullptr ;
edict_t * Edict = nullptr ;
DoorActivationType TriggerType = DOOR_NONE ;
bool bIsActivated = false ;
CBaseEntity * TriggerChangeTargetRef = nullptr ;
float ActivationDelay = 0.0f ;
float LastActivatedTime = 0.0f ;
TOGGLE_STATE LastToggleState = TS_AT_BOTTOM ;
float LastNextThink = 0.0f ;
float NextActivationTime = 0.0f ;
} DoorTrigger ;
typedef struct _AVH_AI_PLAYER_MOVE_TASK
{
BotMovementTaskType TaskType = MOVE_TASK_NONE ;
Vector TaskLocation = g_vecZero ;
edict_t * TaskTarget = nullptr ;
DoorTrigger * TriggerToActivate = nullptr ;
bool bPathGenerated = false ;
} AvHAIPlayerMoveTask ;
typedef struct _AVH_AI_STUCK_TRACKER
{
Vector LastBotPosition = g_vecZero ;
Vector MoveDestination = g_vecZero ;
float TotalStuckTime = 0.0f ; // Total time the bot has spent stuck
bool bPathFollowFailed = false ;
} AvHAIPlayerStuckTracker ;
// Contains the bot's current navigation info, such as current path
typedef struct _NAV_STATUS
{
vector < bot_path_node > CurrentPath ; // Bot's path nodes
unsigned int CurrentPathPoint = 0 ;
Vector TargetDestination = g_vecZero ; // Desired destination
Vector ActualMoveDestination = g_vecZero ; // Actual destination on nav mesh
Vector PathDestination = g_vecZero ; // Where the path is currently headed to
Vector LastNavMeshCheckPosition = g_vecZero ;
Vector LastNavMeshPosition = g_vecZero ; // Tracks the last place the bot was on the nav mesh. Useful if accidentally straying off it
Vector LastOpenLocation = g_vecZero ; // Tracks the last place the bot had enough room to move around people. Useful if in a vent and need to back up somewhere to let another player past.
int CurrentMoveType = MOVETYPE_NONE ; // Tracks the edict's current movement type
unsigned int CurrentPoly = 0 ; // Which nav mesh poly the bot is currently on
float LastStuckCheckTime = 0.0f ; // Last time the bot checked if it had successfully moved
float TotalStuckTime = 0.0f ; // Total time the bot has spent stuck
float LastDistanceFromDestination = 0.0f ; // How far from its destination was it last stuck check
Vector StuckCheckMoveLocation = g_vecZero ; // Where is the bot trying to go that we're checking if they're stuck?
Vector UnstuckMoveLocation = g_vecZero ; // If the bot is unable to find a path, blindly move here to try and fix the problem
float LandedTime = 0.0f ; // When the bot last landed after a fall/jump.
2024-05-13 09:34:45 +00:00
float AirStartedTime = 0.0f ; // When the bot left the ground if in the air
2024-03-21 18:17:18 +00:00
float LeapAttemptedTime = 0.0f ; // When the bot last attempted to leap/blink. Avoid spam that sends it flying around too fast
bool bIsJumping = false ; // Is the bot in the air from a jump? Will duck so it can duck-jump
bool IsOnGround = true ; // Is the bot currently on the ground, or on a ladder?
bool bHasAttemptedJump = false ; // Last frame, the bot tried a jump. If the bot is still on the ground, it probably tried to jump in a vent or something
float LastFlapTime = 0.0f ; // When the bot last flapped its wings (if Lerk). Prevents per-frame spam draining adrenaline
bool bShouldWalk = false ; // Should the bot walk at this point?
BotMoveStyle PreviousMoveStyle = MOVESTYLE_NORMAL ; // Previous desired move style (e.g. normal, ambush, hide). Will trigger new path calculations if this changes
BotMoveStyle MoveStyle = MOVESTYLE_NORMAL ; // Current desired move style (e.g. normal, ambush, hide). Will trigger new path calculations if this changes
float LastPathCalcTime = 0.0f ; // When the bot last calculated a path, to limit how frequently it can recalculate
float NextForceRecalc = 0.0f ; // If set, then the bot will force-recalc its current path
2024-05-14 13:16:10 +00:00
bool bZig ; // Is the bot zigging (moving RIGHT), or zagging (moving LEFT)?
2024-03-21 18:17:18 +00:00
float NextZigTime ; // Controls how frequently they zig or zag
nav_profile NavProfile ;
bool bNavProfileChanged = false ;
AvHAIPlayerStuckTracker StuckInfo ;
unsigned int SpecialMovementFlags = 0 ; // Any special movement flags required for this path (e.g. needs a welder, needs a jetpack etc.)
AvHAIPlayerMoveTask MovementTask ;
} nav_status ;
typedef enum
{
ORDERPURPOSE_NONE ,
ORDERPURPOSE_SECURE_HIVE ,
ORDERPURPOSE_SIEGE_HIVE ,
2024-06-12 19:21:55 +00:00
ORDERPURPOSE_SECURE_RESNODE ,
ORDERPURPOSE_BUILD_MAINBASE ,
ORDERPURPOSE_BUILD_SIEGE ,
ORDERPURPOSE_BUILD_OUTPOST ,
ORDERPURPOSE_BUILD_GUARDPOST
2024-03-21 18:17:18 +00:00
} AvHAIOrderPurpose ;
typedef struct _AI_COMMANDER_ORDER
{
edict_t * Assignee = nullptr ;
AvHAIOrderPurpose OrderPurpose = ORDERPURPOSE_NONE ;
edict_t * OrderTarget = nullptr ;
Vector OrderLocation = g_vecZero ;
float LastReminderTime = 0.0f ;
float LastPlayerDistance = 0.0f ;
} ai_commander_order ;
typedef struct _AI_COMMANDER_REQUEST
{
bool bNewRequest = false ; // Is this a new request just come in?
edict_t * Requestor = nullptr ; // Who sent the request?
AvHMessageID RequestType = MESSAGE_NULL ; // What did they request?
bool bAcknowledged = false ; // If we can't satisfy the request right now, have we at least acknowledged it?
bool bResponded = false ; // Have we already responded to this request?
float RequestTime = 0.0f ; // When the request came in
int ResponseAttempts = 0 ; // How many times have we tried to respond to this request?
Vector RequestLocation = g_vecZero ; // Where was the request raised? Ideal drop location for stuff
} ai_commander_request ;
typedef struct AVH_AI_PLAYER
{
AvHPlayer * Player = nullptr ;
edict_t * Edict = nullptr ;
AvHTeamNumber Team = TEAM_IND ;
float ForwardMove = 0.0f ;
float SideMove = 0.0f ;
float UpMove = 0.0f ;
int Button = 0.0f ;
int Impulse = 0.0f ;
byte AdjustedMsec = 0 ;
bool bIsPendingKill = false ;
bool bIsInactive = false ;
float LastUseTime = 0.0f ;
float f_previous_command_time = 0.0f ;
Vector desiredMovementDir = g_vecZero ;
Vector CurrentLadderNormal = g_vecZero ;
Vector CurrentEyePosition = g_vecZero ;
Vector CurrentFloorPosition = g_vecZero ;
Vector LastPosition = g_vecZero ;
Vector CollisionHullBottomLocation = g_vecZero ;
Vector CollisionHullTopLocation = g_vecZero ;
float TimeSinceLastMovement = 0.0f ;
AvHAIWeapon DesiredMoveWeapon = WEAPON_INVALID ;
AvHAIWeapon DesiredCombatWeapon = WEAPON_INVALID ;
2024-04-05 14:53:19 +00:00
frustum_plane_t viewFrustum [ 6 ] ; // Bot's view frustum. Essentially, their "screen" for determining visibility of stuff
2024-03-21 18:17:18 +00:00
enemy_status TrackedEnemies [ 32 ] ;
int CurrentEnemy = - 1 ;
AvHAICombatStrategy CurrentCombatStrategy = COMBAT_STRATEGY_ATTACK ;
edict_t * CurrentEnemyRef = nullptr ;
vector < AvHAIBuildableStructure > DangerTurrets ;
AvHAIPlayerTask PrimaryBotTask ;
AvHAIPlayerTask SecondaryBotTask ;
AvHAIPlayerTask WantsAndNeedsTask ;
AvHAIPlayerTask CommanderTask ; // Task assigned by the commander
2024-04-16 16:39:23 +00:00
AvHAIPlayerTask * CurrentTask = & PrimaryBotTask ; // Bot's current task they're performing
2024-03-21 18:17:18 +00:00
float BotNextTaskEvaluationTime = 0.0f ;
bot_skill BotSkillSettings ;
char PathStatus [ 128 ] ; // Debug used to help figure out what's going on with a bot's path finding
char MoveStatus [ 128 ] ; // Debug used to help figure out what's going on with a bot's steering
nav_status BotNavInfo ; // Bot's movement information, their current path, where in the path they are etc.
vector < ai_commander_request > ActiveRequests ;
vector < ai_commander_order > ActiveOrders ;
float next_commander_action_time = 0.0f ;
bot_msg ChatMessages [ 5 ] ; // Bot can have up to 5 chat messages pending
float LastCombatTime = 0.0f ;
AvHAIGuardInfo GuardInfo ;
float LastRequestTime = 0.0f ; // When bot last used a voice line to request something. Prevents spam
2024-06-28 11:06:36 +00:00
float LastTeleportTime = 0.0f ; // Last time the bot teleported somewhere
2024-03-21 18:17:18 +00:00
Vector DesiredLookDirection = g_vecZero ; // What view angle is the bot currently turning towards
Vector InterpolatedLookDirection = g_vecZero ; // Used to smoothly interpolate the bot's view rather than snap instantly like an aimbot
edict_t * LookTarget = nullptr ; // Used to work out what view angle is needed to look at the desired entity
Vector LookTargetLocation = g_vecZero ; // This is the bot's current desired look target. Could be an enemy (see LookTarget), or point of interest
Vector MoveLookLocation = g_vecZero ; // If the bot has to look somewhere specific for movement (e.g. up for a ladder or wall-climb), this will override LookTargetLocation so the bot doesn't get distracted and mess the move up
2024-05-17 20:46:35 +00:00
bool bSnapView = false ; // Use for rapid, precise snapping of the bot's view to the target. Useful if the bot requires more precise view angles for movement or other reasons
2024-03-21 18:17:18 +00:00
float LastTargetTrackUpdate = 0.0f ; // Add a delay to how frequently a bot can track a target's movements
float ViewInterpolationSpeed = 0.0f ; // How fast should the bot turn its view? Depends on distance to turn
float ViewInterpStartedTime = 0.0f ; // Used for interpolation
float ViewUpdateRate = 0.2f ; // How frequently the bot can react to new sightings of enemies etc.
float LastViewUpdateTime = 0.0f ; // Used to throttle view updates based on ViewUpdateRate
Vector ViewForwardVector = g_vecZero ; // Bot's current forward unit vector
Vector LastSafeLocation = g_vecZero ;
AvHAIBotRole BotRole = BOT_ROLE_NONE ;
int ExperiencePointsAvailable = 0 ; // How much experience the bot has to spend
AvHMessageID NextCombatModeUpgrade = MESSAGE_NULL ;
float ThinkDelta = 0.0f ; // How long since this bot last ran AIPlayerThink
float LastThinkTime = 0.0f ; // When the bot last ran AIPlayerThink
float ServerUpdateDelta = 0.0f ; // How long since we last called RunPlayerMove
float LastServerUpdateTime = 0.0f ; // When we last called RunPlayerMove
2024-04-18 07:24:16 +00:00
float HearingThreshold = 0.0f ; // How loud does a sound need to be before the bot detects it? This is set when hearing a sound so that louder sounds drown out quieter ones, and decrements quickly
2024-05-02 19:53:25 +00:00
int DebugValue = 0 ; // Used for debugging the bot
2024-05-22 15:21:40 +00:00
Vector RelocationSpot = ZERO_VECTOR ; // If the bot is commanding and wants to relocate, then this is where they plan to go
2024-06-05 19:32:15 +00:00
vector < AvHAIMarineBase > Bases ;
2024-03-21 18:17:18 +00:00
} AvHAIPlayer ;
2024-05-02 19:53:25 +00:00
typedef struct _AVH_AI_SQUAD
{
AvHTeamNumber SquadTeam = TEAM_IND ; // Which team this squad is for
vector < AvHAIPlayer * > SquadMembers ; // Which bots are assigned to this
Vector SquadGatherLocation = g_vecZero ; // Where should the squad gather before attempting the objective?
edict_t * SquadTarget = nullptr ; // The target of the objective
2024-05-15 14:21:17 +00:00
Vector ObjectiveLocation = g_vecZero ;
2024-05-02 19:53:25 +00:00
BotTaskType SquadObjective = TASK_NONE ; // What to do with the objective
bool bExecuteObjective = false ; // Are we at the gather or execute phase?
bool IsValid ( )
{
return ( SquadMembers . size ( ) > 0 & & ! FNullEnt ( SquadTarget ) ) ;
}
} AvHAISquad ;
2024-03-21 18:17:18 +00:00
# endif