mirror of
https://github.com/ENSL/NS.git
synced 2025-04-20 16:30:56 +00:00
Replaced arrays with vectors for simpler code
This commit is contained in:
parent
82ea559a7a
commit
e64cb51067
6 changed files with 325 additions and 234 deletions
|
@ -438,10 +438,9 @@ typedef struct _NAV_STATUS
|
|||
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 LastPathFollowPosition = g_vecZero; // Tracks the last point where the bot was happily following a path
|
||||
|
||||
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
|
||||
|
|
|
@ -1397,6 +1397,24 @@ static float frand()
|
|||
// Special path finding that takes flight movement into account
|
||||
dtStatus FindFlightPathToPoint(const nav_profile &NavProfile, Vector FromLocation, Vector ToLocation, bot_path_node* path, int* pathSize, float MaxAcceptableDistance)
|
||||
{
|
||||
TraceResult directHit;
|
||||
|
||||
UTIL_TraceHull(FromLocation + Vector(0.0f, 0.0f, 5.0f), ToLocation, ignore_monsters, head_hull, nullptr, &directHit);
|
||||
|
||||
if (directHit.flFraction >= 1.0f)
|
||||
{
|
||||
path[0].FromLocation = FromLocation;
|
||||
path[0].Location = ToLocation;
|
||||
path[0].area = SAMPLE_POLYAREA_GROUND;
|
||||
path[0].flag = SAMPLE_POLYFLAGS_WALK;
|
||||
path[0].poly = 0;
|
||||
path[0].requiredZ = ToLocation.z;
|
||||
|
||||
*pathSize = 1;
|
||||
|
||||
return DT_SUCCESS;
|
||||
}
|
||||
|
||||
const dtNavMesh* m_navMesh = UTIL_GetNavMeshForProfile(NavProfile);
|
||||
const dtNavMeshQuery* m_navQuery = UTIL_GetNavMeshQueryForProfile(NavProfile);
|
||||
const dtQueryFilter* m_navFilter = &NavProfile.Filters;
|
||||
|
@ -1406,14 +1424,31 @@ dtStatus FindFlightPathToPoint(const nav_profile &NavProfile, Vector FromLocatio
|
|||
return DT_FAILURE;
|
||||
}
|
||||
|
||||
float pStartPos[3] = { FromLocation.x, FromLocation.z, -FromLocation.y };
|
||||
float pEndPos[3] = { ToLocation.x, ToLocation.z, -ToLocation.y };
|
||||
Vector ToFloorLocation = ToLocation;
|
||||
Vector FromFloorLocation = ToLocation;
|
||||
|
||||
UTIL_TraceHull(ToLocation, ToLocation - Vector(0.0f, 0.0f, 1000.0f), ignore_monsters, head_hull, nullptr, &directHit);
|
||||
|
||||
if (directHit.flFraction < 1.0f)
|
||||
{
|
||||
ToFloorLocation = directHit.vecEndPos;
|
||||
}
|
||||
|
||||
UTIL_TraceHull(FromLocation, FromLocation - Vector(0.0f, 0.0f, 1000.0f), ignore_monsters, head_hull, nullptr, &directHit);
|
||||
|
||||
if (directHit.flFraction < 1.0f)
|
||||
{
|
||||
FromFloorLocation = directHit.vecEndPos;
|
||||
}
|
||||
|
||||
float pStartPos[3] = { FromFloorLocation.x, FromFloorLocation.z, -FromFloorLocation.y };
|
||||
float pEndPos[3] = { ToFloorLocation.x, ToFloorLocation.z, -ToFloorLocation.y };
|
||||
|
||||
dtStatus status;
|
||||
dtPolyRef StartPoly;
|
||||
float StartNearest[3];
|
||||
dtPolyRef EndPoly;
|
||||
float EndNearest[3];
|
||||
dtPolyRef StartPoly = 0;
|
||||
float StartNearest[3] = { 0.0f, 0.0f, 0.0f };
|
||||
dtPolyRef EndPoly = 0;
|
||||
float EndNearest[3] = { 0.0f, 0.0f, 0.0f };
|
||||
dtPolyRef PolyPath[MAX_PATH_POLY];
|
||||
dtPolyRef StraightPolyPath[MAX_AI_PATH_SIZE];
|
||||
int nPathCount = 0;
|
||||
|
@ -1424,7 +1459,7 @@ dtStatus FindFlightPathToPoint(const nav_profile &NavProfile, Vector FromLocatio
|
|||
|
||||
// find the start polygon
|
||||
status = m_navQuery->findNearestPoly(pStartPos, pExtents, m_navFilter, &StartPoly, StartNearest);
|
||||
if ((status & DT_FAILURE) || (status & DT_STATUS_DETAIL_MASK))
|
||||
if (!StartPoly || (status & DT_FAILURE) || (status & DT_STATUS_DETAIL_MASK))
|
||||
{
|
||||
//BotSay(pBot, "findNearestPoly start failed!");
|
||||
return (status & DT_STATUS_DETAIL_MASK); // couldn't find a polygon
|
||||
|
@ -1432,7 +1467,7 @@ dtStatus FindFlightPathToPoint(const nav_profile &NavProfile, Vector FromLocatio
|
|||
|
||||
// find the end polygon
|
||||
status = m_navQuery->findNearestPoly(pEndPos, pExtents, m_navFilter, &EndPoly, EndNearest);
|
||||
if ((status & DT_FAILURE) || (status & DT_STATUS_DETAIL_MASK))
|
||||
if (!EndPoly || (status & DT_FAILURE) || (status & DT_STATUS_DETAIL_MASK))
|
||||
{
|
||||
//BotSay(pBot, "findNearestPoly end failed!");
|
||||
return (status & DT_STATUS_DETAIL_MASK); // couldn't find a polygon
|
||||
|
@ -1447,14 +1482,29 @@ dtStatus FindFlightPathToPoint(const nav_profile &NavProfile, Vector FromLocatio
|
|||
|
||||
m_navQuery->closestPointOnPoly(PolyPath[nPathCount - 1], EndNearest, epos, 0);
|
||||
|
||||
if (dtVdistSqr(EndNearest, epos) > sqrf(MaxAcceptableDistance))
|
||||
float DistToEndSq = dtVdist(EndNearest, epos);
|
||||
|
||||
if (DistToEndSq > MaxAcceptableDistance)
|
||||
{
|
||||
return DT_FAILURE;
|
||||
}
|
||||
else
|
||||
{
|
||||
dtVcopy(EndNearest, epos);
|
||||
// For flight paths, if we can directly reach the end point from where our path finding got to, then see if we can fly directly to our desired target
|
||||
Vector StartTrace = Vector(EndNearest[0], -EndNearest[2], EndNearest[1]);
|
||||
StartTrace.z += 20.0f;
|
||||
|
||||
TraceResult hit;
|
||||
|
||||
UTIL_TraceHull(StartTrace, ToLocation, ignore_monsters, head_hull, nullptr, &hit);
|
||||
|
||||
float DesiredDist = vDist3D(StartTrace, ToLocation);
|
||||
float ActualDist = DesiredDist * hit.flFraction;
|
||||
|
||||
// We couldn't reach our end goal
|
||||
if (DesiredDist - ActualDist > MaxAcceptableDistance)
|
||||
{
|
||||
return DT_FAILURE;
|
||||
}
|
||||
}
|
||||
|
||||
dtVcopy(EndNearest, epos);
|
||||
}
|
||||
|
||||
status = m_navQuery->findStraightPath(StartNearest, EndNearest, PolyPath, nPathCount, StraightPath, straightPathFlags, StraightPolyPath, &nVertCount, MAX_AI_PATH_SIZE, DT_STRAIGHTPATH_AREA_CROSSINGS);
|
||||
|
@ -1607,6 +1657,15 @@ dtStatus FindFlightPathToPoint(const nav_profile &NavProfile, Vector FromLocatio
|
|||
CurrentPathPoint++;
|
||||
}
|
||||
|
||||
path[CurrentPathPoint].requiredZ = ToLocation.z;
|
||||
path[CurrentPathPoint].Location = ToLocation;
|
||||
path[CurrentPathPoint].area = SAMPLE_POLYAREA_GROUND;
|
||||
path[CurrentPathPoint].flag = SAMPLE_POLYFLAGS_WALLCLIMB;
|
||||
path[CurrentPathPoint].FromLocation = path[CurrentPathPoint - 1].Location;
|
||||
path[CurrentPathPoint].poly = 0;
|
||||
|
||||
NumPathPoints++;
|
||||
|
||||
*pathSize = NumPathPoints;
|
||||
|
||||
return DT_SUCCESS;
|
||||
|
@ -1660,6 +1719,11 @@ Vector UTIL_FindHighestSuccessfulTracePoint(const Vector TraceFrom, const Vector
|
|||
|
||||
dtStatus FindPathClosestToPoint(const nav_profile& NavProfile, const Vector FromLocation, const Vector ToLocation, bot_path_node* path, int* pathSize, float MaxAcceptableDistance)
|
||||
{
|
||||
if (NavProfile.bFlyingProfile)
|
||||
{
|
||||
return FindFlightPathToPoint(NavProfile, FromLocation, ToLocation, path, pathSize, MaxAcceptableDistance);
|
||||
}
|
||||
|
||||
const dtNavMeshQuery* m_navQuery = UTIL_GetNavMeshQueryForProfile(NavProfile);
|
||||
const dtNavMesh* m_navMesh = UTIL_GetNavMeshForProfile(NavProfile);
|
||||
const dtQueryFilter* m_navFilter = &NavProfile.Filters;
|
||||
|
@ -1822,6 +1886,11 @@ dtStatus FindPathClosestToPoint(AvHAIPlayer* pBot, const BotMoveStyle MoveStyle,
|
|||
{
|
||||
if (!pBot) { return DT_FAILURE; }
|
||||
|
||||
if (pBot->BotNavInfo.NavProfile.bFlyingProfile)
|
||||
{
|
||||
return FindFlightPathToPoint(pBot->BotNavInfo.NavProfile, FromLocation, ToLocation, path, pathSize, MaxAcceptableDistance);
|
||||
}
|
||||
|
||||
const dtNavMeshQuery* m_navQuery = UTIL_GetNavMeshQueryForProfile(pBot->BotNavInfo.NavProfile);
|
||||
const dtNavMesh* m_navMesh = UTIL_GetNavMeshForProfile(pBot->BotNavInfo.NavProfile);
|
||||
const dtQueryFilter* m_navFilter = &pBot->BotNavInfo.NavProfile.Filters;
|
||||
|
@ -2873,41 +2942,30 @@ void NewMove(AvHAIPlayer* pBot)
|
|||
return;
|
||||
}
|
||||
|
||||
Vector MoveFrom = pBot->BotNavInfo.CurrentPath[pBot->BotNavInfo.CurrentPathPoint].FromLocation;
|
||||
Vector MoveTo = pBot->BotNavInfo.CurrentPath[pBot->BotNavInfo.CurrentPathPoint].Location;
|
||||
|
||||
SamplePolyAreas CurrentNavArea = (SamplePolyAreas)pBot->BotNavInfo.CurrentPath[pBot->BotNavInfo.CurrentPathPoint].area;
|
||||
unsigned short CurrentNavFlags = (SamplePolyFlags)pBot->BotNavInfo.CurrentPath[pBot->BotNavInfo.CurrentPathPoint].flag;
|
||||
|
||||
SamplePolyFlags CurrentNavFlag = (SamplePolyFlags)CurrentNavFlags;
|
||||
SamplePolyFlags CurrentNavFlags = (SamplePolyFlags)pBot->BotNavInfo.CurrentPath[pBot->BotNavInfo.CurrentPathPoint].flag;
|
||||
|
||||
// Used to anticipate if we're about to enter a crouch area so we can start crouching early
|
||||
unsigned char NextArea = SAMPLE_POLYAREA_GROUND;
|
||||
unsigned char NextFlag = SAMPLE_POLYFLAGS_WALK;
|
||||
|
||||
if (pBot->BotNavInfo.CurrentPathPoint < (pBot->BotNavInfo.PathSize - 1))
|
||||
{
|
||||
NextArea = pBot->BotNavInfo.CurrentPath[pBot->BotNavInfo.CurrentPathPoint + 1].area;
|
||||
NextFlag = pBot->BotNavInfo.CurrentPath[pBot->BotNavInfo.CurrentPathPoint + 1].flag;
|
||||
}
|
||||
|
||||
bool bIsNearNextPoint = (pBot->BotNavInfo.CurrentPathPoint < (pBot->BotNavInfo.PathSize - 1)) && vDist2DSq(pBot->Edict->v.origin, pBot->BotNavInfo.CurrentPath[pBot->BotNavInfo.CurrentPathPoint + 1].FromLocation) <= sqrf(50.0f);
|
||||
|
||||
Vector MoveFrom = g_vecZero;
|
||||
|
||||
if (pBot->BotNavInfo.CurrentPathPoint > 0)
|
||||
{
|
||||
MoveFrom = pBot->BotNavInfo.CurrentPath[pBot->BotNavInfo.CurrentPathPoint - 1].Location;
|
||||
}
|
||||
else
|
||||
{
|
||||
MoveFrom = pBot->Edict->v.origin;
|
||||
}
|
||||
|
||||
Vector MoveTo = pBot->BotNavInfo.CurrentPath[pBot->BotNavInfo.CurrentPathPoint].Location;
|
||||
// Are we reaching the start of our next path point?
|
||||
bool bIsNearNextPoint = (pBot->BotNavInfo.CurrentPathPoint < (pBot->BotNavInfo.PathSize - 1)) && (vDist2DSq(pBot->Edict->v.origin, pBot->BotNavInfo.CurrentPath[pBot->BotNavInfo.CurrentPathPoint + 1].FromLocation) <= sqrf(50.0f));
|
||||
|
||||
// Start crouching early if we're about to enter a crouch path point
|
||||
if (CanPlayerCrouch(pBot->Edict) && (CurrentNavArea == SAMPLE_POLYAREA_CROUCH || (NextArea == SAMPLE_POLYAREA_CROUCH && bIsNearNextPoint)))
|
||||
{
|
||||
pBot->Button |= IN_DUCK;
|
||||
}
|
||||
|
||||
switch (CurrentNavFlag)
|
||||
switch (CurrentNavFlags)
|
||||
{
|
||||
case SAMPLE_POLYFLAGS_WALK:
|
||||
GroundMove(pBot, MoveFrom, MoveTo);
|
||||
|
@ -2981,12 +3039,6 @@ void GroundMove(AvHAIPlayer* pBot, const Vector StartPoint, const Vector EndPoin
|
|||
{
|
||||
edict_t* pEdict = pBot->Edict;
|
||||
|
||||
if (pBot->BotNavInfo.IsOnGround)
|
||||
{
|
||||
pBot->BotNavInfo.LastNavMeshPosition = pBot->CurrentFloorPosition;
|
||||
pBot->BotNavInfo.LastPathFollowPosition = pBot->CurrentFloorPosition;
|
||||
}
|
||||
|
||||
Vector CurrentPos = (pBot->BotNavInfo.IsOnGround) ? pBot->Edict->v.origin : pBot->CurrentFloorPosition;
|
||||
|
||||
Vector vForward = UTIL_GetVectorNormal2D(EndPoint - CurrentPos);
|
||||
|
@ -3069,12 +3121,15 @@ void GroundMove(AvHAIPlayer* pBot, const Vector StartPoint, const Vector EndPoin
|
|||
|
||||
pBot->desiredMovementDir = UTIL_GetVectorNormal2D(pBot->desiredMovementDir);
|
||||
|
||||
Vector HeadLocation = GetPlayerTopOfCollisionHull(pEdict, false);
|
||||
|
||||
// Crouch if we have something in our way at head height
|
||||
if (!UTIL_QuickTrace(pBot->Edict, HeadLocation, (HeadLocation + (pBot->desiredMovementDir * 50.0f))))
|
||||
if (CanPlayerCrouch(pEdict))
|
||||
{
|
||||
pBot->Button |= IN_DUCK;
|
||||
Vector HeadLocation = GetPlayerTopOfCollisionHull(pEdict, false);
|
||||
|
||||
// Crouch if we have something in our way at head height
|
||||
if (!UTIL_QuickTrace(pBot->Edict, HeadLocation, (HeadLocation + (pBot->desiredMovementDir * 50.0f))))
|
||||
{
|
||||
pBot->Button |= IN_DUCK;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -5104,23 +5159,23 @@ bool MoveTo(AvHAIPlayer* pBot, const Vector Destination, const BotMoveStyle Move
|
|||
|
||||
BotNavInfo->PathDestination = Destination;
|
||||
|
||||
Vector ValidNavmeshPoint = UTIL_ProjectPointToNavmesh(Destination, Vector(max_ai_use_reach, max_ai_use_reach, max_ai_use_reach), pBot->BotNavInfo.NavProfile);
|
||||
|
||||
// Destination is not on the nav mesh, so we can't get close enough
|
||||
if (vIsZero(ValidNavmeshPoint))
|
||||
{
|
||||
sprintf(pBot->PathStatus, "Could not project destination to navmesh");
|
||||
return false;
|
||||
}
|
||||
|
||||
dtStatus PathFindingStatus = DT_FAILURE;
|
||||
|
||||
if (bIsFlyingProfile)
|
||||
{
|
||||
PathFindingStatus = FindFlightPathToPoint(pBot->BotNavInfo.NavProfile, pBot->CurrentFloorPosition, ValidNavmeshPoint, BotNavInfo->CurrentPath, &BotNavInfo->PathSize, MaxAcceptableDist);
|
||||
PathFindingStatus = FindFlightPathToPoint(pBot->BotNavInfo.NavProfile, pBot->Edict->v.origin, Destination, BotNavInfo->CurrentPath, &BotNavInfo->PathSize, MaxAcceptableDist);
|
||||
}
|
||||
else
|
||||
{
|
||||
Vector ValidNavmeshPoint = UTIL_ProjectPointToNavmesh(Destination, Vector(max_ai_use_reach, max_ai_use_reach, max_ai_use_reach), pBot->BotNavInfo.NavProfile);
|
||||
|
||||
// Destination is not on the nav mesh, so we can't get close enough
|
||||
if (vIsZero(ValidNavmeshPoint))
|
||||
{
|
||||
sprintf(pBot->PathStatus, "Could not project destination to navmesh");
|
||||
return false;
|
||||
}
|
||||
|
||||
PathFindingStatus = FindPathClosestToPoint(pBot, pBot->BotNavInfo.MoveStyle, pBot->CurrentFloorPosition, ValidNavmeshPoint, BotNavInfo->CurrentPath, &BotNavInfo->PathSize, MaxAcceptableDist);
|
||||
}
|
||||
|
||||
|
@ -5308,33 +5363,18 @@ void BotFollowFlightPath(AvHAIPlayer* pBot)
|
|||
nav_status* BotNavInfo = &pBot->BotNavInfo;
|
||||
edict_t* pEdict = pBot->Edict;
|
||||
|
||||
Vector CurrentMoveDest = pBot->BotNavInfo.CurrentPath[pBot->BotNavInfo.CurrentPathPoint].Location;
|
||||
Vector MoveFrom = pBot->BotNavInfo.CurrentPath[pBot->BotNavInfo.CurrentPathPoint].FromLocation;
|
||||
Vector MoveTo = pBot->BotNavInfo.CurrentPath[pBot->BotNavInfo.CurrentPathPoint].Location;
|
||||
Vector NextPoint = pBot->BotNavInfo.CurrentPath[pBot->BotNavInfo.CurrentPathPoint + 1].Location;
|
||||
|
||||
unsigned char CurrentMoveArea = pBot->BotNavInfo.CurrentPath[pBot->BotNavInfo.CurrentPathPoint].area;
|
||||
unsigned char NextMoveArea = pBot->BotNavInfo.CurrentPath[pBot->BotNavInfo.CurrentPathPoint + 1].area;
|
||||
|
||||
Vector ClosestPointToPath = vClosestPointOnLine(MoveFrom, MoveTo, pEdict->v.origin);
|
||||
|
||||
bool bAtOrPastDestination = vEquals(ClosestPointToPath, MoveTo, 32.0f);
|
||||
|
||||
//if ((CurrentMoveArea == SAMPLE_POLYAREA_GROUND || CurrentMoveArea == SAMPLE_POLYAREA_CROUCH) && !UTIL_QuickTrace(pBot->Edict, pBot->Edict->v.origin, CurrentMoveDest))
|
||||
//{
|
||||
// BotRecalcPath(pBot, BotNavInfo->ActualMoveDestination);
|
||||
// return;
|
||||
//}
|
||||
|
||||
Vector ClosestPointToPath = vClosestPointOnLine(pBot->BotNavInfo.CurrentPath[pBot->BotNavInfo.CurrentPathPoint - 1].Location, CurrentMoveDest, pEdict->v.origin);
|
||||
|
||||
bool bAtOrPastDestination = vEquals(ClosestPointToPath, CurrentMoveDest, 32.0f);
|
||||
|
||||
Vector MoveFrom = g_vecZero;
|
||||
|
||||
if (BotNavInfo->CurrentPathPoint > 0)
|
||||
{
|
||||
MoveFrom = BotNavInfo->CurrentPath[BotNavInfo->CurrentPathPoint - 1].Location;
|
||||
}
|
||||
else
|
||||
{
|
||||
MoveFrom = pBot->Edict->v.origin;
|
||||
}
|
||||
|
||||
// If we've reached our current path point
|
||||
// If we've reached our current path point or can directly reach the next point
|
||||
if (bAtOrPastDestination || UTIL_QuickHullTrace(pEdict, pEdict->v.origin, NextPoint, head_hull))
|
||||
{
|
||||
// End of the whole path, stop all movement
|
||||
|
@ -5354,19 +5394,20 @@ void BotFollowFlightPath(AvHAIPlayer* pBot)
|
|||
BotNavInfo->CurrentPathPoint = GetNextDirectFlightPath(pBot);
|
||||
}
|
||||
|
||||
pBot->BotNavInfo.CurrentPath[pBot->BotNavInfo.CurrentPathPoint - 1].Location = pBot->Edict->v.origin;
|
||||
pBot->BotNavInfo.CurrentPath[pBot->BotNavInfo.CurrentPathPoint].FromLocation = pBot->Edict->v.origin;
|
||||
|
||||
CurrentMoveDest = pBot->BotNavInfo.CurrentPath[pBot->BotNavInfo.CurrentPathPoint].Location;
|
||||
MoveFrom = pBot->BotNavInfo.CurrentPath[pBot->BotNavInfo.CurrentPathPoint].FromLocation;
|
||||
MoveTo = pBot->BotNavInfo.CurrentPath[pBot->BotNavInfo.CurrentPathPoint].Location;
|
||||
NextPoint = pBot->BotNavInfo.CurrentPath[pBot->BotNavInfo.CurrentPathPoint + 1].Location;
|
||||
ClosestPointToPath = vClosestPointOnLine(pBot->BotNavInfo.CurrentPath[pBot->BotNavInfo.CurrentPathPoint - 1].Location, CurrentMoveDest, pEdict->v.origin);
|
||||
|
||||
MoveFrom = pBot->BotNavInfo.CurrentPath[pBot->BotNavInfo.CurrentPathPoint - 1].Location;
|
||||
CurrentMoveArea = pBot->BotNavInfo.CurrentPath[pBot->BotNavInfo.CurrentPathPoint].area;
|
||||
NextMoveArea = pBot->BotNavInfo.CurrentPath[pBot->BotNavInfo.CurrentPathPoint + 1].area;
|
||||
|
||||
ClearBotStuck(pBot);
|
||||
}
|
||||
}
|
||||
|
||||
Vector MoveDir = UTIL_GetVectorNormal(NextPoint - pBot->Edict->v.origin);
|
||||
Vector MoveDir = UTIL_GetVectorNormal(MoveTo - pEdict->v.origin);
|
||||
|
||||
Vector ObstacleCheck = pBot->Edict->v.origin + (MoveDir * 32.0f);
|
||||
|
||||
|
@ -5376,8 +5417,7 @@ void BotFollowFlightPath(AvHAIPlayer* pBot)
|
|||
return;
|
||||
}
|
||||
|
||||
|
||||
if (IsBotStuck(pBot, CurrentMoveDest))
|
||||
if (IsBotStuck(pBot, MoveTo))
|
||||
{
|
||||
if (BotNavInfo->TotalStuckTime > 3.0f)
|
||||
{
|
||||
|
@ -5388,9 +5428,9 @@ void BotFollowFlightPath(AvHAIPlayer* pBot)
|
|||
|
||||
float Velocity = vSize2DSq(pBot->Edict->v.velocity);
|
||||
|
||||
bool bMustHugGround = (pBot->BotNavInfo.CurrentPath[pBot->BotNavInfo.CurrentPathPoint].area == SAMPLE_POLYAREA_CROUCH || pBot->BotNavInfo.CurrentPath[pBot->BotNavInfo.CurrentPathPoint + 1].area == SAMPLE_POLYAREA_CROUCH);
|
||||
bool bMustHugGround = (CurrentMoveArea == SAMPLE_POLYAREA_CROUCH || NextMoveArea == SAMPLE_POLYAREA_CROUCH);
|
||||
|
||||
if (!bMustHugGround || pBot->BotNavInfo.CurrentPath[pBot->BotNavInfo.CurrentPathPoint - 1].Location.z <= pBot->BotNavInfo.CurrentPath[pBot->BotNavInfo.CurrentPathPoint].Location.z)
|
||||
if (!bMustHugGround || MoveFrom.z <= MoveTo.z)
|
||||
{
|
||||
if (Velocity < sqrf(500.f))
|
||||
{
|
||||
|
@ -5416,11 +5456,9 @@ void BotFollowFlightPath(AvHAIPlayer* pBot)
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
pBot->desiredMovementDir = UTIL_GetForwardVector2D(pBot->Edict->v.v_angle);
|
||||
|
||||
Vector LookLocation = CurrentMoveDest;
|
||||
Vector LookLocation = MoveTo;
|
||||
|
||||
|
||||
if (ClosestPointToPath.z - pBot->Edict->v.origin.z > 8.0f)
|
||||
|
@ -5431,29 +5469,27 @@ void BotFollowFlightPath(AvHAIPlayer* pBot)
|
|||
{
|
||||
// Crouch areas need the lerk to stick close to the ground to avoid missing the crouch entry point
|
||||
|
||||
bool bIsFinalPoint = pBot->BotNavInfo.CurrentPathPoint == pBot->BotNavInfo.PathSize - 1;
|
||||
bool bIsFinalPoint = pBot->BotNavInfo.CurrentPathPoint == (pBot->BotNavInfo.PathSize - 1);
|
||||
|
||||
if (bMustHugGround || bIsFinalPoint)
|
||||
{
|
||||
if (pBot->Edict->v.origin.z - CurrentMoveDest.z > 8.0f)
|
||||
if (pBot->Edict->v.origin.z - MoveTo.z > 8.0f)
|
||||
{
|
||||
LookLocation.z -= 50.0f;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (UTIL_QuickHullTrace(pBot->Edict, pBot->Edict->v.origin, CurrentMoveDest + Vector(0.0f, 0.0f, 50.0f)))
|
||||
if (UTIL_QuickHullTrace(pBot->Edict, pBot->Edict->v.origin, MoveTo + Vector(0.0f, 0.0f, 50.0f)))
|
||||
{
|
||||
LookLocation.z += 50.0f;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
BotMoveLookAt(pBot, LookLocation);
|
||||
|
||||
CheckAndHandleBreakableObstruction(pBot, MoveFrom, CurrentMoveDest);
|
||||
CheckAndHandleBreakableObstruction(pBot, MoveFrom, MoveTo);
|
||||
|
||||
CheckAndHandleDoorObstruction(pBot);
|
||||
}
|
||||
|
@ -5468,8 +5504,6 @@ void BotFollowPath(AvHAIPlayer* pBot)
|
|||
nav_status* BotNavInfo = &pBot->BotNavInfo;
|
||||
edict_t* pEdict = pBot->Edict;
|
||||
|
||||
SamplePolyAreas CurrentMoveArea = (SamplePolyAreas)BotNavInfo->CurrentPath[BotNavInfo->CurrentPathPoint].area;
|
||||
|
||||
// If we've reached our current path point
|
||||
if (HasBotReachedPathPoint(pBot))
|
||||
{
|
||||
|
@ -5511,20 +5545,15 @@ void BotFollowPath(AvHAIPlayer* pBot)
|
|||
}
|
||||
}
|
||||
|
||||
Vector TargetMoveLocation = BotNavInfo->CurrentPath[BotNavInfo->CurrentPathPoint].Location;
|
||||
Vector MoveTo = BotNavInfo->CurrentPath[BotNavInfo->CurrentPathPoint].Location;
|
||||
|
||||
bool bIsUsingPhaseGate = (BotNavInfo->CurrentPath[BotNavInfo->CurrentPathPoint].flag == SAMPLE_POLYFLAGS_TEAM1PHASEGATE || BotNavInfo->CurrentPath[BotNavInfo->CurrentPathPoint].flag == SAMPLE_POLYFLAGS_TEAM2PHASEGATE);
|
||||
unsigned short CurrentFlag = BotNavInfo->CurrentPath[BotNavInfo->CurrentPathPoint].flag;
|
||||
|
||||
bool bIsJumping = (BotNavInfo->CurrentPath[BotNavInfo->CurrentPathPoint].flag == SAMPLE_POLYFLAGS_JUMP);
|
||||
|
||||
if (bIsJumping)
|
||||
{
|
||||
bool thing = true;
|
||||
}
|
||||
bool bIsUsingPhaseGate = (CurrentFlag == SAMPLE_POLYFLAGS_TEAM1PHASEGATE || CurrentFlag == SAMPLE_POLYFLAGS_TEAM2PHASEGATE);
|
||||
|
||||
NewMove(pBot);
|
||||
|
||||
if (!bIsUsingPhaseGate && IsBotStuck(pBot, TargetMoveLocation))
|
||||
if (!bIsUsingPhaseGate && IsBotStuck(pBot, MoveTo))
|
||||
{
|
||||
if (BotNavInfo->TotalStuckTime > 3.0f)
|
||||
{
|
||||
|
@ -5540,13 +5569,11 @@ void BotFollowPath(AvHAIPlayer* pBot)
|
|||
|
||||
if (!IsPlayerClimbingWall(pBot->Edict) && !IsPlayerOnLadder(pBot->Edict))
|
||||
{
|
||||
PerformUnstuckMove(pBot, TargetMoveLocation);
|
||||
PerformUnstuckMove(pBot, MoveTo);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
void PerformUnstuckMove(AvHAIPlayer* pBot, const Vector MoveDestination)
|
||||
|
@ -5698,7 +5725,7 @@ Vector UTIL_ProjectPointToNavmesh(const Vector Location)
|
|||
|
||||
dtStatus success = m_navQuery->findNearestPoly(pCheckLoc, Extents, m_navFilter, &FoundPoly, NavNearest);
|
||||
|
||||
if (dtStatusSucceed(success))
|
||||
if (FoundPoly > 0 && dtStatusSucceed(success))
|
||||
{
|
||||
return Vector(NavNearest[0], -NavNearest[2], NavNearest[1]);
|
||||
}
|
||||
|
@ -5729,7 +5756,7 @@ Vector UTIL_ProjectPointToNavmesh(const Vector Location, const Vector Extents)
|
|||
|
||||
dtStatus success = m_navQuery->findNearestPoly(pCheckLoc, extents, m_navFilter, &FoundPoly, NavNearest);
|
||||
|
||||
if (dtStatusSucceed(success))
|
||||
if (FoundPoly > 0 && dtStatusSucceed(success))
|
||||
{
|
||||
return Vector(NavNearest[0], -NavNearest[2], NavNearest[1]);
|
||||
}
|
||||
|
@ -5754,7 +5781,7 @@ Vector UTIL_ProjectPointToNavmesh(const Vector Location, const nav_profile &NavP
|
|||
|
||||
dtStatus success = m_navQuery->findNearestPoly(pCheckLoc, pExtents, m_navFilter, &FoundPoly, NavNearest);
|
||||
|
||||
if (dtStatusSucceed(success))
|
||||
if (FoundPoly > 0 && dtStatusSucceed(success))
|
||||
{
|
||||
return Vector(NavNearest[0], -NavNearest[2], NavNearest[1]);
|
||||
}
|
||||
|
@ -5781,7 +5808,7 @@ Vector UTIL_ProjectPointToNavmesh(const Vector Location, const Vector Extents, c
|
|||
|
||||
dtStatus success = m_navQuery->findNearestPoly(pCheckLoc, fExtents, m_navFilter, &FoundPoly, NavNearest);
|
||||
|
||||
if (dtStatusSucceed(success))
|
||||
if (FoundPoly > 0 && dtStatusSucceed(success))
|
||||
{
|
||||
return Vector(NavNearest[0], -NavNearest[2], NavNearest[1]);
|
||||
}
|
||||
|
|
|
@ -1420,7 +1420,19 @@ void StartNewBotFrame(AvHAIPlayer* pBot)
|
|||
|
||||
ClearBotInputs(pBot);
|
||||
pBot->CurrentEyePosition = GetPlayerEyePosition(pEdict);
|
||||
|
||||
pBot->CurrentFloorPosition = UTIL_GetEntityGroundLocation(pEdict);
|
||||
|
||||
if (vDist3DSq(pBot->BotNavInfo.LastNavMeshCheckPosition, pBot->CurrentFloorPosition) > sqrf(16.0f))
|
||||
{
|
||||
if (UTIL_PointIsReachable(pBot->BotNavInfo.NavProfile, AITAC_GetTeamStartingLocation(pBot->Player->GetTeam()), pBot->CurrentFloorPosition, 16.0f))
|
||||
{
|
||||
pBot->BotNavInfo.LastNavMeshPosition = pBot->CurrentFloorPosition;
|
||||
}
|
||||
|
||||
pBot->BotNavInfo.LastNavMeshCheckPosition = pBot->CurrentFloorPosition;
|
||||
}
|
||||
|
||||
pBot->LookTargetLocation = ZERO_VECTOR;
|
||||
pBot->MoveLookLocation = ZERO_VECTOR;
|
||||
pBot->LookTarget = nullptr;
|
||||
|
@ -1465,6 +1477,8 @@ void StartNewBotFrame(AvHAIPlayer* pBot)
|
|||
UpdateCommanderOrders(pBot);
|
||||
}
|
||||
|
||||
UTIL_DrawLine(INDEXENT(1), pBot->Edict->v.origin, pBot->BotNavInfo.LastNavMeshPosition);
|
||||
|
||||
}
|
||||
|
||||
void DroneThink(AvHAIPlayer* pBot)
|
||||
|
|
|
@ -13,7 +13,7 @@
|
|||
double last_think_time = 0.0;
|
||||
float BotDeltaTime = 0.01666667f;
|
||||
|
||||
AvHAIPlayer ActiveAIPlayers[MAX_PLAYERS];
|
||||
vector<AvHAIPlayer> ActiveAIPlayers;
|
||||
|
||||
extern cvar_t avh_botautomode;
|
||||
extern cvar_t avh_botsenabled;
|
||||
|
@ -69,6 +69,19 @@ string BotNames[MAX_PLAYERS] = { "MrRobot",
|
|||
|
||||
void AIMGR_UpdateAIPlayerCounts()
|
||||
{
|
||||
for (auto BotIt = ActiveAIPlayers.begin(); BotIt != ActiveAIPlayers.end();)
|
||||
{
|
||||
// If bot has been kicked from the server then remove from active AI player list
|
||||
if (FNullEnt(BotIt->Edict) || BotIt->Edict->free || !BotIt->Player)
|
||||
{
|
||||
BotIt = ActiveAIPlayers.erase(BotIt);
|
||||
}
|
||||
else
|
||||
{
|
||||
BotIt++;
|
||||
}
|
||||
}
|
||||
|
||||
// Don't add or remove bots too quickly, otherwise it can cause lag or even overflows
|
||||
if (gpGlobals->time - LastAIPlayerCountUpdate < 0.2f) { return; }
|
||||
|
||||
|
@ -94,11 +107,6 @@ void AIMGR_UpdateAIPlayerCounts()
|
|||
return;
|
||||
}
|
||||
|
||||
if (avh_botautomode.value == 0) // Manual mode: do nothing, server can manually add/remove as they want
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (avh_botautomode.value == 1) // Balance only: bots will only be added and removed to ensure teams remain balanced
|
||||
{
|
||||
AIMGR_UpdateTeamBalance();
|
||||
|
@ -110,6 +118,9 @@ void AIMGR_UpdateAIPlayerCounts()
|
|||
AIMGR_UpdateFillTeams();
|
||||
return;
|
||||
}
|
||||
|
||||
// Assume manual mode: do nothing, host can manually add/remove as they wish via sv_addaiplayer
|
||||
return;
|
||||
}
|
||||
|
||||
void AIMGR_UpdateTeamBalance()
|
||||
|
@ -255,14 +266,14 @@ void AIMGR_RemoveAIPlayerFromTeam(int Team)
|
|||
// resources tied up in them or are commanding, which could cause big disruption to the team they're leaving
|
||||
|
||||
int MinValue = 0; // Track the least valuable bot on the desired team.
|
||||
int IndexToKick = -1; // Current bot to be kicked
|
||||
vector<AvHAIPlayer>::iterator ItemToRemove = ActiveAIPlayers.end(); // Current bot to be kicked
|
||||
|
||||
for (int i = 0; i < MAX_PLAYERS; i++)
|
||||
for (auto it = ActiveAIPlayers.begin(); it != ActiveAIPlayers.end(); it++)
|
||||
{
|
||||
// Don't kick if the slot is empty, or the bot in that slot isn't on the right team
|
||||
if (!ActiveAIPlayers[i].Player || ActiveAIPlayers[i].Player->GetTeam() != DesiredTeam) { continue; }
|
||||
if (it->Player->GetTeam() != DesiredTeam) { continue; }
|
||||
|
||||
AvHPlayer* theAIPlayer = ActiveAIPlayers[i].Player;
|
||||
AvHPlayer* theAIPlayer = it->Player;
|
||||
|
||||
float BotValue = theAIPlayer->GetResources();
|
||||
|
||||
|
@ -305,18 +316,19 @@ void AIMGR_RemoveAIPlayerFromTeam(int Team)
|
|||
break;
|
||||
}
|
||||
|
||||
if (IndexToKick < 0 || BotValue < MinValue)
|
||||
if (ItemToRemove == ActiveAIPlayers.end() || BotValue < MinValue)
|
||||
{
|
||||
IndexToKick = i;
|
||||
ItemToRemove = it;
|
||||
MinValue = BotValue;
|
||||
}
|
||||
}
|
||||
|
||||
if (IndexToKick > -1)
|
||||
|
||||
if (ItemToRemove != ActiveAIPlayers.end())
|
||||
{
|
||||
ActiveAIPlayers[IndexToKick].Player->Kick();
|
||||
ItemToRemove->Player->Kick();
|
||||
|
||||
memset(&ActiveAIPlayers[IndexToKick], 0, sizeof(AvHAIPlayer));
|
||||
ActiveAIPlayers.erase(ItemToRemove);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -332,22 +344,6 @@ void AIMGR_AddAIPlayerToTeam(int Team)
|
|||
return;
|
||||
}
|
||||
|
||||
|
||||
for (int i = 0; i < gpGlobals->maxClients; i++)
|
||||
{
|
||||
if (!ActiveAIPlayers[i].Player)
|
||||
{
|
||||
NewBotIndex = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (NewBotIndex < 0)
|
||||
{
|
||||
ALERT(at_console, "Bot limit reached, cannot add more\n");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!NavmeshLoaded())
|
||||
{
|
||||
CONFIG_ParseConfigFile();
|
||||
|
@ -360,12 +356,30 @@ void AIMGR_AddAIPlayerToTeam(int Team)
|
|||
}
|
||||
}
|
||||
|
||||
if (ActiveAIPlayers.size() >= gpGlobals->maxClients)
|
||||
{
|
||||
ALERT(at_console, "Bot limit reached, cannot add more\n");
|
||||
return;
|
||||
}
|
||||
|
||||
if (AIMGR_GetNumAIPlayers() == 0)
|
||||
{
|
||||
// Initialise the name index to a random number so we don't always get the same bot names
|
||||
BotNameIndex = RANDOM_LONG(0, 31);
|
||||
}
|
||||
|
||||
// Retrieve the current bot name and then cycle the index so the names are always unique
|
||||
// Slap a [BOT] tag too so players know they're not human
|
||||
string NewName = CONFIG_GetBotPrefix() + BotNames[BotNameIndex];
|
||||
|
||||
BotEnt = (*g_engfuncs.pfnCreateFakeClient)(NewName.c_str());
|
||||
|
||||
if (FNullEnt(BotEnt))
|
||||
{
|
||||
ALERT(at_console, "Failed to create AI player: server is full\n");
|
||||
return;
|
||||
}
|
||||
|
||||
AvHTeamNumber DesiredTeam = TEAM_IND;
|
||||
|
||||
AvHTeamNumber teamA = GetGameRules()->GetTeamANumber();
|
||||
|
@ -376,12 +390,6 @@ void AIMGR_AddAIPlayerToTeam(int Team)
|
|||
DesiredTeam = (Team == 1) ? teamA : teamB;
|
||||
}
|
||||
|
||||
// Retrieve the current bot name and then cycle the index so the names are always unique
|
||||
// Slap a [BOT] tag too so players know they're not human
|
||||
string NewName = CONFIG_GetBotPrefix() + BotNames[BotNameIndex];
|
||||
|
||||
BotEnt = (*g_engfuncs.pfnCreateFakeClient)(NewName.c_str());
|
||||
|
||||
BotNameIndex++;
|
||||
|
||||
if (BotNameIndex > 31)
|
||||
|
@ -389,12 +397,6 @@ void AIMGR_AddAIPlayerToTeam(int Team)
|
|||
BotNameIndex = 0;
|
||||
}
|
||||
|
||||
if (!BotEnt)
|
||||
{
|
||||
ALERT(at_console, "Failed to create AI player: server is full\n");
|
||||
return;
|
||||
}
|
||||
|
||||
char ptr[128]; // allocate space for message from ClientConnect
|
||||
int clientIndex;
|
||||
|
||||
|
@ -431,6 +433,17 @@ void AIMGR_AddAIPlayerToTeam(int Team)
|
|||
|
||||
if (theNewAIPlayer)
|
||||
{
|
||||
AvHAIPlayer NewAIPlayer;
|
||||
NewAIPlayer.Player = theNewAIPlayer;
|
||||
NewAIPlayer.Edict = BotEnt;
|
||||
NewAIPlayer.Team = theNewAIPlayer->GetTeam();
|
||||
|
||||
const bot_skill BotSkillSettings = CONFIG_GetGlobalBotSkillLevel();
|
||||
|
||||
memcpy(&NewAIPlayer.BotSkillSettings, &BotSkillSettings, sizeof(bot_skill));
|
||||
|
||||
ActiveAIPlayers.push_back(NewAIPlayer);
|
||||
|
||||
if (DesiredTeam != TEAM_IND)
|
||||
{
|
||||
ALERT(at_console, "Adding AI Player to team: %d\n", (int)Team);
|
||||
|
@ -441,16 +454,6 @@ void AIMGR_AddAIPlayerToTeam(int Team)
|
|||
ALERT(at_console, "Auto-assigning AI Player to team\n");
|
||||
GetGameRules()->AutoAssignPlayer(theNewAIPlayer);
|
||||
}
|
||||
|
||||
ActiveAIPlayers[NewBotIndex].Player = theNewAIPlayer;
|
||||
ActiveAIPlayers[NewBotIndex].Edict = BotEnt;
|
||||
ActiveAIPlayers[NewBotIndex].Team = theNewAIPlayer->GetTeam();
|
||||
|
||||
AvHAIPlayer* NewBotRef = &ActiveAIPlayers[NewBotIndex];
|
||||
|
||||
const bot_skill BotSkillSettings = CONFIG_GetGlobalBotSkillLevel();
|
||||
|
||||
memcpy(&NewBotRef->BotSkillSettings, &BotSkillSettings, sizeof(bot_skill));
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -497,11 +500,16 @@ void AIMGR_UpdateAIPlayers()
|
|||
float FrameDelta = CurrTime - PrevTime;
|
||||
float ThinkDelta = CurrTime - LastThinkTime;
|
||||
|
||||
for (int bot_index = 0; bot_index < gpGlobals->maxClients; bot_index++)
|
||||
for (auto BotIt = ActiveAIPlayers.begin(); BotIt != ActiveAIPlayers.end();)
|
||||
{
|
||||
if (!ActiveAIPlayers[bot_index].Player) { continue; } // Slot isn't filled
|
||||
// If bot has been kicked from the server then remove from active AI player list
|
||||
if (FNullEnt(BotIt->Edict) || BotIt->Edict->free || !BotIt->Player)
|
||||
{
|
||||
BotIt = ActiveAIPlayers.erase(BotIt);
|
||||
continue;
|
||||
}
|
||||
|
||||
AvHAIPlayer* bot = &ActiveAIPlayers[bot_index];
|
||||
AvHAIPlayer* bot = &(*BotIt);
|
||||
|
||||
BotUpdateViewRotation(bot, FrameDelta);
|
||||
|
||||
|
@ -548,7 +556,9 @@ void AIMGR_UpdateAIPlayers()
|
|||
bot->SideMove, bot->UpMove, bot->Button, bot->Impulse, adjustedmsec);
|
||||
|
||||
LastThinkTime = gpGlobals->time;
|
||||
}
|
||||
}
|
||||
|
||||
BotIt++;
|
||||
}
|
||||
|
||||
PrevTime = CurrTime;
|
||||
|
@ -562,26 +572,16 @@ float AIMGR_GetBotDeltaTime()
|
|||
|
||||
int AIMGR_GetNumAIPlayers()
|
||||
{
|
||||
int Result = 0;
|
||||
|
||||
for (int i = 0; i < MAX_PLAYERS; i++)
|
||||
{
|
||||
if (ActiveAIPlayers[i].Player != nullptr)
|
||||
{
|
||||
Result++;
|
||||
}
|
||||
}
|
||||
|
||||
return Result;
|
||||
return ActiveAIPlayers.size();
|
||||
}
|
||||
|
||||
int AIMGR_GetNumAIPlayersOnTeam(AvHTeamNumber Team)
|
||||
{
|
||||
int Result = 0;
|
||||
|
||||
for (int i = 0; i < MAX_PLAYERS; i++)
|
||||
for (auto it = ActiveAIPlayers.begin(); it != ActiveAIPlayers.end(); it++)
|
||||
{
|
||||
if (ActiveAIPlayers[i].Player != nullptr && ActiveAIPlayers[i].Team == Team)
|
||||
if (it->Player->GetTeam() == Team)
|
||||
{
|
||||
Result++;
|
||||
}
|
||||
|
@ -592,9 +592,9 @@ int AIMGR_GetNumAIPlayersOnTeam(AvHTeamNumber Team)
|
|||
|
||||
int AIMGR_AIPlayerExistsOnTeam(AvHTeamNumber Team)
|
||||
{
|
||||
for (int i = 0; i < MAX_PLAYERS; i++)
|
||||
for (auto it = ActiveAIPlayers.begin(); it != ActiveAIPlayers.end(); it++)
|
||||
{
|
||||
if (ActiveAIPlayers[i].Player != nullptr && ActiveAIPlayers[i].Team == Team)
|
||||
if (it->Player->GetTeam() == Team)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
@ -605,13 +605,16 @@ int AIMGR_AIPlayerExistsOnTeam(AvHTeamNumber Team)
|
|||
|
||||
void AIMGR_RemoveBotsInReadyRoom()
|
||||
{
|
||||
for (int i = 0; i < MAX_PLAYERS; i++)
|
||||
for (auto it = ActiveAIPlayers.begin(); it != ActiveAIPlayers.end();)
|
||||
{
|
||||
if (ActiveAIPlayers[i].Player != nullptr && ActiveAIPlayers[i].Player->GetInReadyRoom())
|
||||
if (it->Player->GetInReadyRoom())
|
||||
{
|
||||
ActiveAIPlayers[i].Player->Kick();
|
||||
|
||||
memset(&ActiveAIPlayers[i], 0, sizeof(AvHAIPlayer));
|
||||
it->Player->Kick();
|
||||
it = ActiveAIPlayers.erase(it);
|
||||
}
|
||||
else
|
||||
{
|
||||
it++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -638,7 +641,18 @@ void AIMGR_ResetRound()
|
|||
|
||||
void AIMGR_ClearBotData()
|
||||
{
|
||||
memset(&ActiveAIPlayers, 0, sizeof(ActiveAIPlayers));
|
||||
// We shouldn't have any bots in the server when this is called, but this ensures no bots end up "orphans" and no longer tracked by the system
|
||||
for (auto it = ActiveAIPlayers.begin(); it != ActiveAIPlayers.end();)
|
||||
{
|
||||
if (!FNullEnt(it->Edict) && it->Player)
|
||||
{
|
||||
it->Player->Kick();
|
||||
}
|
||||
|
||||
it = ActiveAIPlayers.erase(it);
|
||||
}
|
||||
|
||||
ActiveAIPlayers.clear();
|
||||
}
|
||||
|
||||
void AIMGR_NewMap()
|
||||
|
@ -671,11 +685,11 @@ AvHAIPlayer* AIMGR_GetAICommander(AvHTeamNumber Team)
|
|||
|
||||
if (!ActiveCommander) { return nullptr; }
|
||||
|
||||
for (int i = 0; i < MAX_PLAYERS; i++)
|
||||
for (auto it = ActiveAIPlayers.begin(); it != ActiveAIPlayers.end(); it++)
|
||||
{
|
||||
if (ActiveAIPlayers[i].Player == ActiveCommander)
|
||||
if (it->Player == ActiveCommander)
|
||||
{
|
||||
return &ActiveAIPlayers[i];
|
||||
return &(*it);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -684,33 +698,34 @@ AvHAIPlayer* AIMGR_GetAICommander(AvHTeamNumber Team)
|
|||
|
||||
AvHAIPlayer* AIMGR_FindPlayerOnTeamWaitingBuildLink(const AvHTeamNumber Team, const AvHAIDeployableStructureType NewStructure, const Vector BuildLocation)
|
||||
{
|
||||
for (int i = 0; i < MAX_PLAYERS; i++)
|
||||
vector<AvHAIPlayer*> TeamPlayers = AIMGR_GetAIPlayersOnTeam(Team);
|
||||
|
||||
for (auto it = TeamPlayers.begin(); it != TeamPlayers.end(); it++)
|
||||
{
|
||||
if (ActiveAIPlayers[i].Player != nullptr && ActiveAIPlayers[i].Player->GetTeam() == Team)
|
||||
AvHAIPlayer* AIPlayer = (*it);
|
||||
|
||||
if (AIPlayer->PrimaryBotTask.bIsWaitingForBuildLink && AIPlayer->PrimaryBotTask.StructureType == NewStructure)
|
||||
{
|
||||
if (ActiveAIPlayers[i].PrimaryBotTask.bIsWaitingForBuildLink && ActiveAIPlayers[i].PrimaryBotTask.StructureType == NewStructure)
|
||||
if (vDist2DSq(BuildLocation, AIPlayer->PrimaryBotTask.TaskLocation) < sqrf(UTIL_MetresToGoldSrcUnits(2.0f)))
|
||||
{
|
||||
if (vDist2DSq(BuildLocation, ActiveAIPlayers[i].PrimaryBotTask.TaskLocation) < sqrf(UTIL_MetresToGoldSrcUnits(2.0f)))
|
||||
{
|
||||
return &ActiveAIPlayers[i];
|
||||
}
|
||||
|
||||
return AIPlayer;
|
||||
}
|
||||
|
||||
if (ActiveAIPlayers[i].SecondaryBotTask.bIsWaitingForBuildLink && ActiveAIPlayers[i].SecondaryBotTask.StructureType == NewStructure)
|
||||
{
|
||||
if (vDist2DSq(BuildLocation, ActiveAIPlayers[i].SecondaryBotTask.TaskLocation) < sqrf(UTIL_MetresToGoldSrcUnits(2.0f)))
|
||||
{
|
||||
return &ActiveAIPlayers[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (ActiveAIPlayers[i].WantsAndNeedsTask.bIsWaitingForBuildLink && ActiveAIPlayers[i].WantsAndNeedsTask.StructureType == NewStructure)
|
||||
if (AIPlayer->SecondaryBotTask.bIsWaitingForBuildLink && AIPlayer->SecondaryBotTask.StructureType == NewStructure)
|
||||
{
|
||||
if (vDist2DSq(BuildLocation, AIPlayer->SecondaryBotTask.TaskLocation) < sqrf(UTIL_MetresToGoldSrcUnits(2.0f)))
|
||||
{
|
||||
if (vDist2DSq(BuildLocation, ActiveAIPlayers[i].WantsAndNeedsTask.TaskLocation) < sqrf(UTIL_MetresToGoldSrcUnits(2.0f)))
|
||||
{
|
||||
return &ActiveAIPlayers[i];
|
||||
}
|
||||
return AIPlayer;
|
||||
}
|
||||
}
|
||||
|
||||
if (AIPlayer->WantsAndNeedsTask.bIsWaitingForBuildLink && AIPlayer->WantsAndNeedsTask.StructureType == NewStructure)
|
||||
{
|
||||
if (vDist2DSq(BuildLocation, AIPlayer->WantsAndNeedsTask.TaskLocation) < sqrf(UTIL_MetresToGoldSrcUnits(2.0f)))
|
||||
{
|
||||
return AIPlayer;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -726,11 +741,39 @@ AvHTeamNumber AIMGR_GetEnemyTeam(const AvHTeamNumber FriendlyTeam)
|
|||
return (FriendlyTeam == TeamANumber) ? TeamBNumber : TeamANumber;
|
||||
}
|
||||
|
||||
AvHAIPlayer* AIMGR_GetAIPlayerAtIndex(const int Index)
|
||||
vector<AvHAIPlayer*> AIMGR_GetAllAIPlayers()
|
||||
{
|
||||
if (Index < 0 || Index >= MAX_PLAYERS) { return nullptr; }
|
||||
vector<AvHAIPlayer*> Result;
|
||||
|
||||
return &ActiveAIPlayers[Index];
|
||||
Result.clear();
|
||||
|
||||
for (auto BotIt = ActiveAIPlayers.begin(); BotIt != ActiveAIPlayers.end(); BotIt++)
|
||||
{
|
||||
if (FNullEnt(BotIt->Edict)) { continue; }
|
||||
|
||||
Result.push_back(&(*BotIt));
|
||||
}
|
||||
|
||||
return Result;
|
||||
}
|
||||
|
||||
vector<AvHAIPlayer*> AIMGR_GetAIPlayersOnTeam(AvHTeamNumber Team)
|
||||
{
|
||||
vector<AvHAIPlayer*> Result;
|
||||
|
||||
Result.clear();
|
||||
|
||||
for (auto BotIt = ActiveAIPlayers.begin(); BotIt != ActiveAIPlayers.end(); BotIt++)
|
||||
{
|
||||
if (FNullEnt(BotIt->Edict)) { continue; }
|
||||
|
||||
if (BotIt->Player->GetTeam() == Team)
|
||||
{
|
||||
Result.push_back(&(*BotIt));
|
||||
}
|
||||
}
|
||||
|
||||
return Result;
|
||||
}
|
||||
|
||||
void AIMGR_UpdateAIMapData()
|
||||
|
|
|
@ -49,7 +49,8 @@ AvHAIPlayer* AIMGR_FindPlayerOnTeamWaitingBuildLink(const AvHTeamNumber Team, co
|
|||
|
||||
AvHTeamNumber AIMGR_GetEnemyTeam(const AvHTeamNumber FriendlyTeam);
|
||||
|
||||
AvHAIPlayer* AIMGR_GetAIPlayerAtIndex(const int Index);
|
||||
vector<AvHAIPlayer*> AIMGR_GetAllAIPlayers();
|
||||
vector<AvHAIPlayer*> AIMGR_GetAIPlayersOnTeam(AvHTeamNumber Team);
|
||||
|
||||
void AIMGR_ClearBotData();
|
||||
|
||||
|
|
|
@ -2542,11 +2542,13 @@ void AITASK_GenerateGuardWatchPoints(AvHAIPlayer* pBot, const Vector& GuardLocat
|
|||
|
||||
bool BotWithBuildTaskExists(AvHTeamNumber Team, AvHAIDeployableStructureType StructureType)
|
||||
{
|
||||
for (int i = 0; i < MAX_PLAYERS; i++)
|
||||
{
|
||||
AvHAIPlayer* Bot = AIMGR_GetAIPlayerAtIndex(i);
|
||||
vector<AvHAIPlayer*> AIPlayers = AIMGR_GetAIPlayersOnTeam(Team);
|
||||
|
||||
if (!Bot || FNullEnt(Bot->Edict) || Bot->Player->GetTeam() != Team || !IsPlayerActiveInGame(Bot->Edict)) { continue; }
|
||||
for (auto it = AIPlayers.begin(); it != AIPlayers.end(); it++)
|
||||
{
|
||||
AvHAIPlayer* Bot = (*it);
|
||||
|
||||
if (!IsPlayerActiveInGame(Bot->Edict)) { continue; }
|
||||
|
||||
if ((Bot->PrimaryBotTask.TaskType == TASK_BUILD && Bot->PrimaryBotTask.StructureType == StructureType) || (Bot->SecondaryBotTask.TaskType == TASK_BUILD && Bot->SecondaryBotTask.StructureType == StructureType))
|
||||
{
|
||||
|
@ -2559,11 +2561,13 @@ bool BotWithBuildTaskExists(AvHTeamNumber Team, AvHAIDeployableStructureType Str
|
|||
|
||||
AvHAIPlayer* GetFirstBotWithBuildTask(AvHTeamNumber Team, AvHAIDeployableStructureType StructureType, edict_t* IgnorePlayer)
|
||||
{
|
||||
for (int i = 0; i < MAX_PLAYERS; i++)
|
||||
{
|
||||
AvHAIPlayer* Bot = AIMGR_GetAIPlayerAtIndex(i);
|
||||
vector<AvHAIPlayer*> AIPlayers = AIMGR_GetAIPlayersOnTeam(Team);
|
||||
|
||||
if (!Bot || FNullEnt(Bot->Edict) || Bot->Player->GetTeam() != Team || !IsPlayerActiveInGame(Bot->Edict)) { continue; }
|
||||
for (auto it = AIPlayers.begin(); it != AIPlayers.end(); it++)
|
||||
{
|
||||
AvHAIPlayer* Bot = (*it);
|
||||
|
||||
if (!IsPlayerActiveInGame(Bot->Edict)) { continue; }
|
||||
|
||||
bool bPrimaryIsBuildTask = (Bot->PrimaryBotTask.TaskType == TASK_BUILD || Bot->PrimaryBotTask.TaskType == TASK_REINFORCE_STRUCTURE);
|
||||
bool bSecondaryIsBuildTask = (Bot->SecondaryBotTask.TaskType == TASK_BUILD || Bot->SecondaryBotTask.TaskType == TASK_REINFORCE_STRUCTURE);
|
||||
|
@ -2572,6 +2576,7 @@ AvHAIPlayer* GetFirstBotWithBuildTask(AvHTeamNumber Team, AvHAIDeployableStructu
|
|||
{
|
||||
return Bot;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
|
@ -2579,11 +2584,13 @@ AvHAIPlayer* GetFirstBotWithBuildTask(AvHTeamNumber Team, AvHAIDeployableStructu
|
|||
|
||||
AvHAIPlayer* GetFirstBotWithReinforceTask(AvHTeamNumber Team, edict_t* ReinforceStructure, edict_t* IgnorePlayer)
|
||||
{
|
||||
for (int i = 0; i < MAX_PLAYERS; i++)
|
||||
{
|
||||
AvHAIPlayer* Bot = AIMGR_GetAIPlayerAtIndex(i);
|
||||
vector<AvHAIPlayer*> AIPlayers = AIMGR_GetAIPlayersOnTeam(Team);
|
||||
|
||||
if (!Bot || FNullEnt(Bot->Edict) || Bot->Player->GetTeam() != Team || !IsPlayerActiveInGame(Bot->Edict)) { continue; }
|
||||
for (auto it = AIPlayers.begin(); it != AIPlayers.end(); it++)
|
||||
{
|
||||
AvHAIPlayer* Bot = (*it);
|
||||
|
||||
if (!IsPlayerActiveInGame(Bot->Edict)) { continue; }
|
||||
|
||||
if ((Bot->PrimaryBotTask.TaskType == TASK_REINFORCE_STRUCTURE && Bot->PrimaryBotTask.TaskTarget == ReinforceStructure) || (Bot->SecondaryBotTask.TaskType == TASK_REINFORCE_STRUCTURE && Bot->SecondaryBotTask.TaskTarget == ReinforceStructure))
|
||||
{
|
||||
|
@ -2808,7 +2815,7 @@ void AITASK_SetMoveTask(AvHAIPlayer* pBot, AvHAIPlayerTask* Task, const Vector L
|
|||
Task->TaskType = TASK_MOVE;
|
||||
Task->TaskLocation = MoveLocation;
|
||||
Task->bTaskIsUrgent = bIsUrgent;
|
||||
Task->TaskLength = 60.0f; // Set a maximum time to reach destination. Helps avoid bots getting permanently stuck
|
||||
Task->TaskLength = 120.0f; // Set a maximum time to reach destination. Helps avoid bots getting permanently stuck
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue