Started Bot Swimming

This commit is contained in:
RGreenlees 2023-10-31 17:20:14 +00:00 committed by pierow
parent e64cb51067
commit b336ec028c
9 changed files with 689 additions and 575 deletions

View file

@ -432,7 +432,8 @@ typedef struct _AVH_AI_PLAYER_TASK
// Contains the bot's current navigation info, such as current path
typedef struct _NAV_STATUS
{
bot_path_node CurrentPath[MAX_AI_PATH_SIZE]; // Bot's path nodes
vector<bot_path_node> CurrentPath; // Bot's path nodes
vector<bot_path_node>::iterator CurrentPathPoint;
Vector TargetDestination = g_vecZero; // Desired destination
Vector ActualMoveDestination = g_vecZero; // Actual destination on nav mesh
@ -441,8 +442,6 @@ typedef struct _NAV_STATUS
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
int PathSize = 0; // How many path nodes the bot's current path has
int CurrentPathPoint = 0; // Which point in the path the bot is on
int CurrentMoveType = MOVETYPE_NONE; // Tracks the edict's current movement type
unsigned int CurrentPoly = 0; // Which nav mesh poly the bot is currently on

View file

@ -26,7 +26,7 @@ bool UTIL_QuickTrace(const edict_t* pEdict, const Vector& start, const Vector& e
bool UTIL_QuickHullTrace(const edict_t* pEdict, const Vector& start, const Vector& end)
{
int hullNum = 0;// GetPlayerHullIndex(pEdict);
int hullNum = (!FNullEnt(pEdict)) ? GetPlayerHullIndex(pEdict) : point_hull;
edict_t* IgnoreEdict = (!FNullEnt(pEdict)) ? pEdict->v.pContainingEntity : NULL;
TraceResult hit;
UTIL_TraceHull(start, end, ignore_monsters, hullNum, IgnoreEdict, &hit);
@ -54,14 +54,27 @@ edict_t* UTIL_TraceEntity(const edict_t* pEdict, const Vector& start, const Vect
Vector UTIL_GetTraceHitLocation(const Vector Start, const Vector End)
{
TraceResult hit;
UTIL_TraceLine(Start, End, ignore_monsters, ignore_glass, NULL, &hit);
UTIL_TraceHull(Start, End, ignore_monsters, point_hull, NULL, &hit);
if (hit.flFraction < 1.0f)
if (hit.flFraction < 1.0f && !hit.fAllSolid)
{
return hit.vecEndPos;
}
return g_vecZero;
return Start;
}
Vector UTIL_GetHullTraceHitLocation(const Vector Start, const Vector End, int HullNum)
{
TraceResult hit;
UTIL_TraceHull(Start, End, ignore_monsters, HullNum, NULL, &hit);
if (hit.flFraction < 1.0f && !hit.fAllSolid)
{
return hit.vecEndPos;
}
return Start;
}
Vector UTIL_GetGroundLocation(const Vector CheckLocation)
@ -244,41 +257,46 @@ bool GetNearestMapLocationAtPoint(vec3_t SearchLocation, string& outLocation)
return theSuccess;
}
void AIDEBUG_DrawBotPath(AvHAIPlayer* pBot)
void AIDEBUG_DrawBotPath(AvHAIPlayer* pBot, float DrawTime)
{
if (pBot->BotNavInfo.PathSize == 0) { return; }
AIDEBUG_DrawPath(pBot->BotNavInfo.CurrentPath, DrawTime);
}
for (int i = 0; i < pBot->BotNavInfo.PathSize; i++)
void AIDEBUG_DrawPath(vector<bot_path_node>& path, float DrawTime)
{
if (path.size() == 0) { return; }
for (auto it = path.begin(); it != path.end(); it++)
{
Vector FromLoc = pBot->BotNavInfo.CurrentPath[i].FromLocation;
Vector ToLoc = pBot->BotNavInfo.CurrentPath[i].Location;
Vector FromLoc = it->FromLocation;
Vector ToLoc = it->Location;
switch (pBot->BotNavInfo.CurrentPath[i].flag)
switch (it->flag)
{
case SAMPLE_POLYFLAGS_WELD:
case SAMPLE_POLYFLAGS_DOOR:
UTIL_DrawLine(INDEXENT(1), FromLoc, ToLoc, 255, 0, 0);
break;
case SAMPLE_POLYFLAGS_JUMP:
case SAMPLE_POLYFLAGS_DUCKJUMP:
UTIL_DrawLine(INDEXENT(1), FromLoc, ToLoc, 255, 255, 0);
break;
case SAMPLE_POLYFLAGS_LADDER:
UTIL_DrawLine(INDEXENT(1), FromLoc, ToLoc, 0, 0, 255);
break;
case SAMPLE_POLYFLAGS_WALLCLIMB:
UTIL_DrawLine(INDEXENT(1), FromLoc, ToLoc, 0, 128, 0);
break;
case SAMPLE_POLYFLAGS_BLOCKED:
UTIL_DrawLine(INDEXENT(1), FromLoc, ToLoc, 128, 128, 128);
break;
case SAMPLE_POLYFLAGS_TEAM1PHASEGATE:
case SAMPLE_POLYFLAGS_TEAM2PHASEGATE:
UTIL_DrawLine(INDEXENT(1), FromLoc, ToLoc, 255, 128, 128);
break;
default:
UTIL_DrawLine(INDEXENT(1), FromLoc, ToLoc);
break;
case SAMPLE_POLYFLAGS_WELD:
case SAMPLE_POLYFLAGS_DOOR:
UTIL_DrawLine(INDEXENT(1), FromLoc, ToLoc, DrawTime, 255, 0, 0);
break;
case SAMPLE_POLYFLAGS_JUMP:
case SAMPLE_POLYFLAGS_DUCKJUMP:
UTIL_DrawLine(INDEXENT(1), FromLoc, ToLoc, DrawTime, 255, 255, 0);
break;
case SAMPLE_POLYFLAGS_LADDER:
UTIL_DrawLine(INDEXENT(1), FromLoc, ToLoc, DrawTime, 0, 0, 255);
break;
case SAMPLE_POLYFLAGS_WALLCLIMB:
UTIL_DrawLine(INDEXENT(1), FromLoc, ToLoc, DrawTime, 0, 128, 0);
break;
case SAMPLE_POLYFLAGS_BLOCKED:
UTIL_DrawLine(INDEXENT(1), FromLoc, ToLoc, DrawTime, 128, 128, 128);
break;
case SAMPLE_POLYFLAGS_TEAM1PHASEGATE:
case SAMPLE_POLYFLAGS_TEAM2PHASEGATE:
UTIL_DrawLine(INDEXENT(1), FromLoc, ToLoc, DrawTime, 255, 128, 128);
break;
default:
UTIL_DrawLine(INDEXENT(1), FromLoc, ToLoc, DrawTime);
break;
}
}
}
@ -347,6 +365,7 @@ void UTIL_DrawLine(edict_t* pEntity, Vector start, Vector end, float drawTimeSec
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);

View file

@ -12,6 +12,7 @@ bool UTIL_QuickHullTrace(const edict_t* pEdict, const Vector& start, const Vecto
bool UTIL_QuickHullTrace(const edict_t* pEdict, const Vector& start, const Vector& end, int hullNum);
edict_t* UTIL_TraceEntity(const edict_t* pEdict, const Vector& start, const Vector& end);
Vector UTIL_GetTraceHitLocation(const Vector Start, const Vector End);
Vector UTIL_GetHullTraceHitLocation(const Vector Start, const Vector End, int HullNum);
Vector UTIL_GetGroundLocation(const Vector CheckLocation);
Vector UTIL_GetEntityGroundLocation(const edict_t* pEntity);
@ -30,7 +31,8 @@ bool GetNearestMapLocationAtPoint(vec3_t SearchLocation, string& outLocation);
AvHAIDeployableStructureType GetDeployableObjectTypeFromEdict(const edict_t* StructureEdict);
void AIDEBUG_DrawBotPath(AvHAIPlayer* pBot);
void AIDEBUG_DrawBotPath(AvHAIPlayer* pBot, float DrawTime = 0.0f);
void AIDEBUG_DrawPath(vector<bot_path_node>& path, float DrawTime = 0.0f);
// 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);

File diff suppressed because it is too large Load diff

View file

@ -55,13 +55,14 @@ enum SamplePolyFlags
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_TEAM1PHASEGATE = 1 << 8, // Requires using a phase gate to traverse (team 1 only)
SAMPLE_POLYFLAGS_TEAM2PHASEGATE = 1 << 9, // Requires using a phase gate to traverse (team 2 only)
SAMPLE_POLYFLAGS_TEAM1STRUCTURE = 1 << 10, // A team 1 structure is in the way that cannot be jumped over. Impassable to team 1 players (assume cannot teamkill own structures)
SAMPLE_POLYFLAGS_TEAM2STRUCTURE = 1 << 11, // A team 2 structure is in the way that cannot be jumped over. Impassable to team 2 players (assume cannot teamkill own structures)
SAMPLE_POLYFLAGS_WELD = 1 << 12, // Requires a welder to get through here
SAMPLE_POLYFLAGS_DOOR = 1 << 13, // Requires a welder to get through here
SAMPLE_POLYFLAGS_FLY = 1 << 7, // Requires lerk or jetpack to traverse
SAMPLE_POLYFLAGS_NOONOS = 1 << 8, // This movement is not allowed by onos
SAMPLE_POLYFLAGS_TEAM1PHASEGATE = 1 << 9, // Requires using a phase gate to traverse (team 1 only)
SAMPLE_POLYFLAGS_TEAM2PHASEGATE = 1 << 10, // Requires using a phase gate to traverse (team 2 only)
SAMPLE_POLYFLAGS_TEAM1STRUCTURE = 1 << 11, // A team 1 structure is in the way that cannot be jumped over. Impassable to team 1 players (assume cannot teamkill own structures)
SAMPLE_POLYFLAGS_TEAM2STRUCTURE = 1 << 12, // A team 2 structure is in the way that cannot be jumped over. Impassable to team 2 players (assume cannot teamkill own structures)
SAMPLE_POLYFLAGS_WELD = 1 << 13, // Requires a welder to get through here
SAMPLE_POLYFLAGS_DOOR = 1 << 14, // Requires a welder to get through here
SAMPLE_POLYFLAGS_DISABLED = 1 << 15, // Disabled, not usable by anyone
SAMPLE_POLYFLAGS_ALL = 0xffff // All abilities.
@ -320,8 +321,9 @@ bool MoveTo(AvHAIPlayer* pBot, const Vector Destination, const BotMoveStyle Move
// Used by the MoveTo command, handles the bot's movement and inputs to follow a path it has calculated for itself
void BotFollowPath(AvHAIPlayer* pBot);
void BotFollowFlightPath(AvHAIPlayer* pBot);
void BotFollowSwimPath(AvHAIPlayer* pBot);
int GetNextDirectFlightPath(AvHAIPlayer* pBot);
void SkipAheadInFlightPath(AvHAIPlayer* pBot);
// If the bot has been unable to move more than 32 units in the last MaxStuckTime seconds (must be trying to move somewhere) then returns true
bool IsBotPermaStuck(AvHAIPlayer* pBot);
@ -332,14 +334,16 @@ void MoveDirectlyTo(AvHAIPlayer* pBot, const Vector Destination);
// Check if there are any players in our way and try to move around them. If we can't, then back up to let them through
void HandlePlayerAvoidance(AvHAIPlayer* pBot, const Vector MoveDestination);
Vector AdjustPointForPathfinding(const Vector Point);
// Special path finding that takes the presence of phase gates into account
dtStatus FindFlightPathToPoint(const nav_profile& NavProfile, Vector FromLocation, Vector ToLocation, bot_path_node* path, int* pathSize, float MaxAcceptableDistance);
dtStatus FindFlightPathToPoint(const nav_profile& NavProfile, Vector FromLocation, Vector ToLocation, vector<bot_path_node>& path, 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 nav_profile& NavProfile, const Vector FromLocation, const Vector ToLocation, bot_path_node* path, int* pathSize, float MaxAcceptableDistance);
dtStatus FindPathClosestToPoint(AvHAIPlayer* pBot, const BotMoveStyle MoveStyle, const Vector FromLocation, const Vector ToLocation, vector<bot_path_node>& path, float MaxAcceptableDistance);
dtStatus FindPathClosestToPoint(const nav_profile& NavProfile, const Vector FromLocation, const Vector ToLocation, vector<bot_path_node>& path, 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);
@ -403,8 +407,8 @@ bool UTIL_PointIsReachable(const nav_profile& NavProfile, const Vector FromLocat
// 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);
// For the given viewer location and path, will return the furthest point along the path the viewer could see
Vector UTIL_GetFurthestVisiblePointOnPath(const Vector ViewerLocation, const bot_path_node* path, const int pathSize, bool bPrecise);
Vector UTIL_GetFurthestVisiblePointOnPath(const Vector ViewerLocation, vector<bot_path_node>& path, bool bPrecise);
Vector UTIL_GetFurthestVisiblePointOnLineWithHull(const Vector ViewerLocation, const Vector LineStart, const Vector LineEnd, int HullNumber);
// Returns the nearest nav mesh poly reference for the edict's current world position
dtPolyRef UTIL_GetNearestPolyRefForEntity(const edict_t* Edict);
@ -435,6 +439,8 @@ void ClearBotStuckMovement(AvHAIPlayer* pBot);
void UTIL_ClearDoorData();
void UTIL_ClearWeldablesData();
const nav_profile GetBaseNavProfile(const int index);
// Based on the direction the bot wants to move and it's current facing angle, sets the forward and side move, and the directional buttons to make the bot actually move
void BotMovementInputs(AvHAIPlayer* pBot);
@ -459,10 +465,9 @@ nav_door* UTIL_GetNavDoorByEdict(const edict_t* DoorEdict);
Vector UTIL_AdjustPointAwayFromNavWall(const Vector Location, const float MaxDistanceFromWall);
unsigned char UTIL_GetBotCurrentPathArea(AvHAIPlayer* pBot);
unsigned char UTIL_GetNextBotCurrentPathArea(AvHAIPlayer* pBot);
void UTIL_PopulateBaseNavProfiles();
void UTIL_RefreshOffMeshConnections();
#endif // BOT_NAVIGATION_H

View file

@ -1477,8 +1477,6 @@ void StartNewBotFrame(AvHAIPlayer* pBot)
UpdateCommanderOrders(pBot);
}
UTIL_DrawLine(INDEXENT(1), pBot->Edict->v.origin, pBot->BotNavInfo.LastNavMeshPosition);
}
void DroneThink(AvHAIPlayer* pBot)

View file

@ -2512,19 +2512,19 @@ bool AITAC_GetNumPlayersOnTeamWithLOS(AvHTeamNumber Team, const Vector& Location
bool AITAC_ShouldBotBeCautious(AvHAIPlayer* pBot)
{
if (pBot->BotNavInfo.PathSize == 0) { return false; }
if (pBot->BotNavInfo.CurrentPath.size() == 0 || pBot->BotNavInfo.CurrentPathPoint == pBot->BotNavInfo.CurrentPath.end()) { return false; }
if (UTIL_GetBotCurrentPathArea(pBot) != SAMPLE_POLYAREA_GROUND) { return false; }
if (pBot->BotNavInfo.CurrentPathPoint->area != SAMPLE_POLYAREA_GROUND) { return false; }
AvHTeamNumber EnemyTeam = AIMGR_GetEnemyTeam(pBot->Player->GetTeam());
if (AITAC_AnyPlayerOnTeamHasLOSToLocation(EnemyTeam, pBot->Edict->v.origin, UTIL_MetresToGoldSrcUnits(50.0f), nullptr)) { return false; }
int NumEnemiesAtDestination = AITAC_GetNumPlayersOnTeamWithLOS(EnemyTeam, pBot->BotNavInfo.CurrentPath[pBot->BotNavInfo.CurrentPathPoint].Location, UTIL_MetresToGoldSrcUnits(50.0f), pBot->Edict);
int NumEnemiesAtDestination = AITAC_GetNumPlayersOnTeamWithLOS(EnemyTeam, pBot->BotNavInfo.CurrentPathPoint->Location, UTIL_MetresToGoldSrcUnits(50.0f), pBot->Edict);
if (NumEnemiesAtDestination > 1)
{
return (vDist2DSq(pBot->Edict->v.origin, pBot->BotNavInfo.CurrentPath[pBot->BotNavInfo.CurrentPathPoint].Location) < sqrf(UTIL_MetresToGoldSrcUnits(5.0f)));
return (vDist2DSq(pBot->Edict->v.origin, pBot->BotNavInfo.CurrentPathPoint->Location) < sqrf(UTIL_MetresToGoldSrcUnits(5.0f)));
}
return false;

View file

@ -2486,8 +2486,8 @@ void AITASK_GenerateGuardWatchPoints(AvHAIPlayer* pBot, const Vector& GuardLocat
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;
vector<bot_path_node> path;
path.clear();
for (int i = 0; i < AITAC_GetNumHives(); i++)
@ -2498,41 +2498,41 @@ 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(NavProfile, Hive->FloorLocation, GuardLocation, path, &pathSize, 500.0f);
dtStatus SearchResult = FindPathClosestToPoint(NavProfile, Hive->FloorLocation, GuardLocation, path, 500.0f);
if (dtStatusSucceed(SearchResult))
{
Vector FinalApproachDir = UTIL_GetVectorNormal2D(path[pathSize - 1].Location - path[pathSize - 2].Location);
Vector FinalApproachDir = UTIL_GetVectorNormal2D(path.back().Location - prev(prev(path.end()))->Location);
Vector ProspectiveNewGuardLoc = GuardLocation - (FinalApproachDir * 300.0f);
ProspectiveNewGuardLoc.z = path[pathSize - 2].Location.z;
ProspectiveNewGuardLoc.z = prev(prev(path.end()))->Location.z;
pBot->GuardInfo.GuardPoints[pBot->GuardInfo.NumGuardPoints++] = ProspectiveNewGuardLoc;
}
}
dtStatus SearchResult = FindPathClosestToPoint(NavProfile, AITAC_GetTeamStartingLocation(EnemyTeam), GuardLocation, path, &pathSize, 500.0f);
dtStatus SearchResult = FindPathClosestToPoint(NavProfile, AITAC_GetTeamStartingLocation(EnemyTeam), GuardLocation, path, 500.0f);
if (dtStatusSucceed(SearchResult))
{
Vector FinalApproachDir = UTIL_GetVectorNormal2D(path[pathSize - 1].Location - path[pathSize - 2].Location);
Vector FinalApproachDir = UTIL_GetVectorNormal2D(path.back().Location - prev(prev(path.end()))->Location);
Vector ProspectiveNewGuardLoc = GuardLocation - (FinalApproachDir * 300.0f);
ProspectiveNewGuardLoc.z = path[pathSize - 2].Location.z;
ProspectiveNewGuardLoc.z = prev(prev(path.end()))->Location.z;
pBot->GuardInfo.GuardPoints[pBot->GuardInfo.NumGuardPoints++] = ProspectiveNewGuardLoc;
}
if (vDist2DSq(GuardLocation, AITAC_GetTeamStartingLocation(pBot->Player->GetTeam())) > sqrf(UTIL_MetresToGoldSrcUnits(15.0f)))
{
dtStatus SearchResult = FindPathClosestToPoint(NavProfile, AITAC_GetTeamStartingLocation(pBot->Player->GetTeam()), GuardLocation, path, &pathSize, 500.0f);
dtStatus SearchResult = FindPathClosestToPoint(NavProfile, AITAC_GetTeamStartingLocation(pBot->Player->GetTeam()), GuardLocation, path, 500.0f);
if (dtStatusSucceed(SearchResult))
{
Vector FinalApproachDir = UTIL_GetVectorNormal2D(path[pathSize - 1].Location - path[pathSize - 2].Location);
Vector FinalApproachDir = UTIL_GetVectorNormal2D(path.back().Location - prev(prev(path.end()))->Location);
Vector ProspectiveNewGuardLoc = GuardLocation - (FinalApproachDir * 300.0f);
ProspectiveNewGuardLoc.z = path[pathSize - 2].Location.z;
ProspectiveNewGuardLoc.z = prev(prev(path.end()))->Location.z;
pBot->GuardInfo.GuardPoints[pBot->GuardInfo.NumGuardPoints++] = ProspectiveNewGuardLoc;
}

View file

@ -428,14 +428,14 @@ Vector UTIL_GetGrenadeThrowTarget(edict_t* Player, const Vector TargetLocation,
return NewSpot;
}
bot_path_node CheckPath[MAX_AI_PATH_SIZE];
int PathSize = 0;
vector<bot_path_node> CheckPath;
CheckPath.clear();
dtStatus Status = FindPathClosestToPoint(BaseNavProfiles[ALL_NAV_PROFILE], Player->v.origin, TargetLocation, CheckPath, &PathSize, ExplosionRadius);
dtStatus Status = FindPathClosestToPoint(BaseNavProfiles[ALL_NAV_PROFILE], Player->v.origin, TargetLocation, CheckPath, ExplosionRadius);
if (dtStatusSucceed(Status))
{
Vector FurthestPointVisible = UTIL_GetFurthestVisiblePointOnPath(GetPlayerEyePosition(Player), CheckPath, PathSize, bPrecise);
Vector FurthestPointVisible = UTIL_GetFurthestVisiblePointOnPath(GetPlayerEyePosition(Player), CheckPath, bPrecise);
if (vDist3DSq(FurthestPointVisible, TargetLocation) <= sqrf(ExplosionRadius))
{