Reworked nav profiles

Nav profiles for bots are now dynamically updated to take into account changing capabilities, such as picking up a welder
This commit is contained in:
RGreenlees 2023-10-14 20:54:42 +01:00 committed by pierow
parent f8951d672b
commit b7db5adcaa
15 changed files with 1232 additions and 1066 deletions

View file

@ -3,6 +3,9 @@
#ifndef AVH_AI_CONSTANTS_H
#define AVH_AI_CONSTANTS_H
#include "DetourStatus.h"
#include "DetourNavMeshQuery.h"
#include "../AvHHive.h"
#include "../AvHEntities.h"
@ -98,7 +101,8 @@ typedef enum _AI_REACHABILITY_STATUS
AI_REACHABILITY_NONE = 0,
AI_REACHABILITY_MARINE = 1u << 0,
AI_REACHABILITY_SKULK = 1u << 1,
AI_REACHABILITY_ONOS = 1u << 2
AI_REACHABILITY_ONOS = 1u << 2,
AI_REACHABILITY_WELDER = 1u << 3,
} AvHAIReachabilityStatus;
// Data structure used to track resource nodes in the map
@ -189,6 +193,15 @@ typedef enum _STRUCTUREPURPOSE
} StructurePurpose;
// 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 _DEPLOYABLE_SEARCH_FILTER
{
unsigned int DeployableTypes = SEARCH_ALL_STRUCTURES;
@ -434,7 +447,6 @@ typedef struct _NAV_STATUS
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
int LastMoveProfile = -1; // The last navigation profile used by the bot. Will trigger new path calculations if this changes (e.g. changed class, changed move style)
bool bPendingRecalculation = false; // This bot should recalculate its path as soon as it can
@ -443,6 +455,9 @@ typedef struct _NAV_STATUS
AvHAIPlayerTask MovementTask;
nav_profile NavProfile;
bool bNavProfileChanged = false;
} nav_status;
// Type of goal the commander wants to achieve
@ -506,6 +521,7 @@ typedef struct AVH_AI_PLAYER
byte AdjustedMsec = 0;
bool bIsPendingKill = false;
bool bIsInactive = false;
float LastUseTime = 0.0f;

View file

@ -5,6 +5,8 @@
#include "../AvHGamerules.h"
int m_spriteTexture;
bool UTIL_CommanderTrace(const edict_t* pEdict, const Vector& start, const Vector& end)
{
TraceResult hit;
@ -239,4 +241,121 @@ bool GetNearestMapLocationAtPoint(vec3_t SearchLocation, string& outLocation)
}
return theSuccess;
}
void UTIL_DrawLine(edict_t* pEntity, Vector start, Vector end)
{
if (FNullEnt(pEntity) || pEntity->free) { return; }
MESSAGE_BEGIN(MSG_ONE, SVC_TEMPENTITY, NULL, pEntity);
WRITE_BYTE(TE_BEAMPOINTS);
WRITE_COORD(start.x);
WRITE_COORD(start.y);
WRITE_COORD(start.z);
WRITE_COORD(end.x);
WRITE_COORD(end.y);
WRITE_COORD(end.z);
WRITE_SHORT(m_spriteTexture);
WRITE_BYTE(1); // framestart
WRITE_BYTE(10); // framerate
WRITE_BYTE(1); // life in 0.1's
WRITE_BYTE(5); // width
WRITE_BYTE(0); // noise
WRITE_BYTE(255); // r, g, b
WRITE_BYTE(255); // r, g, b
WRITE_BYTE(255); // r, g, b
WRITE_BYTE(250); // brightness
WRITE_BYTE(5); // speed
MESSAGE_END();
}
void UTIL_DrawLine(edict_t* pEntity, Vector start, Vector end, float drawTimeSeconds)
{
if (FNullEnt(pEntity) || pEntity->free) { return; }
int timeTenthSeconds = (int)floorf(drawTimeSeconds * 10.0f);
timeTenthSeconds = fmaxf(timeTenthSeconds, 1);
MESSAGE_BEGIN(MSG_ONE, SVC_TEMPENTITY, NULL, pEntity);
WRITE_BYTE(TE_BEAMPOINTS);
WRITE_COORD(start.x);
WRITE_COORD(start.y);
WRITE_COORD(start.z);
WRITE_COORD(end.x);
WRITE_COORD(end.y);
WRITE_COORD(end.z);
WRITE_SHORT(m_spriteTexture);
WRITE_BYTE(1); // framestart
WRITE_BYTE(10); // framerate
WRITE_BYTE(timeTenthSeconds); // life in 0.1's
WRITE_BYTE(5); // width
WRITE_BYTE(0); // noise
WRITE_BYTE(255); // r, g, b
WRITE_BYTE(255); // r, g, b
WRITE_BYTE(255); // r, g, b
WRITE_BYTE(250); // brightness
WRITE_BYTE(5); // speed
MESSAGE_END();
}
void UTIL_DrawLine(edict_t* pEntity, Vector start, Vector end, float drawTimeSeconds, int r, int g, int b)
{
if (FNullEnt(pEntity) || pEntity->free) { return; }
int timeTenthSeconds = (int)floorf(drawTimeSeconds * 10.0f);
MESSAGE_BEGIN(MSG_ONE, SVC_TEMPENTITY, NULL, pEntity);
WRITE_BYTE(TE_BEAMPOINTS);
WRITE_COORD(start.x);
WRITE_COORD(start.y);
WRITE_COORD(start.z);
WRITE_COORD(end.x);
WRITE_COORD(end.y);
WRITE_COORD(end.z);
WRITE_SHORT(m_spriteTexture);
WRITE_BYTE(1); // framestart
WRITE_BYTE(10); // framerate
WRITE_BYTE(timeTenthSeconds); // life in 0.1's
WRITE_BYTE(5); // width
WRITE_BYTE(0); // noise
WRITE_BYTE(r); // r, g, b
WRITE_BYTE(g); // r, g, b
WRITE_BYTE(b); // r, g, b
WRITE_BYTE(250); // brightness
WRITE_BYTE(5); // speed
MESSAGE_END();
}
void UTIL_DrawLine(edict_t* pEntity, Vector start, Vector end, int r, int g, int b)
{
if (FNullEnt(pEntity) || pEntity->free) { return; }
MESSAGE_BEGIN(MSG_ONE, SVC_TEMPENTITY, NULL, pEntity);
WRITE_BYTE(TE_BEAMPOINTS);
WRITE_COORD(start.x);
WRITE_COORD(start.y);
WRITE_COORD(start.z);
WRITE_COORD(end.x);
WRITE_COORD(end.y);
WRITE_COORD(end.z);
WRITE_SHORT(m_spriteTexture);
WRITE_BYTE(1); // framestart
WRITE_BYTE(10); // framerate
WRITE_BYTE(1); // life in 0.1's
WRITE_BYTE(5); // width
WRITE_BYTE(0); // noise
WRITE_BYTE(r); // r, g, b
WRITE_BYTE(g); // r, g, b
WRITE_BYTE(b); // r, g, b
WRITE_BYTE(250); // brightness
WRITE_BYTE(5); // speed
MESSAGE_END();
}

View file

@ -30,4 +30,13 @@ bool GetNearestMapLocationAtPoint(vec3_t SearchLocation, string& outLocation);
AvHAIDeployableStructureType GetDeployableObjectTypeFromEdict(const edict_t* StructureEdict);
// Draws a white line between start and end for the given player (pEntity) for 0.1s
void UTIL_DrawLine(edict_t* pEntity, Vector start, Vector end);
// Draws a white line between start and end for the given player (pEntity) for given number of seconds
void UTIL_DrawLine(edict_t* pEntity, Vector start, Vector end, float drawTimeSeconds);
// Draws a coloured line using RGB input, between start and end for the given player (pEntity) for 0.1s
void UTIL_DrawLine(edict_t* pEntity, Vector start, Vector end, int r, int g, int b);
// Draws a coloured line using RGB input, between start and end for the given player (pEntity) for given number of seconds
void UTIL_DrawLine(edict_t* pEntity, Vector start, Vector end, float drawTimeSeconds, int r, int g, int b);
#endif

File diff suppressed because it is too large Load diff

View file

@ -19,74 +19,48 @@
cannot wall climb, and has a higher cost for crouch movement since it's slower.
*/
constexpr auto MARINE_REGULAR_NAV_PROFILE = 0;
constexpr auto SKULK_REGULAR_NAV_PROFILE = 1;
constexpr auto SKULK_AMBUSH_NAV_PROFILE = 2;
constexpr auto GORGE_REGULAR_NAV_PROFILE = 3;
constexpr auto GORGE_HIDE_NAV_PROFILE = 4;
constexpr auto FADE_REGULAR_NAV_PROFILE = 5;
constexpr auto ONOS_REGULAR_NAV_PROFILE = 6;
constexpr auto BUILDING_REGULAR_NAV_PROFILE = 7;
constexpr auto ALL_NAV_PROFILE = 8;
constexpr auto LERK_FLYING_NAV_PROFILE = 9;
constexpr auto GORGE_BUILD_NAV_PROFILE = 10;
constexpr auto MARINE_WELD_NAV_PROFILE = 11;
constexpr auto MIN_PATH_RECALC_TIME = 0.33f; // How frequently can a bot recalculate its path? Default to max 3 times per second
constexpr auto MAX_BOT_STUCK_TIME = 30.0f; // How long a bot can be stuck, unable to move, before giving up and suiciding
constexpr auto MARINE_BASE_NAV_PROFILE = 0;
constexpr auto SKULK_BASE_NAV_PROFILE = 1;
constexpr auto GORGE_BASE_NAV_PROFILE = 2;
constexpr auto LERK_BASE_NAV_PROFILE = 3;
constexpr auto FADE_BASE_NAV_PROFILE = 4;
constexpr auto ONOS_BASE_NAV_PROFILE = 5;
constexpr auto STRUCTURE_BASE_NAV_PROFILE = 6;
constexpr auto ALL_NAV_PROFILE = 7;
#define MAX_PATH_POLY 512 // Max nav mesh polys that can be traversed in a path. This should be sufficient for any sized map.
// Possible area types. Water, Road, Door and Grass are not used (left-over from Detour library)
enum SamplePolyAreas
{
SAMPLE_POLYAREA_GROUND = 0, // Regular ground movement
SAMPLE_POLYAREA_CROUCH = 1, // Requires crouched movement
SAMPLE_POLYAREA_WATER = 2, // Swimming (NOT USED)
SAMPLE_POLYAREA_BLOCKED = 3, // Requires a jump to get over
SAMPLE_POLYAREA_WALLCLIMB = 4, // Requires the ability to wall climb (i.e. skulks/fades/lerks only)
SAMPLE_POLYAREA_LADDER = 5, // Requires climbing a ladder (ignored by skulks)
SAMPLE_POLYAREA_DOOR = 6, // Requires moving through a door (NOT USED)
SAMPLE_POLYAREA_JUMP = 7, // Requires a jump to get through
SAMPLE_POLYAREA_HIGHJUMP = 8, // Requires jumping from a great height
SAMPLE_POLYAREA_FALL = 9, // Requires dropping down from a higher elevation
SAMPLE_POLYAREA_HIGHFALL = 10, // Requires a large drop from a high height
SAMPLE_POLYAREA_PHASEGATE = 11, // Requires accessing a phase gate (i.e. marines only)
SAMPLE_POLYAREA_MSTRUCTURE = 12, // Requires bypassing a marine structure
SAMPLE_POLYAREA_ASTRUCTURE = 13, // Requires bypassing an alien structure
SAMPLE_POLYAREA_FLY = 14, // Requires the ability to fly (currently lerks only)
SAMPLE_POLYAREA_GROUND = 0, // Regular ground movement
SAMPLE_POLYAREA_CROUCH = 1, // Requires crouched movement
SAMPLE_POLYAREA_BLOCKED = 2, // Requires a jump to get over
SAMPLE_POLYAREA_FALLDAMAGE = 3, // Requires taking fall damage (if not immune to it)
SAMPLE_POLYAREA_WALLCLIMB = 4 // Requires the ability to wall-stick, fly or blink
};
// Possible movement types. Swim and door are not used
enum SamplePolyFlags
{
SAMPLE_POLYFLAGS_WALK = 1 << 0, // Simple walk to traverse
SAMPLE_POLYFLAGS_BLOCKED = 1 << 1, // Blocked by an obstruction, but can be jumped over
SAMPLE_POLYFLAGS_WALLCLIMB = 1 << 2, // Requires climbing a wall to traverse
SAMPLE_POLYFLAGS_LADDER = 1 << 3, // Requires climbing a ladder to traverse
SAMPLE_POLYFLAGS_DOOR = 1 << 4, // Requires opening a door to traverse (not used)
SAMPLE_POLYFLAGS_JUMP = 1 << 5, // Requires a jump to traverse
SAMPLE_POLYFLAGS_HIGHJUMP = 1 << 6, // Requires a jump from a high height to traverse
SAMPLE_POLYFLAGS_FALL = 1 << 7, // Requires dropping down from a safe height to traverse
SAMPLE_POLYFLAGS_HIGHFALL = 1 << 8, // Requires dropping from a high height to traverse
SAMPLE_POLYFLAGS_DISABLED = 1 << 9, // Disabled, not usable by anyone
SAMPLE_POLYFLAGS_NOONOS = 1 << 10, // This movement is not allowed by onos
SAMPLE_POLYFLAGS_PHASEGATE = 1 << 11, // Requires using a phase gate to traverse
SAMPLE_POLYFLAGS_MSTRUCTURE = 1 << 12, // Marine Structure in the way, must be destroyed if alien, or impassable if marine
SAMPLE_POLYFLAGS_ASTRUCTURE = 1 << 13, // Structure in the way, must be destroyed if marine, or impassable if alien
SAMPLE_POLYFLAGS_WELD = 1 << 14, // Requires a welder to get through here
SAMPLE_POLYFLAGS_ALL = 0xffff // All abilities.
SAMPLE_POLYFLAGS_WALK = 1 << 0, // Simple walk to traverse
SAMPLE_POLYFLAGS_FALL = 1 << 1, // Required dropping down
SAMPLE_POLYFLAGS_BLOCKED = 1 << 2, // Blocked by an obstruction, but can be jumped over
SAMPLE_POLYFLAGS_WALLCLIMB = 1 << 3, // Requires climbing a wall to traverse
SAMPLE_POLYFLAGS_LADDER = 1 << 4, // Requires climbing a ladder to traverse
SAMPLE_POLYFLAGS_JUMP = 1 << 5, // Requires a regular jump to traverse
SAMPLE_POLYFLAGS_DUCKJUMP = 1 << 6, // Requires a duck-jump to traverse
SAMPLE_POLYFLAGS_NOONOS = 1 << 7, // This movement is not allowed by onos
SAMPLE_POLYFLAGS_PHASEGATE = 1 << 8, // Requires using a phase gate to traverse
SAMPLE_POLYFLAGS_TEAM1STRUCTURE = 1 << 9, // A team 1 structure is in the way that cannot be jumped over. Impassable to team 1 players
SAMPLE_POLYFLAGS_TEAM2STRUCTURE = 1 << 10, // A team 2 structure is in the way that cannot be jumped over. Impassable to team 2 players
SAMPLE_POLYFLAGS_WELD = 1 << 11, // Requires a welder to get through here
SAMPLE_POLYFLAGS_DISABLED = 1 << 15, // Disabled, not usable by anyone
SAMPLE_POLYFLAGS_ALL = 0xffff // All abilities.
};
// Door type. Not currently used, future feature so bots know how to open a door
@ -145,14 +119,6 @@ typedef struct _NAV_MESH
class dtNavMesh* navMesh;
} nav_mesh;
// 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;
static const int NAVMESHSET_MAGIC = 'M' << 24 | 'S' << 16 | 'E' << 8 | 'T'; //'MSET', used to confirm the nav mesh we're loading is compatible;
static const int NAVMESHSET_VERSION = 1;
@ -181,7 +147,7 @@ static const int DOOR_START_OPEN = 1;
static const float CHECK_STUCK_INTERVAL = 0.1f; // How frequently should the bot check if it's stuck?
static nav_mesh NavMeshes[MAX_NAV_MESHES]; // Array of nav meshes. Currently only 3 are used (building, onos, and regular)
static nav_profile NavProfiles[MAX_NAV_PROFILES]; // Array of nav profiles
static nav_profile BaseNavProfiles[MAX_NAV_PROFILES]; // Array of nav profiles
// Returns true if a valid nav mesh has been loaded into memory
bool NavmeshLoaded();
@ -196,6 +162,15 @@ bool LoadNavMesh(const char* mapname);
// Unloads the nav meshes (UnloadNavMeshes()) and then reloads them (LoadNavMesh). Map data such as doors, hives, locations are not touched.
void ReloadNavMeshes();
void SetBaseNavProfile(AvHAIPlayer* pBot);
void UpdateBotMoveProfile(AvHAIPlayer* pBot, BotMoveStyle MoveStyle);
void MarineUpdateBotMoveProfile(AvHAIPlayer* pBot, BotMoveStyle MoveStyle);
void SkulkUpdateBotMoveProfile(AvHAIPlayer* pBot, BotMoveStyle MoveStyle);
void GorgeUpdateBotMoveProfile(AvHAIPlayer* pBot, BotMoveStyle MoveStyle);
void LerkUpdateBotMoveProfile(AvHAIPlayer* pBot, BotMoveStyle MoveStyle);
void FadeUpdateBotMoveProfile(AvHAIPlayer* pBot, BotMoveStyle MoveStyle);
void OnosUpdateBotMoveProfile(AvHAIPlayer* pBot, BotMoveStyle MoveStyle);
// FUTURE FEATURE: Will eventually link a door to the trigger than opens it
void UTIL_LinkTriggerToDoor(const edict_t* DoorEdict, nav_door* DoorRef);
@ -207,14 +182,14 @@ Vector UTIL_GetRandomPointOnNavmesh(const AvHAIPlayer* pBot);
Returns ZERO_VECTOR if none found
*/
Vector UTIL_GetRandomPointOnNavmeshInRadius(const int NavProfileIndex, const Vector origin, const float MaxRadius);
Vector UTIL_GetRandomPointOnNavmeshInRadius(const nav_profile& NavProfile, const Vector origin, const float MaxRadius);
/* Finds any random point on the navmesh that is relevant for the bot within a given radius of the origin point,
ignores reachability (could return a location that isn't actually reachable for the bot).
Returns ZERO_VECTOR if none found
*/
Vector UTIL_GetRandomPointOnNavmeshInRadiusIgnoreReachability(const int NavProfileIndex, const Vector origin, const float MaxRadius);
Vector UTIL_GetRandomPointOnNavmeshInRadiusIgnoreReachability(const nav_profile& NavProfile, const Vector origin, const float MaxRadius);
/* Finds any random point on the navmesh of the area type (e.g. crouch area) that is relevant for the bot within a given radius of the origin point,
taking reachability into account(will not return impossible to reach location).
@ -228,17 +203,17 @@ Vector UTIL_GetRandomPointOnNavmeshInRadiusOfAreaType(SamplePolyFlags Flag, cons
Returns ZERO_VECTOR if none found
*/
Vector UTIL_GetRandomPointOnNavmeshInDonut(const int NavProfile, const Vector origin, const float MinRadius, const float MaxRadius);
Vector UTIL_GetRandomPointOnNavmeshInDonut(const nav_profile& NavProfile, const Vector origin, const float MinRadius, const float MaxRadius);
/* Finds any random point on the navmesh of the area type (e.g. crouch area) that is relevant for the bot within the min and max radius of the origin point,
ignores reachability (could return a location that isn't actually reachable for the bot).
Returns ZERO_VECTOR if none found
*/
Vector UTIL_GetRandomPointOnNavmeshInDonutIgnoreReachability(const int NavProfile, const Vector origin, const float MinRadius, const float MaxRadius);
Vector UTIL_GetRandomPointOnNavmeshInDonutIgnoreReachability(const nav_profile& NavProfile, const Vector origin, const float MinRadius, const float MaxRadius);
// Roughly estimates the movement cost to move between FromLocation and ToLocation. Uses simple formula of distance between points x cost modifier for that movement
float UTIL_GetPathCostBetweenLocations(const int NavProfileIndex, const Vector FromLocation, const Vector ToLocation);
float UTIL_GetPathCostBetweenLocations(const nav_profile &NavProfile, const Vector FromLocation, const Vector ToLocation);
// Returns true is the bot is grounded, on the nav mesh, and close enough to the Destination to be considered at that point
bool BotIsAtLocation(const AvHAIPlayer* pBot, const Vector Destination);
@ -275,7 +250,9 @@ DoorTrigger* UTIL_GetNearestDoorTrigger(const Vector Location, nav_door* Door, C
bool UTIL_IsPathBlockedByDoor(const Vector StartLoc, const Vector EndLoc, edict_t* SearchDoor);
edict_t* UTIL_GetDoorBlockingPathPoint(bot_path_node* PathNode, edict_t* SearchDoor);
edict_t* UTIL_GetDoorBlockingPathPoint(const Vector FromLocation, const Vector ToLocation, const unsigned char Area, edict_t* SearchDoor);
edict_t* UTIL_GetDoorBlockingPathPoint(const Vector FromLocation, const Vector ToLocation, const unsigned short MovementFlag, edict_t* SearchDoor);
edict_t* UTIL_GetBreakableBlockingPathPoint(AvHAIPlayer* pBot, bot_path_node* PathNode, edict_t* SearchBreakable);
edict_t* UTIL_GetBreakableBlockingPathPoint(AvHAIPlayer* pBot, const Vector FromLocation, const Vector ToLocation, const unsigned short MovementFlag, edict_t* SearchBreakable);
Vector UTIL_GetButtonFloorLocation(const Vector UserLocation, edict_t* ButtonEdict);
@ -292,7 +269,7 @@ bool IsBotStuck(AvHAIPlayer* pBot, const Vector MoveDestination);
void UTIL_UpdateTileCache();
Vector UTIL_GetNearestPointOnNavWall(AvHAIPlayer* pBot, const float MaxRadius);
Vector UTIL_GetNearestPointOnNavWall(const int NavProfileIndex, const Vector Location, const float MaxRadius);
Vector UTIL_GetNearestPointOnNavWall(const nav_profile& NavProfile, const Vector Location, const float MaxRadius);
/* Places a temporary obstacle of the given height and radius on the mesh.Will modify that part of the nav mesh to be the given area.
An example use case is to place an obstacle of area type SAMPLE_POLYAREA_OBSTRUCTION to mark where buildings are.
@ -346,22 +323,21 @@ void MoveDirectlyTo(AvHAIPlayer* pBot, const Vector Destination);
void HandlePlayerAvoidance(AvHAIPlayer* pBot, const Vector MoveDestination);
// Special path finding that takes the presence of phase gates into account
dtStatus FindPhaseGatePathToPoint(const int NavProfileIndex, Vector FromLocation, Vector ToLocation, bot_path_node* path, int* pathSize, float MaxAcceptableDistance);
dtStatus FindPhaseGatePathToPoint(const nav_profile& NavProfile, Vector FromLocation, Vector ToLocation, bot_path_node* path, int* pathSize, float MaxAcceptableDistance);
// Special path finding that takes the presence of phase gates into account
dtStatus FindFlightPathToPoint(const int NavProfileIndex, Vector FromLocation, Vector ToLocation, bot_path_node* path, int* pathSize, float MaxAcceptableDistance);
dtStatus FindFlightPathToPoint(const nav_profile& NavProfile, Vector FromLocation, Vector ToLocation, bot_path_node* path, int* pathSize, float MaxAcceptableDistance);
Vector UTIL_FindHighestSuccessfulTracePoint(const Vector TraceFrom, const Vector TargetPoint, const Vector NextPoint, const float IterationStep, const float MinIdealHeight, const float MaxHeight);
// Similar to FindPathToPoint, but you can specify a max acceptable distance for partial results. Will return a failure if it can't reach at least MaxAcceptableDistance away from the ToLocation
dtStatus FindPathClosestToPoint(AvHAIPlayer* pBot, const BotMoveStyle MoveStyle, const Vector FromLocation, const Vector ToLocation, bot_path_node* path, int* pathSize, float MaxAcceptableDistance);
dtStatus FindPathClosestToPoint(const int NavProfileIndex, const Vector FromLocation, const Vector ToLocation, bot_path_node* path, int* pathSize, float MaxAcceptableDistance);
dtStatus FindDetailedPathClosestToPoint(const int NavProfileIndex, const Vector FromLocation, const Vector ToLocation, bot_path_node* path, int* pathSize, float MaxAcceptableDistance);
dtStatus FindPathClosestToPoint(const nav_profile& NavProfile, const Vector FromLocation, const Vector ToLocation, bot_path_node* path, int* pathSize, float MaxAcceptableDistance);
// If the bot is stuck and off the path or nav mesh, this will try to find a point it can directly move towards to get it back on track
Vector FindClosestPointBackOnPath(AvHAIPlayer* pBot);
Vector FindClosestNavigablePointToDestination(const int NavProfileIndex, const Vector FromLocation, const Vector ToLocation, float MaxAcceptableDistance);
Vector FindClosestNavigablePointToDestination(const nav_profile& NavProfile, const Vector FromLocation, const Vector ToLocation, float MaxAcceptableDistance);
// Will attempt to move directly towards MoveDestination while jumping/ducking as needed, and avoiding obstacles in the way
void PerformUnstuckMove(AvHAIPlayer* pBot, const Vector MoveDestination);
@ -370,14 +346,11 @@ void PerformUnstuckMove(AvHAIPlayer* pBot, const Vector MoveDestination);
static float frand();
// Finds the appropriate nav mesh for the requested profile
const dtNavMesh* UTIL_GetNavMeshForProfile(const int NavProfileIndex);
const dtNavMesh* UTIL_GetNavMeshForProfile(const nav_profile & NavProfile);
// Finds the appropriate nav mesh query for the requested profile
const dtNavMeshQuery* UTIL_GetNavMeshQueryForProfile(const int NavProfileIndex);
// Finds the appropriate query filter for the requested profile
const dtQueryFilter* UTIL_GetNavMeshFilterForProfile(const int NavProfileIndex);
const dtNavMeshQuery* UTIL_GetNavMeshQueryForProfile(const nav_profile& NavProfile);
// Finds the appropriatetile cache for the requested profile
const dtTileCache* UTIL_GetTileCacheForProfile(const int NavProfileIndex);
AvHAIReachabilityStatus UTIL_GetReachabilityFlagForProfile(const int NavProfileIndex);
const dtTileCache* UTIL_GetTileCacheForProfile(const nav_profile& NavProfile);
float UTIL_PointIsDirectlyReachable_DEBUG(const Vector start, const Vector target);
@ -389,12 +362,12 @@ float UTIL_PointIsDirectlyReachable_DEBUG(const Vector start, const Vector targe
bool UTIL_PointIsDirectlyReachable(const AvHAIPlayer* pBot, const Vector targetPoint);
bool UTIL_PointIsDirectlyReachable(const AvHAIPlayer* pBot, const Vector start, const Vector target);
bool UTIL_PointIsDirectlyReachable(const Vector start, const Vector target);
bool UTIL_PointIsDirectlyReachable(const int NavProfileIndex, const Vector start, const Vector target);
bool UTIL_PointIsDirectlyReachable(const nav_profile& NavProfile, const Vector start, const Vector target);
// Will trace along the nav mesh from start to target and return true if the trace reaches within MaxAcceptableDistance
bool UTIL_TraceNav(const int NavProfileIndex, const Vector start, const Vector target, const float MaxAcceptableDistance);
bool UTIL_TraceNav(const nav_profile& NavProfile, const Vector start, const Vector target, const float MaxAcceptableDistance);
void UTIL_TraceNavLine(const int NavProfileIndex, const Vector Start, const Vector End, nav_hitresult* HitResult);
void UTIL_TraceNavLine(const nav_profile& NavProfile, const Vector Start, const Vector End, nav_hitresult* HitResult);
/*
Project point to navmesh:
@ -404,31 +377,21 @@ void UTIL_TraceNavLine(const int NavProfileIndex, const Vector Start, const Vect
*/
Vector UTIL_ProjectPointToNavmesh(const Vector Location);
Vector UTIL_ProjectPointToNavmesh(const Vector Location, const Vector Extents);
Vector UTIL_ProjectPointToNavmesh(const Vector Location, const int NavProfileIndex);
Vector UTIL_ProjectPointToNavmesh(const Vector Location, const Vector Extents, const int NavProfileIndex);
Vector UTIL_ProjectPointToNavmesh(const Vector Location, const nav_profile& NavProfile);
Vector UTIL_ProjectPointToNavmesh(const Vector Location, const Vector Extents, const nav_profile& NavProfile);
/*
Point is on navmesh:
Returns true if it was able to project the point to the navmesh (see UTIL_ProjectPointToNavmesh())
*/
bool UTIL_PointIsOnNavmesh(const Vector Location, const int NavProfileIndex);
bool UTIL_PointIsOnNavmesh(const int NavProfileIndex, const Vector Location, const Vector SearchExtents);
int UTIL_GetMoveProfileForBot(const AvHAIPlayer* pBot, BotMoveStyle MoveStyle);
int UTIL_GetMoveProfileForMarine(const BotMoveStyle MoveStyle);
int UTIL_GetMoveProfileForSkulk(const BotMoveStyle MoveStyle);
int UTIL_GetMoveProfileForGorge(const BotMoveStyle MoveStyle);
int UTIL_GetMoveProfileForLerk(const BotMoveStyle MoveStyle);
int UTIL_GetMoveProfileForFade(const BotMoveStyle MoveStyle);
int UTIL_GetMoveProfileForOnos(const BotMoveStyle MoveStyle);
bool UTIL_PointIsOnNavmesh(const Vector Location, const nav_profile& NavProfile);
bool UTIL_PointIsOnNavmesh(const nav_profile& NavProfile, const Vector Location, const Vector SearchExtents);
// Sets the BotNavInfo so the bot can track if it's on the ground, in the air, climbing a wall, on a ladder etc.
void UTIL_UpdateBotMovementStatus(AvHAIPlayer* pBot);
// Returns true if a path could be found between From and To location. Cheaper than full path finding, only a rough check to confirm it can be done.
bool UTIL_PointIsReachable(const int NavProfileIndex, const Vector FromLocation, const Vector ToLocation, const float MaxAcceptableDistance);
bool UTIL_PointIsReachable(const nav_profile& NavProfile, const Vector FromLocation, const Vector ToLocation, const float MaxAcceptableDistance);
// If the bot has a path, it will work out how far along the path it can see and return the furthest point. Used so that the bot looks ahead along the path rather than just at its next path point
Vector UTIL_GetFurthestVisiblePointOnPath(const AvHAIPlayer* pBot);
@ -439,11 +402,11 @@ Vector UTIL_GetFurthestVisiblePointOnPath(const Vector ViewerLocation, const bot
// Returns the nearest nav mesh poly reference for the edict's current world position
dtPolyRef UTIL_GetNearestPolyRefForEntity(const edict_t* Edict);
dtPolyRef UTIL_GetNearestPolyRefForLocation(const Vector Location);
dtPolyRef UTIL_GetNearestPolyRefForLocation(const int NavProfileIndex, const Vector Location);
dtPolyRef UTIL_GetNearestPolyRefForLocation(const nav_profile& NavProfile, const Vector Location);
// Returns the area for the nearest nav mesh poly to the given location. Returns BLOCKED if none found
unsigned char UTIL_GetNavAreaAtLocation(const Vector Location);
unsigned char UTIL_GetNavAreaAtLocation(const int NavProfile, const Vector Location);
unsigned char UTIL_GetNavAreaAtLocation(const nav_profile& NavProfile, const Vector Location);
// For printing out human-readable nav mesh areas
const char* UTIL_NavmeshAreaToChar(const unsigned char Area);
@ -491,5 +454,7 @@ Vector UTIL_AdjustPointAwayFromNavWall(const Vector Location, const float MaxDis
unsigned char UTIL_GetBotCurrentPathArea(AvHAIPlayer* pBot);
unsigned char UTIL_GetNextBotCurrentPathArea(AvHAIPlayer* pBot);
void UTIL_PopulateBaseNavProfiles();
#endif // BOT_NAVIGATION_H

View file

@ -257,9 +257,7 @@ void BotLeap(AvHAIPlayer* pBot, const Vector TargetLocation)
Vector LookLocation = TargetLocation;
int NavProfileIndex = UTIL_GetMoveProfileForBot(pBot, MOVESTYLE_NORMAL);
unsigned char NavArea = UTIL_GetNavAreaAtLocation(NavProfileIndex, pBot->Edict->v.origin);
unsigned char NavArea = UTIL_GetNavAreaAtLocation(pBot->BotNavInfo.NavProfile, pBot->Edict->v.origin);
if (NavArea == SAMPLE_POLYAREA_CROUCH)
{
@ -377,7 +375,7 @@ void LinkDeployedObjectToCommanderAction(AvHAIPlayer* Commander, AvHAIBuildableS
if (Action->NumDesiredInstances > 1)
{
Action->BuildLocation = UTIL_GetRandomPointOnNavmeshInRadius(MARINE_REGULAR_NAV_PROFILE, Action->BuildLocation, UTIL_MetresToGoldSrcUnits(1.0f));
Action->BuildLocation = UTIL_GetRandomPointOnNavmeshInRadius(BaseNavProfiles[MARINE_BASE_NAV_PROFILE], Action->BuildLocation, UTIL_MetresToGoldSrcUnits(1.0f));
}
Action->bIsAwaitingBuildLink = false;
@ -543,15 +541,13 @@ void BotAttackTarget(AvHAIPlayer* pBot, edict_t* Target)
{
Vector NewAttackLocation = ZERO_VECTOR;
int BotMoveProfile = UTIL_GetMoveProfileForBot(pBot, MOVESTYLE_NORMAL);
if (vIsZero(pBot->BotNavInfo.ActualMoveDestination))
{
NewAttackLocation = FindClosestNavigablePointToDestination(BotMoveProfile, pBot->CurrentFloorPosition, UTIL_GetEntityGroundLocation(Target), WeaponRange);
NewAttackLocation = FindClosestNavigablePointToDestination(pBot->BotNavInfo.NavProfile, pBot->CurrentFloorPosition, UTIL_GetEntityGroundLocation(Target), WeaponRange);
}
else
{
NewAttackLocation = UTIL_GetRandomPointOnNavmeshInRadius(BotMoveProfile, pBot->CurrentFloorPosition, 2.0f);
NewAttackLocation = UTIL_GetRandomPointOnNavmeshInRadius(pBot->BotNavInfo.NavProfile, pBot->CurrentFloorPosition, 2.0f);
// Did we find a clear spot we could attack from? If so, make that our new move destination
if (NewAttackLocation != ZERO_VECTOR && UTIL_TraceEntity(pBot->Edict, NewAttackLocation + Vector(0.0f, 0.0f, 32.0f), UTIL_GetCentreOfEntity(Target)) == Target)
@ -1405,16 +1401,21 @@ void UpdateBotChat(AvHAIPlayer* pBot)
}
}
void StartNewBotFrame(AvHAIPlayer* pBot)
void ClearBotInputs(AvHAIPlayer* pBot)
{
edict_t* pEdict = pBot->Edict;
pBot->Button = 0;
pBot->ForwardMove = 0.0f;
pBot->SideMove = 0.0f;
pBot->UpMove = 0.0f;
pBot->Impulse = 0;
pBot->Button = 0;
}
void StartNewBotFrame(AvHAIPlayer* pBot)
{
edict_t* pEdict = pBot->Edict;
ClearBotInputs(pBot);
pBot->CurrentEyePosition = GetPlayerEyePosition(pEdict);
pBot->CurrentFloorPosition = UTIL_GetEntityGroundLocation(pEdict);
pBot->LookTargetLocation = ZERO_VECTOR;
@ -1482,15 +1483,13 @@ void TestNavThink(AvHAIPlayer* pBot)
}
else
{
int MoveProfile = UTIL_GetMoveProfileForBot(pBot, MOVESTYLE_NORMAL);
AvHAIResourceNode* RandomNode = AITAC_GetRandomResourceNode();
if (!RandomNode) { return; }
Vector RandomPoint = RandomNode->Location;
if (RandomPoint != ZERO_VECTOR && UTIL_PointIsReachable(MoveProfile, pBot->Edict->v.origin, RandomPoint, max_player_use_reach))
if (RandomPoint != ZERO_VECTOR && UTIL_PointIsReachable(pBot->BotNavInfo.NavProfile, pBot->Edict->v.origin, RandomPoint, max_player_use_reach))
{
AITASK_SetMoveTask(pBot, &pBot->PrimaryBotTask, RandomPoint, true);
}
@ -1505,4 +1504,17 @@ void BotSwitchToWeapon(AvHAIPlayer* pBot, AvHAIWeapon NewWeaponSlot)
{
char* WeaponName = UTIL_WeaponTypeToClassname(NewWeaponSlot);
pBot->Player->SwitchWeapon(WeaponName);
}
bool ShouldBotThink(AvHAIPlayer* pBot)
{
return IsPlayerActiveInGame(pBot->Edict) && !IsPlayerGestating(pBot->Edict);
}
void BotResumePlay(AvHAIPlayer* pBot)
{
ClearBotMovement(pBot);
SetBaseNavProfile(pBot);
pBot->bIsInactive = false;
}

View file

@ -50,6 +50,7 @@ Vector GetVisiblePointOnPlayerFromObserver(edict_t* Observer, edict_t* TargetPla
void UpdateBotChat(AvHAIPlayer* pBot);
void ClearBotInputs(AvHAIPlayer* pBot);
void StartNewBotFrame(AvHAIPlayer* pBot);
void TestNavThink(AvHAIPlayer* pBot);
@ -57,4 +58,8 @@ void DroneThink(AvHAIPlayer* pBot);
void BotSwitchToWeapon(AvHAIPlayer* pBot, AvHAIWeapon NewWeaponSlot);
bool ShouldBotThink(AvHAIPlayer* pBot);
void BotResumePlay(AvHAIPlayer* pBot);
#endif

View file

@ -5,6 +5,7 @@
#include "AvHAINavigation.h"
#include "AvHAIConfig.h"
#include "AvHAIWeaponHelper.h"
#include "AvHAIHelper.h"
#include "../AvHGamerules.h"
#include "../dlls/client.h"
#include <time.h>
@ -26,6 +27,8 @@ int BotNameIndex = 0;
float AIStartedTime = 0.0f; // Used to give 5-second grace period before adding bots
extern int m_spriteTexture;
string BotNames[MAX_PLAYERS] = { "MrRobot",
"Wall-E",
"BeepBoop",
@ -503,20 +506,33 @@ void AIMGR_UpdateAIPlayers()
{
BotDeltaTime = ThinkDelta;
StartNewBotFrame(bot);
UpdateBotChat(bot);
DroneThink(bot);
AvHAIWeapon DesiredWeapon = (bot->DesiredMoveWeapon != WEAPON_NONE) ? bot->DesiredMoveWeapon : bot->DesiredCombatWeapon;
if (DesiredWeapon != WEAPON_NONE && GetBotCurrentWeapon(bot) != DesiredWeapon)
if (ShouldBotThink(bot))
{
BotSwitchToWeapon(bot, DesiredWeapon);
}
if (bot->bIsInactive)
{
BotResumePlay(bot);
}
BotUpdateDesiredViewRotation(bot);
StartNewBotFrame(bot);
UpdateBotChat(bot);
DroneThink(bot);
AvHAIWeapon DesiredWeapon = (bot->DesiredMoveWeapon != WEAPON_NONE) ? bot->DesiredMoveWeapon : bot->DesiredCombatWeapon;
if (DesiredWeapon != WEAPON_NONE && GetBotCurrentWeapon(bot) != DesiredWeapon)
{
BotSwitchToWeapon(bot, DesiredWeapon);
}
BotUpdateDesiredViewRotation(bot);
}
else
{
ClearBotInputs(bot);
bot->bIsInactive = true;
}
// Needed to correctly handle client prediction and physics calculations
byte adjustedmsec = BotThrottledMsec(bot);
@ -642,6 +658,8 @@ void AIMGR_NewMap()
{
return;
}
AIMGR_BotPrecache();
}
AvHAIPlayer* AIMGR_GetAICommander(AvHTeamNumber Team)
@ -716,4 +734,9 @@ void AIMGR_UpdateAIMapData()
{
UTIL_UpdateTileCache();
AITAC_UpdateMapAIData();
}
void AIMGR_BotPrecache()
{
m_spriteTexture = PRECACHE_MODEL("sprites/zbeam6.spr");
}

View file

@ -9,6 +9,7 @@ static const double BOT_MIN_FRAME_TIME = (1.0 / 60.0);
// At map load / map restart, how long to wait before starting to add bots
static const float AI_GRACE_PERIOD = 5.0f;
void AIMGR_BotPrecache();
// Called when the round restarts. Clears all tactical information but keeps navigation data.
void AIMGR_ResetRound();

View file

@ -206,6 +206,23 @@ float GetPlayerRadius(const AvHPlayer* Player)
}
}
bool CanPlayerCrouch(const edict_t* Player)
{
if (FNullEnt(Player) || Player->free || !IsEdictPlayer(Player)) { return false; }
switch (Player->v.iuser3)
{
case AVH_USER3_ALIEN_PLAYER1:
case AVH_USER3_ALIEN_PLAYER2:
case AVH_USER3_ALIEN_PLAYER3:
return false;
default:
return true;
}
return false;
}
int GetPlayerHullIndex(const edict_t* Player, const bool bIsCrouching)
{
if (!Player) { return 0; }
@ -642,34 +659,36 @@ bool PlayerHasWeapon(const AvHPlayer* Player, const AvHAIWeapon DesiredCombatWea
case WEAPON_LERK_BITE:
case WEAPON_FADE_SWIPE:
case WEAPON_ONOS_GORE:
DesiredWeaponIndex = 0;
DesiredWeaponIndex = 1;
break;
case WEAPON_SKULK_PARASITE:
case WEAPON_GORGE_HEALINGSPRAY:
case WEAPON_LERK_SPORES:
case WEAPON_FADE_BLINK:
case WEAPON_ONOS_DEVOUR:
DesiredWeaponIndex = 1;
DesiredWeaponIndex = 2;
break;
case WEAPON_SKULK_LEAP:
case WEAPON_GORGE_BILEBOMB:
case WEAPON_LERK_UMBRA:
case WEAPON_FADE_METABOLIZE:
case WEAPON_ONOS_STOMP:
DesiredWeaponIndex = 2;
DesiredWeaponIndex = 3;
break;
case WEAPON_SKULK_XENOCIDE:
case WEAPON_GORGE_WEB:
case WEAPON_LERK_PRIMALSCREAM:
case WEAPON_FADE_ACIDROCKET:
case WEAPON_ONOS_CHARGE:
DesiredWeaponIndex = 3;
DesiredWeaponIndex = 4;
break;
default:
DesiredWeaponIndex = -1;
break;
}
if (DesiredWeaponIndex < 0) { return false; }
AvHBasePlayerWeapon* Weapon = dynamic_cast<AvHBasePlayerWeapon*>(Player->m_rgpPlayerItems[DesiredWeaponIndex]);
return (Weapon && Weapon->m_iEnabled);

View file

@ -77,6 +77,8 @@ int GetPlayerMaxArmour(const edict_t* Player);
// Returns the player's current energy (between 0.0 and 1.0)
float GetPlayerEnergy(const edict_t* Player);
// Can the player duck? Skulks, gorges and lerks cannot
bool CanPlayerCrouch(const edict_t* Player);
// Returns player resources (for marines will be team resources)
int GetPlayerResources(const edict_t* Player);

View file

@ -232,7 +232,7 @@ AvHAIBuildableStructure* AITAC_GetNearestDeployableDirectlyReachable(AvHAIPlayer
if (it.second.StructureType & Filter->DeployableTypes)
{
if (!UTIL_PointIsDirectlyReachable(UTIL_GetMoveProfileForBot(pBot, MOVESTYLE_NORMAL), pBot->Edict->v.origin, it.second.Location)) { continue; }
if (!UTIL_PointIsDirectlyReachable(pBot->BotNavInfo.NavProfile, pBot->Edict->v.origin, it.second.Location)) { continue; }
float DistSq = (Filter->bConsiderPhaseDistance) ? sqrf(AITAC_GetPhaseDistanceBetweenPoints(it.second.Location, Location)) : vDist2DSq(it.second.Location, Location);
@ -255,7 +255,7 @@ AvHAIBuildableStructure* AITAC_GetNearestDeployableDirectlyReachable(AvHAIPlayer
if (it.second.StructureType & Filter->DeployableTypes)
{
if (!UTIL_PointIsDirectlyReachable(UTIL_GetMoveProfileForBot(pBot, MOVESTYLE_NORMAL), pBot->Edict->v.origin, it.second.Location)) { continue; }
if (!UTIL_PointIsDirectlyReachable(pBot->BotNavInfo.NavProfile, pBot->Edict->v.origin, it.second.Location)) { continue; }
float DistSq = (Filter->bConsiderPhaseDistance) ? sqrf(AITAC_GetPhaseDistanceBetweenPoints(it.second.Location, Location)) : vDist2DSq(it.second.Location, Location);
@ -338,7 +338,7 @@ Vector AITAC_GetFloorLocationForHive(const AvHAIHiveDefinition* Hive)
FOR_ALL_ENTITIES(kesTeamStart, AvHTeamStartEntity*)
if (NearestNavigableLoc == ZERO_VECTOR)
{
NearestNavigableLoc = FindClosestNavigablePointToDestination(MARINE_REGULAR_NAV_PROFILE, theEntity->pev->origin, HiveFloorLoc, UTIL_MetresToGoldSrcUnits(10.0f));
NearestNavigableLoc = FindClosestNavigablePointToDestination(BaseNavProfiles[MARINE_BASE_NAV_PROFILE], theEntity->pev->origin, HiveFloorLoc, UTIL_MetresToGoldSrcUnits(10.0f));
}
END_FOR_ALL_ENTITIES(kesTeamStart);
@ -493,9 +493,9 @@ void AITAC_RefreshResourceNodes()
ResourceNodes[NumTotalResNodes].Location = theEntity->pev->origin;
ResourceNodes[NumTotalResNodes].ReachabilityFlags = AI_REACHABILITY_NONE;
bool bIsReachableMarine = UTIL_PointIsReachable(MARINE_REGULAR_NAV_PROFILE, AITAC_GetTeamStartingLocation(GetGameRules()->GetTeamANumber()), ResourceNodes[NumTotalResNodes].Location, max_player_use_reach);
bool bIsReachableSkulk = UTIL_PointIsReachable(SKULK_REGULAR_NAV_PROFILE, AITAC_GetTeamStartingLocation(GetGameRules()->GetTeamANumber()), ResourceNodes[NumTotalResNodes].Location, max_player_use_reach);
bool bIsReachableOnos = UTIL_PointIsReachable(ONOS_REGULAR_NAV_PROFILE, AITAC_GetTeamStartingLocation(GetGameRules()->GetTeamANumber()), ResourceNodes[NumTotalResNodes].Location, max_player_use_reach);
bool bIsReachableMarine = UTIL_PointIsReachable(BaseNavProfiles[MARINE_BASE_NAV_PROFILE], AITAC_GetTeamStartingLocation(GetGameRules()->GetTeamANumber()), ResourceNodes[NumTotalResNodes].Location, max_player_use_reach);
bool bIsReachableSkulk = UTIL_PointIsReachable(BaseNavProfiles[SKULK_BASE_NAV_PROFILE], AITAC_GetTeamStartingLocation(GetGameRules()->GetTeamANumber()), ResourceNodes[NumTotalResNodes].Location, max_player_use_reach);
bool bIsReachableOnos = UTIL_PointIsReachable(BaseNavProfiles[ONOS_BASE_NAV_PROFILE], AITAC_GetTeamStartingLocation(GetGameRules()->GetTeamANumber()), ResourceNodes[NumTotalResNodes].Location, max_player_use_reach);
if (bIsReachableMarine)
{
@ -861,11 +861,11 @@ void AITAC_UpdateMarineItem(CBaseEntity* Item, AvHAIDeployableItemType ItemType)
}
else
{
MarineDroppedItemMap[EntIndex].bOnNavMesh = UTIL_PointIsOnNavmesh(MARINE_REGULAR_NAV_PROFILE, ItemEdict->v.origin, Vector(max_player_use_reach, max_player_use_reach, max_player_use_reach));
MarineDroppedItemMap[EntIndex].bOnNavMesh = UTIL_PointIsOnNavmesh(BaseNavProfiles[MARINE_BASE_NAV_PROFILE], ItemEdict->v.origin, Vector(max_player_use_reach, max_player_use_reach, max_player_use_reach));
if (MarineDroppedItemMap[EntIndex].bOnNavMesh)
{
MarineDroppedItemMap[EntIndex].bIsReachableMarine = UTIL_PointIsReachable(MARINE_REGULAR_NAV_PROFILE, AITAC_GetTeamStartingLocation(GetGameRules()->GetTeamANumber()), ItemEdict->v.origin, max_player_use_reach);
MarineDroppedItemMap[EntIndex].bIsReachableMarine = UTIL_PointIsReachable(BaseNavProfiles[MARINE_BASE_NAV_PROFILE], AITAC_GetTeamStartingLocation(GetGameRules()->GetTeamANumber()), ItemEdict->v.origin, max_player_use_reach);
}
else
{
@ -937,7 +937,7 @@ void AITAC_UpdateBuildableStructure(CBaseEntity* Structure)
if (bShouldCollide)
{
unsigned int area = UTIL_GetAreaForObstruction(StructureType);
unsigned int area = UTIL_GetAreaForObstruction(StructureType, BuildingEdict);
float Radius = UTIL_GetStructureRadiusForObstruction(StructureType);
UTIL_AddTemporaryObstacles(UTIL_GetCentreOfEntity(BuildingMap[EntIndex].edict), Radius, 100.0f, area, BuildingMap[EntIndex].ObstacleRefs);
}
@ -953,12 +953,12 @@ void AITAC_UpdateBuildableStructure(CBaseEntity* Structure)
if (vIsZero(BuildingMap[EntIndex].Location) || !vEquals(BaseBuildable->pev->origin, BuildingMap[EntIndex].Location, 5.0f))
{
bool bIsOnNavMesh = UTIL_PointIsOnNavmesh(MARINE_REGULAR_NAV_PROFILE, UTIL_GetEntityGroundLocation(BuildingEdict), Vector(max_player_use_reach, max_player_use_reach, max_player_use_reach));
bool bIsOnNavMesh = UTIL_PointIsOnNavmesh(BaseNavProfiles[MARINE_BASE_NAV_PROFILE], UTIL_GetEntityGroundLocation(BuildingEdict), Vector(max_player_use_reach, max_player_use_reach, max_player_use_reach));
if (bIsOnNavMesh)
{
bool bIsReachableMarine = UTIL_PointIsReachable(MARINE_REGULAR_NAV_PROFILE, AITAC_GetTeamStartingLocation(GetGameRules()->GetTeamANumber()), UTIL_GetEntityGroundLocation(BuildingEdict), max_player_use_reach);
bool bIsReachableSkulk = UTIL_PointIsReachable(SKULK_REGULAR_NAV_PROFILE, AITAC_GetTeamStartingLocation(GetGameRules()->GetTeamANumber()), UTIL_GetEntityGroundLocation(BuildingEdict), max_player_use_reach);
bool bIsReachableOnos = UTIL_PointIsReachable(ONOS_REGULAR_NAV_PROFILE, AITAC_GetTeamStartingLocation(GetGameRules()->GetTeamANumber()), UTIL_GetEntityGroundLocation(BuildingEdict), max_player_use_reach);
bool bIsReachableMarine = UTIL_PointIsReachable(BaseNavProfiles[MARINE_BASE_NAV_PROFILE], AITAC_GetTeamStartingLocation(GetGameRules()->GetTeamANumber()), UTIL_GetEntityGroundLocation(BuildingEdict), max_player_use_reach);
bool bIsReachableSkulk = UTIL_PointIsReachable(BaseNavProfiles[SKULK_BASE_NAV_PROFILE], AITAC_GetTeamStartingLocation(GetGameRules()->GetTeamANumber()), UTIL_GetEntityGroundLocation(BuildingEdict), max_player_use_reach);
bool bIsReachableOnos = UTIL_PointIsReachable(BaseNavProfiles[ONOS_BASE_NAV_PROFILE], AITAC_GetTeamStartingLocation(GetGameRules()->GetTeamANumber()), UTIL_GetEntityGroundLocation(BuildingEdict), max_player_use_reach);
if (bIsReachableMarine)
{
@ -1237,10 +1237,15 @@ AvHAIDeployableStructureType UTIL_IUSER3ToStructureType(const int inIUSER3)
}
unsigned char UTIL_GetAreaForObstruction(AvHAIDeployableStructureType StructureType)
unsigned char UTIL_GetAreaForObstruction(AvHAIDeployableStructureType StructureType, const edict_t* BuildingEdict)
{
if (StructureType == STRUCTURE_NONE) { return DT_TILECACHE_NULL_AREA; }
AvHTeamNumber TeamA = GetGameRules()->GetTeamANumber();
AvHTeamNumber TeamB = GetGameRules()->GetTeamBNumber();
unsigned char StructureArea = (BuildingEdict->v.team == TeamA) ? DT_TILECACHE_TEAM1STRUCTURE_AREA : DT_TILECACHE_TEAM2STRUCTURE_AREA;
switch (StructureType)
{
case STRUCTURE_MARINE_RESTOWER:
@ -1248,10 +1253,9 @@ unsigned char UTIL_GetAreaForObstruction(AvHAIDeployableStructureType StructureT
case STRUCTURE_MARINE_ARMOURY:
case STRUCTURE_MARINE_ADVARMOURY:
case STRUCTURE_MARINE_OBSERVATORY:
return DT_TILECACHE_MSTRUCTURE_AREA;
case STRUCTURE_ALIEN_RESTOWER:
case STRUCTURE_ALIEN_HIVE:
return DT_TILECACHE_ASTRUCTURE_AREA;
return StructureArea;
default:
return DT_TILECACHE_BLOCKED_AREA;
}
@ -1342,9 +1346,7 @@ bool UTIL_IsBuildableStructureStillReachable(AvHAIPlayer* pBot, const edict_t* S
if (!StructureRef) { return false; }
int MoveProfile = UTIL_GetMoveProfileForBot(pBot, MOVESTYLE_NORMAL);
return (StructureRef->ReachabilityFlags & UTIL_GetReachabilityFlagForProfile(MoveProfile)) != 0;
return (StructureRef->ReachabilityFlags & pBot->BotNavInfo.NavProfile.ReachabilityFlag) != 0;
}
bool UTIL_IsDroppedItemStillReachable(AvHAIPlayer* pBot, const edict_t* Item)
@ -1759,7 +1761,7 @@ Vector UTIL_GetNextMinePosition(edict_t* StructureToMine)
}
}
Vector BuildLocation = UTIL_GetRandomPointOnNavmeshInDonut(MARINE_REGULAR_NAV_PROFILE, StructureToMine->v.origin, Size, Size + 16.0f);
Vector BuildLocation = UTIL_GetRandomPointOnNavmeshInDonut(BaseNavProfiles[MARINE_BASE_NAV_PROFILE], StructureToMine->v.origin, Size, Size + 16.0f);
return BuildLocation;
}

View file

@ -79,7 +79,7 @@ AvHAIDeployableStructureType UTIL_IUSER3ToStructureType(const int inIUSER3);
bool UTIL_ShouldStructureCollide(AvHAIDeployableStructureType StructureType);
float UTIL_GetStructureRadiusForObstruction(AvHAIDeployableStructureType StructureType);
unsigned char UTIL_GetAreaForObstruction(AvHAIDeployableStructureType StructureType);
unsigned char UTIL_GetAreaForObstruction(AvHAIDeployableStructureType StructureType, const edict_t* BuildingEdict);
bool UTIL_IsStructureElectrified(edict_t* Structure);
bool UTIL_StructureIsFullyBuilt(edict_t* Structure);

View file

@ -385,14 +385,14 @@ bool AITASK_IsWeldTaskStillValid(AvHAIPlayer* pBot, AvHAIPlayerTask* Task)
if (IsEdictPlayer(Task->TaskTarget))
{
if (!IsPlayerMarine(Task->TaskTarget) || !IsPlayerActiveInGame(Task->TaskTarget)) { return false; }
if (Task->TaskTarget->v.team != pBot->Edict->v.team || !IsPlayerMarine(Task->TaskTarget) || !IsPlayerActiveInGame(Task->TaskTarget)) { return false; }
return (Task->TaskTarget->v.armorvalue < GetPlayerMaxArmour(Task->TaskTarget));
}
else
{
if (IsEdictStructure(Task->TaskTarget))
{
if (!UTIL_IsBuildableStructureStillReachable(pBot, Task->TaskTarget)) { return false; }
if (Task->TaskTarget->v.team != pBot->Edict->v.team || !UTIL_IsBuildableStructureStillReachable(pBot, Task->TaskTarget)) { return false; }
return (Task->TaskTarget->v.health < Task->TaskTarget->v.max_health);
}
@ -1064,7 +1064,7 @@ void BotProgressMineStructureTask(AvHAIPlayer* pBot, AvHAIPlayerTask* Task)
if (Task->BuildAttempts > 3)
{
float Size = fmaxf(Task->TaskTarget->v.size.x, Task->TaskTarget->v.size.y);
Task->TaskLocation = UTIL_GetRandomPointOnNavmeshInRadius(BUILDING_REGULAR_NAV_PROFILE, Task->TaskTarget->v.origin, Size + 8.0f);
Task->TaskLocation = UTIL_GetRandomPointOnNavmeshInRadius(BaseNavProfiles[STRUCTURE_BASE_NAV_PROFILE], Task->TaskTarget->v.origin, Size + 8.0f);
}
else
{
@ -1318,7 +1318,7 @@ void BotProgressReinforceStructureTask(AvHAIPlayer* pBot, AvHAIPlayerTask* Task)
if (Task->TaskLocation != g_vecZero)
{
dtPolyRef Poly = UTIL_GetNavAreaAtLocation(BUILDING_REGULAR_NAV_PROFILE, Task->TaskLocation);
dtPolyRef Poly = UTIL_GetNavAreaAtLocation(BaseNavProfiles[STRUCTURE_BASE_NAV_PROFILE], Task->TaskLocation);
if (Poly != SAMPLE_POLYAREA_GROUND)
{
@ -1332,7 +1332,7 @@ void BotProgressReinforceStructureTask(AvHAIPlayer* pBot, AvHAIPlayerTask* Task)
Vector TargetLocation = (ReinforcedStructure == STRUCTURE_ALIEN_HIVE) ? UTIL_GetFloorUnderEntity(Task->TaskTarget) : Task->TaskTarget->v.origin;
Vector BuildLocation = FindClosestNavigablePointToDestination(MARINE_REGULAR_NAV_PROFILE, AITAC_GetTeamStartingLocation(GetGameRules()->GetTeamANumber()), TargetLocation, UTIL_MetresToGoldSrcUnits(50.0f));
Vector BuildLocation = FindClosestNavigablePointToDestination(BaseNavProfiles[MARINE_BASE_NAV_PROFILE], AITAC_GetTeamStartingLocation(GetGameRules()->GetTeamANumber()), TargetLocation, UTIL_MetresToGoldSrcUnits(50.0f));
if (BuildLocation != g_vecZero)
{
@ -1340,7 +1340,7 @@ void BotProgressReinforceStructureTask(AvHAIPlayer* pBot, AvHAIPlayerTask* Task)
float MaxDist = fmaxf(UTIL_MetresToGoldSrcUnits(1.0f), (UTIL_MetresToGoldSrcUnits(5.0f) - currDist));
Task->TaskLocation = UTIL_GetRandomPointOnNavmeshInRadius(GORGE_BUILD_NAV_PROFILE, BuildLocation, MaxDist);
Task->TaskLocation = UTIL_GetRandomPointOnNavmeshInRadius(BaseNavProfiles[GORGE_BASE_NAV_PROFILE], BuildLocation, MaxDist);
}
if (vIsZero(Task->TaskLocation)) { return; }
@ -1640,11 +1640,11 @@ void BotProgressEvolveTask(AvHAIPlayer* pBot, AvHAIPlayerTask* Task)
{
if ((gpGlobals->time - Task->TaskStartedTime) > 1.0f)
{
Task->TaskLocation = UTIL_GetRandomPointOnNavmeshInRadius(BUILDING_REGULAR_NAV_PROFILE, pBot->Edict->v.origin, UTIL_MetresToGoldSrcUnits(5.0f));
Task->TaskLocation = UTIL_GetRandomPointOnNavmeshInRadius(BaseNavProfiles[STRUCTURE_BASE_NAV_PROFILE], pBot->Edict->v.origin, UTIL_MetresToGoldSrcUnits(5.0f));
if (vIsZero(Task->TaskLocation))
{
Task->TaskLocation = UTIL_GetRandomPointOnNavmeshInRadius(GORGE_REGULAR_NAV_PROFILE, pBot->Edict->v.origin, UTIL_MetresToGoldSrcUnits(5.0f));
Task->TaskLocation = UTIL_GetRandomPointOnNavmeshInRadius(BaseNavProfiles[GORGE_BASE_NAV_PROFILE], pBot->Edict->v.origin, UTIL_MetresToGoldSrcUnits(5.0f));
}
Task->TaskStartedTime = 0.0f;
@ -1675,14 +1675,14 @@ void BotProgressEvolveTask(AvHAIPlayer* pBot, AvHAIPlayerTask* Task)
}
else
{
if (vDist2DSq(pBot->Edict->v.origin, UTIL_GetEntityGroundLocation(Task->TaskTarget)) > sqrf(UTIL_MetresToGoldSrcUnits(10.0f)) || UTIL_GetNavAreaAtLocation(GORGE_BUILD_NAV_PROFILE, pBot->Edict->v.origin) != SAMPLE_POLYAREA_GROUND)
if (vDist2DSq(pBot->Edict->v.origin, UTIL_GetEntityGroundLocation(Task->TaskTarget)) > sqrf(UTIL_MetresToGoldSrcUnits(10.0f)) || UTIL_GetNavAreaAtLocation(BaseNavProfiles[GORGE_BASE_NAV_PROFILE], pBot->Edict->v.origin) != SAMPLE_POLYAREA_GROUND)
{
MoveTo(pBot, UTIL_GetEntityGroundLocation(Task->TaskTarget), MOVESTYLE_NORMAL);
return;
}
else
{
Task->TaskLocation = FindClosestNavigablePointToDestination(GORGE_BUILD_NAV_PROFILE, pBot->Edict->v.origin, UTIL_GetEntityGroundLocation(Task->TaskTarget), UTIL_MetresToGoldSrcUnits(10.0f));
Task->TaskLocation = FindClosestNavigablePointToDestination(BaseNavProfiles[GORGE_BASE_NAV_PROFILE], pBot->Edict->v.origin, UTIL_GetEntityGroundLocation(Task->TaskTarget), UTIL_MetresToGoldSrcUnits(10.0f));
if (vIsZero(Task->TaskLocation))
{
@ -1691,7 +1691,7 @@ void BotProgressEvolveTask(AvHAIPlayer* pBot, AvHAIPlayerTask* Task)
if (Task->TaskLocation != g_vecZero)
{
Vector FinalEvolveLoc = UTIL_GetRandomPointOnNavmeshInRadius(GORGE_BUILD_NAV_PROFILE, Task->TaskLocation, UTIL_MetresToGoldSrcUnits(5.0f));
Vector FinalEvolveLoc = UTIL_GetRandomPointOnNavmeshInRadius(BaseNavProfiles[GORGE_BASE_NAV_PROFILE], Task->TaskLocation, UTIL_MetresToGoldSrcUnits(5.0f));
if (FinalEvolveLoc != g_vecZero)
{
@ -1777,7 +1777,7 @@ void AlienProgressBuildHiveTask(AvHAIPlayer* pBot, AvHAIPlayerTask* Task)
if (Task->bIsWaitingForBuildLink)
{
Task->TaskLocation = FindClosestNavigablePointToDestination(GORGE_REGULAR_NAV_PROFILE, pBot->Edict->v.origin, Hive->FloorLocation, UTIL_MetresToGoldSrcUnits(7.5f));
Task->TaskLocation = FindClosestNavigablePointToDestination(BaseNavProfiles[GORGE_BASE_NAV_PROFILE], pBot->Edict->v.origin, Hive->FloorLocation, UTIL_MetresToGoldSrcUnits(7.5f));
if (vIsZero(Task->TaskLocation))
{
@ -1789,7 +1789,7 @@ void AlienProgressBuildHiveTask(AvHAIPlayer* pBot, AvHAIPlayerTask* Task)
float MaxDist = (UTIL_MetresToGoldSrcUnits(7.5f) - Dist);
Vector AltLocation = UTIL_GetRandomPointOnNavmeshInRadius(GORGE_REGULAR_NAV_PROFILE, Task->TaskLocation, MaxDist);
Vector AltLocation = UTIL_GetRandomPointOnNavmeshInRadius(BaseNavProfiles[GORGE_BASE_NAV_PROFILE], Task->TaskLocation, MaxDist);
if (AltLocation != g_vecZero)
{
@ -1899,18 +1899,18 @@ void AlienProgressBuildTask(AvHAIPlayer* pBot, AvHAIPlayerTask* Task)
if (Task->bIsWaitingForBuildLink)
{
Task->TaskLocation = UTIL_GetRandomPointOnNavmeshInRadius(GORGE_BUILD_NAV_PROFILE, Task->TaskLocation, UTIL_MetresToGoldSrcUnits(2.0f));
Task->TaskLocation = UTIL_GetRandomPointOnNavmeshInRadius(BaseNavProfiles[GORGE_BASE_NAV_PROFILE], Task->TaskLocation, UTIL_MetresToGoldSrcUnits(2.0f));
Task->bIsWaitingForBuildLink = false;
}
// If we are building a chamber
if (Task->StructureType != STRUCTURE_ALIEN_RESTOWER)
{
dtPolyRef Poly = UTIL_GetNavAreaAtLocation(BUILDING_REGULAR_NAV_PROFILE, Task->TaskLocation);
dtPolyRef Poly = UTIL_GetNavAreaAtLocation(BaseNavProfiles[STRUCTURE_BASE_NAV_PROFILE], Task->TaskLocation);
if (Poly != SAMPLE_POLYAREA_GROUND)
{
Vector NewLocation = UTIL_GetRandomPointOnNavmeshInRadius(BUILDING_REGULAR_NAV_PROFILE, Task->TaskLocation, UTIL_MetresToGoldSrcUnits(2.0f));
Vector NewLocation = UTIL_GetRandomPointOnNavmeshInRadius(BaseNavProfiles[STRUCTURE_BASE_NAV_PROFILE], Task->TaskLocation, UTIL_MetresToGoldSrcUnits(2.0f));
if (NewLocation != g_vecZero)
{
@ -2416,7 +2416,7 @@ void BotGuardLocation(AvHAIPlayer* pBot, const Vector GuardLocation)
}
else
{
pBot->GuardInfo.GuardLookLocation = UTIL_GetRandomPointOnNavmeshInRadius(SKULK_REGULAR_NAV_PROFILE, pBot->Edict->v.origin, UTIL_MetresToGoldSrcUnits(5.0f));
pBot->GuardInfo.GuardLookLocation = UTIL_GetRandomPointOnNavmeshInRadius(BaseNavProfiles[SKULK_BASE_NAV_PROFILE], pBot->Edict->v.origin, UTIL_MetresToGoldSrcUnits(5.0f));
pBot->GuardInfo.GuardLookLocation.z = pBot->CurrentEyePosition.z;
}
@ -2425,7 +2425,7 @@ void BotGuardLocation(AvHAIPlayer* pBot, const Vector GuardLocation)
Vector NewMoveCentre = GuardLocation - (LookDir * UTIL_MetresToGoldSrcUnits(2.0f));
Vector NewMoveLoc = UTIL_GetRandomPointOnNavmeshInRadius(MARINE_REGULAR_NAV_PROFILE, NewMoveCentre, UTIL_MetresToGoldSrcUnits(2.0f));
Vector NewMoveLoc = UTIL_GetRandomPointOnNavmeshInRadius(BaseNavProfiles[MARINE_BASE_NAV_PROFILE], NewMoveCentre, UTIL_MetresToGoldSrcUnits(2.0f));
if (NewMoveLoc != g_vecZero)
{
@ -2471,7 +2471,7 @@ void AITASK_GenerateGuardWatchPoints(AvHAIPlayer* pBot, const Vector& GuardLocat
bool bEnemyIsAlien = GetGameRules()->GetTeam(EnemyTeam)->GetTeamType() == AVH_CLASS_TYPE_ALIEN;
int MoveProfileIndex = (bEnemyIsAlien) ? SKULK_REGULAR_NAV_PROFILE : MARINE_REGULAR_NAV_PROFILE;
const nav_profile NavProfile = (bEnemyIsAlien) ? BaseNavProfiles[SKULK_BASE_NAV_PROFILE] : BaseNavProfiles[MARINE_BASE_NAV_PROFILE];
bot_path_node path[MAX_AI_PATH_SIZE];
int pathSize = 0;
@ -2485,7 +2485,7 @@ void AITASK_GenerateGuardWatchPoints(AvHAIPlayer* pBot, const Vector& GuardLocat
if (UTIL_QuickTrace(pEdict, GuardLocation + Vector(0.0f, 0.0f, 10.0f), Hive->Location) || vDist2DSq(GuardLocation, Hive->Location) < sqrf(UTIL_MetresToGoldSrcUnits(10.0f))) { continue; }
dtStatus SearchResult = FindPathClosestToPoint(MoveProfileIndex, Hive->FloorLocation, GuardLocation, path, &pathSize, 500.0f);
dtStatus SearchResult = FindPathClosestToPoint(NavProfile, Hive->FloorLocation, GuardLocation, path, &pathSize, 500.0f);
if (dtStatusSucceed(SearchResult))
{
@ -2498,7 +2498,7 @@ void AITASK_GenerateGuardWatchPoints(AvHAIPlayer* pBot, const Vector& GuardLocat
}
}
dtStatus SearchResult = FindPathClosestToPoint(MoveProfileIndex, AITAC_GetTeamStartingLocation(EnemyTeam), GuardLocation, path, &pathSize, 500.0f);
dtStatus SearchResult = FindPathClosestToPoint(NavProfile, AITAC_GetTeamStartingLocation(EnemyTeam), GuardLocation, path, &pathSize, 500.0f);
if (dtStatusSucceed(SearchResult))
{
@ -2512,7 +2512,7 @@ void AITASK_GenerateGuardWatchPoints(AvHAIPlayer* pBot, const Vector& GuardLocat
if (vDist2DSq(GuardLocation, AITAC_GetTeamStartingLocation(pBot->Player->GetTeam())) > sqrf(UTIL_MetresToGoldSrcUnits(15.0f)))
{
dtStatus SearchResult = FindPathClosestToPoint(MoveProfileIndex, AITAC_GetTeamStartingLocation(pBot->Player->GetTeam()), GuardLocation, path, &pathSize, 500.0f);
dtStatus SearchResult = FindPathClosestToPoint(NavProfile, AITAC_GetTeamStartingLocation(pBot->Player->GetTeam()), GuardLocation, path, &pathSize, 500.0f);
if (dtStatusSucceed(SearchResult))
{
@ -2658,6 +2658,7 @@ void AITASK_SetWeldTask(AvHAIPlayer* pBot, AvHAIPlayerTask* Task, edict_t* Targe
Task->TaskTarget = Target;
Task->TaskType = TASK_WELD;
Task->bTaskIsUrgent = bIsUrgent;
Task->TaskLength = 0.0f;
if (IsEdictPlayer(Target) || IsEdictStructure(Target)) { return; }
@ -2668,9 +2669,7 @@ void AITASK_SetWeldTask(AvHAIPlayer* pBot, AvHAIPlayerTask* Task, edict_t* Targe
TargetLocation = Task->TaskTarget->v.origin;
}
int MoveProfile = UTIL_GetMoveProfileForBot(pBot, MOVESTYLE_NORMAL);
Vector TaskLocation = FindClosestNavigablePointToDestination(MoveProfile, pBot->Edict->v.origin, TargetLocation, UTIL_MetresToGoldSrcUnits(5.0f));
Vector TaskLocation = FindClosestNavigablePointToDestination(pBot->BotNavInfo.NavProfile, pBot->Edict->v.origin, TargetLocation, UTIL_MetresToGoldSrcUnits(5.0f));
if (vIsZero(TaskLocation))
{
@ -2709,10 +2708,8 @@ void AITASK_SetAttackTask(AvHAIPlayer* pBot, AvHAIPlayerTask* Task, edict_t* Tar
return;
}
int BotProfile = UTIL_GetMoveProfileForBot(pBot, MOVESTYLE_NORMAL);
// Get as close as possible to the target
Vector AttackLocation = FindClosestNavigablePointToDestination(BotProfile, pBot->CurrentFloorPosition, UTIL_GetEntityGroundLocation(Target), UTIL_MetresToGoldSrcUnits(20.0f));
Vector AttackLocation = FindClosestNavigablePointToDestination(pBot->BotNavInfo.NavProfile, pBot->CurrentFloorPosition, UTIL_GetEntityGroundLocation(Target), UTIL_MetresToGoldSrcUnits(20.0f));
if (AttackLocation != g_vecZero)
{
@ -2736,10 +2733,8 @@ void AITASK_SetMoveTask(AvHAIPlayer* pBot, AvHAIPlayerTask* Task, const Vector L
if (vIsZero(Location)) { return; }
int BotProfile = UTIL_GetMoveProfileForBot(pBot, MOVESTYLE_NORMAL);
// Get as close as possible to desired location
Vector MoveLocation = FindClosestNavigablePointToDestination(BotProfile, pBot->CurrentFloorPosition, Location, UTIL_MetresToGoldSrcUnits(20.0f));
Vector MoveLocation = FindClosestNavigablePointToDestination(pBot->BotNavInfo.NavProfile, pBot->CurrentFloorPosition, Location, UTIL_MetresToGoldSrcUnits(20.0f));
if (!vIsZero(MoveLocation))
{
@ -2760,12 +2755,12 @@ void AITASK_SetBuildTask(AvHAIPlayer* pBot, AvHAIPlayerTask* Task, const AvHAIDe
if (vIsZero(Location)) { return; }
// Get as close as possible to desired location
Vector BuildLocation = FindClosestNavigablePointToDestination(GORGE_REGULAR_NAV_PROFILE, AITAC_GetTeamStartingLocation(pBot->Player->GetTeam()), Location, UTIL_MetresToGoldSrcUnits(10.0f));
BuildLocation = UTIL_ProjectPointToNavmesh(BuildLocation, BUILDING_REGULAR_NAV_PROFILE);
Vector BuildLocation = FindClosestNavigablePointToDestination(BaseNavProfiles[GORGE_BASE_NAV_PROFILE], AITAC_GetTeamStartingLocation(pBot->Player->GetTeam()), Location, UTIL_MetresToGoldSrcUnits(10.0f));
BuildLocation = UTIL_ProjectPointToNavmesh(BuildLocation, BaseNavProfiles[STRUCTURE_BASE_NAV_PROFILE]);
if (vIsZero(BuildLocation))
{
BuildLocation = FindClosestNavigablePointToDestination(UTIL_GetMoveProfileForBot(pBot, MOVESTYLE_NORMAL), pBot->CurrentFloorPosition, Location, UTIL_MetresToGoldSrcUnits(10.0f));
BuildLocation = FindClosestNavigablePointToDestination(pBot->BotNavInfo.NavProfile, pBot->CurrentFloorPosition, Location, UTIL_MetresToGoldSrcUnits(10.0f));
}
if (BuildLocation != g_vecZero)
@ -2804,10 +2799,8 @@ void AITASK_SetBuildTask(AvHAIPlayer* pBot, AvHAIPlayerTask* Task, edict_t* Stru
if (Task->TaskType == TASK_BUILD && Task->TaskTarget == StructureToBuild) { return; }
int BotProfile = UTIL_GetMoveProfileForBot(pBot, MOVESTYLE_NORMAL);
// Get as close as possible to desired location
Vector BuildLocation = FindClosestNavigablePointToDestination(BotProfile, pBot->CurrentFloorPosition, UTIL_GetEntityGroundLocation(StructureToBuild), 80.0f);
Vector BuildLocation = FindClosestNavigablePointToDestination(pBot->BotNavInfo.NavProfile, pBot->CurrentFloorPosition, UTIL_GetEntityGroundLocation(StructureToBuild), 80.0f);
if (BuildLocation != g_vecZero)
{
@ -2863,9 +2856,7 @@ void AITASK_SetDefendTask(AvHAIPlayer* pBot, AvHAIPlayerTask* Task, edict_t* Tar
Task->TaskTarget = Target;
Task->bTaskIsUrgent = bIsUrgent;
int MoveProfile = UTIL_GetMoveProfileForBot(pBot, MOVESTYLE_NORMAL);
Vector DefendPoint = FindClosestNavigablePointToDestination(MoveProfile, pBot->CurrentFloorPosition, UTIL_GetEntityGroundLocation(Target), UTIL_MetresToGoldSrcUnits(10.0f));
Vector DefendPoint = FindClosestNavigablePointToDestination(pBot->BotNavInfo.NavProfile, pBot->CurrentFloorPosition, UTIL_GetEntityGroundLocation(Target), UTIL_MetresToGoldSrcUnits(10.0f));
if (DefendPoint != g_vecZero)
{
@ -2931,11 +2922,9 @@ void AITASK_SetUseTask(AvHAIPlayer* pBot, AvHAIPlayerTask* Task, edict_t* Target
return;
}
int MoveProfile = UTIL_GetMoveProfileForBot(pBot, MOVESTYLE_NORMAL);
Task->TaskType = TASK_USE;
Task->TaskTarget = Target;
Task->TaskLocation = FindClosestNavigablePointToDestination(MoveProfile, pBot->CurrentFloorPosition, UTIL_ProjectPointToNavmesh(UTIL_GetCentreOfEntity(Target)), UTIL_MetresToGoldSrcUnits(10.0f));
Task->TaskLocation = FindClosestNavigablePointToDestination(pBot->BotNavInfo.NavProfile, pBot->CurrentFloorPosition, UTIL_ProjectPointToNavmesh(UTIL_GetCentreOfEntity(Target)), UTIL_MetresToGoldSrcUnits(10.0f));
Task->bTaskIsUrgent = bIsUrgent;
Task->TaskLength = 10.0f;
Task->TaskStartedTime = gpGlobals->time;
@ -2949,11 +2938,9 @@ void AITASK_SetUseTask(AvHAIPlayer* pBot, AvHAIPlayerTask* Task, edict_t* Target
return;
}
int MoveProfile = UTIL_GetMoveProfileForBot(pBot, MOVESTYLE_NORMAL);
Task->TaskType = TASK_USE;
Task->TaskTarget = Target;
Task->TaskLocation = FindClosestNavigablePointToDestination(MoveProfile, pBot->CurrentFloorPosition, UseLocation, UTIL_MetresToGoldSrcUnits(10.0f));
Task->TaskLocation = FindClosestNavigablePointToDestination(pBot->BotNavInfo.NavProfile, pBot->CurrentFloorPosition, UseLocation, UTIL_MetresToGoldSrcUnits(10.0f));
Task->bTaskIsUrgent = bIsUrgent;
Task->TaskLength = 10.0f;
Task->TaskStartedTime = gpGlobals->time;
@ -2967,11 +2954,9 @@ void AITASK_SetTouchTask(AvHAIPlayer* pBot, AvHAIPlayerTask* Task, edict_t* Targ
return;
}
int MoveProfile = UTIL_GetMoveProfileForBot(pBot, MOVESTYLE_NORMAL);
Task->TaskType = TASK_TOUCH;
Task->TaskTarget = Target;
Task->TaskLocation = FindClosestNavigablePointToDestination(MoveProfile, pBot->CurrentFloorPosition, UTIL_ProjectPointToNavmesh(UTIL_GetCentreOfEntity(Target)), UTIL_MetresToGoldSrcUnits(10.0f));
Task->TaskLocation = FindClosestNavigablePointToDestination(pBot->BotNavInfo.NavProfile, pBot->CurrentFloorPosition, UTIL_ProjectPointToNavmesh(UTIL_GetCentreOfEntity(Target)), UTIL_MetresToGoldSrcUnits(10.0f));
Task->bTaskIsUrgent = bIsUrgent;
}

View file

@ -164,7 +164,7 @@ void InterruptReload(AvHAIPlayer* pBot)
AvHAIWeapon UTIL_GetBotPrimaryWeapon(const AvHAIPlayer* pBot)
{
AvHBasePlayerWeapon* Weapon = dynamic_cast<AvHBasePlayerWeapon*>(pBot->Player->m_rgpPlayerItems[0]);
AvHBasePlayerWeapon* Weapon = dynamic_cast<AvHBasePlayerWeapon*>(pBot->Player->m_rgpPlayerItems[1]);
if (Weapon)
{
@ -205,7 +205,7 @@ AvHAIWeapon GetBotMarineSecondaryWeapon(const AvHAIPlayer* pBot)
int BotGetPrimaryWeaponMaxAmmoReserve(AvHAIPlayer* pBot)
{
AvHBasePlayerWeapon* theBasePlayerWeapon = dynamic_cast<AvHBasePlayerWeapon*>(pBot->Player->m_rgpPlayerItems[0]);
AvHBasePlayerWeapon* theBasePlayerWeapon = dynamic_cast<AvHBasePlayerWeapon*>(pBot->Player->m_rgpPlayerItems[1]);
if (theBasePlayerWeapon)
{
@ -217,7 +217,7 @@ int BotGetPrimaryWeaponMaxAmmoReserve(AvHAIPlayer* pBot)
int BotGetPrimaryWeaponAmmoReserve(AvHAIPlayer* pBot)
{
AvHBasePlayerWeapon* theBasePlayerWeapon = dynamic_cast<AvHBasePlayerWeapon*>(pBot->Player->m_rgpPlayerItems[0]);
AvHBasePlayerWeapon* theBasePlayerWeapon = dynamic_cast<AvHBasePlayerWeapon*>(pBot->Player->m_rgpPlayerItems[1]);
if (theBasePlayerWeapon)
{
@ -229,7 +229,7 @@ int BotGetPrimaryWeaponAmmoReserve(AvHAIPlayer* pBot)
int BotGetSecondaryWeaponAmmoReserve(AvHAIPlayer* pBot)
{
AvHBasePlayerWeapon* theBasePlayerWeapon = dynamic_cast<AvHBasePlayerWeapon*>(pBot->Player->m_rgpPlayerItems[1]);
AvHBasePlayerWeapon* theBasePlayerWeapon = dynamic_cast<AvHBasePlayerWeapon*>(pBot->Player->m_rgpPlayerItems[2]);
if (theBasePlayerWeapon)
{
@ -241,7 +241,7 @@ int BotGetSecondaryWeaponAmmoReserve(AvHAIPlayer* pBot)
int BotGetPrimaryWeaponClipAmmo(const AvHAIPlayer* pBot)
{
AvHBasePlayerWeapon* theBasePlayerWeapon = dynamic_cast<AvHBasePlayerWeapon*>(pBot->Player->m_rgpPlayerItems[0]);
AvHBasePlayerWeapon* theBasePlayerWeapon = dynamic_cast<AvHBasePlayerWeapon*>(pBot->Player->m_rgpPlayerItems[1]);
if (theBasePlayerWeapon)
{
@ -253,7 +253,7 @@ int BotGetPrimaryWeaponClipAmmo(const AvHAIPlayer* pBot)
int BotGetSecondaryWeaponClipAmmo(const AvHAIPlayer* pBot)
{
AvHBasePlayerWeapon* theBasePlayerWeapon = dynamic_cast<AvHBasePlayerWeapon*>(pBot->Player->m_rgpPlayerItems[1]);
AvHBasePlayerWeapon* theBasePlayerWeapon = dynamic_cast<AvHBasePlayerWeapon*>(pBot->Player->m_rgpPlayerItems[2]);
if (theBasePlayerWeapon)
{
@ -265,7 +265,7 @@ int BotGetSecondaryWeaponClipAmmo(const AvHAIPlayer* pBot)
int BotGetPrimaryWeaponMaxClipSize(const AvHAIPlayer* pBot)
{
AvHBasePlayerWeapon* theBasePlayerWeapon = dynamic_cast<AvHBasePlayerWeapon*>(pBot->Player->m_rgpPlayerItems[0]);
AvHBasePlayerWeapon* theBasePlayerWeapon = dynamic_cast<AvHBasePlayerWeapon*>(pBot->Player->m_rgpPlayerItems[1]);
if (theBasePlayerWeapon)
{
@ -277,7 +277,7 @@ int BotGetPrimaryWeaponMaxClipSize(const AvHAIPlayer* pBot)
int BotGetSecondaryWeaponMaxClipSize(const AvHAIPlayer* pBot)
{
AvHBasePlayerWeapon* theBasePlayerWeapon = dynamic_cast<AvHBasePlayerWeapon*>(pBot->Player->m_rgpPlayerItems[1]);
AvHBasePlayerWeapon* theBasePlayerWeapon = dynamic_cast<AvHBasePlayerWeapon*>(pBot->Player->m_rgpPlayerItems[2]);
if (theBasePlayerWeapon)
{
@ -289,7 +289,7 @@ int BotGetSecondaryWeaponMaxClipSize(const AvHAIPlayer* pBot)
int BotGetSecondaryWeaponMaxAmmoReserve(AvHAIPlayer* pBot)
{
AvHBasePlayerWeapon* theBasePlayerWeapon = dynamic_cast<AvHBasePlayerWeapon*>(pBot->Player->m_rgpPlayerItems[1]);
AvHBasePlayerWeapon* theBasePlayerWeapon = dynamic_cast<AvHBasePlayerWeapon*>(pBot->Player->m_rgpPlayerItems[2]);
if (theBasePlayerWeapon)
{
@ -326,19 +326,19 @@ float GetMaxIdealWeaponRange(const AvHAIWeapon Weapon)
case WEAPON_SKULK_XENOCIDE:
return UTIL_MetresToGoldSrcUnits(5.0f);
case WEAPON_ONOS_GORE:
return kClawsRange;
return BALANCE_VAR(kClawsRange);
case WEAPON_ONOS_DEVOUR:
return kDevourRange;
return BALANCE_VAR(kDevourRange);
case WEAPON_FADE_SWIPE:
return kSwipeRange;
return BALANCE_VAR(kSwipeRange);
case WEAPON_SKULK_BITE:
return kBiteRange;
return BALANCE_VAR(kBiteRange);
case WEAPON_LERK_BITE:
return kBite2Range;
return BALANCE_VAR(kBite2Range);
case WEAPON_GORGE_HEALINGSPRAY:
return kHealingSprayRange;
return BALANCE_VAR(kHealingSprayRange);
case WEAPON_MARINE_WELDER:
return kWelderRange;
return BALANCE_VAR(kWelderRange);
default:
return max_player_use_reach;
}
@ -428,7 +428,7 @@ Vector UTIL_GetGrenadeThrowTarget(edict_t* Player, const Vector TargetLocation,
bot_path_node CheckPath[MAX_AI_PATH_SIZE];
int PathSize = 0;
dtStatus Status = FindPathClosestToPoint(ALL_NAV_PROFILE, Player->v.origin, TargetLocation, CheckPath, &PathSize, ExplosionRadius);
dtStatus Status = FindPathClosestToPoint(BaseNavProfiles[ALL_NAV_PROFILE], Player->v.origin, TargetLocation, CheckPath, &PathSize, ExplosionRadius);
if (dtStatusSucceed(Status))
{