mirror of
https://github.com/ENSL/NS.git
synced 2024-11-10 15:21:54 +00:00
Bot improvements
This commit is contained in:
parent
0df89d9abe
commit
8c9b150ba5
19 changed files with 813 additions and 392 deletions
|
@ -131,6 +131,7 @@ cvar_t avh_botminplayers = { kvBotMinPlayers,"0", FCVAR_SERVER }; // If bots
|
||||||
cvar_t avh_botskill = { kvBotSkill,"0", FCVAR_SERVER }; // Sets the skill for the bots (0 = easiest, 3 = hardest)
|
cvar_t avh_botskill = { kvBotSkill,"0", FCVAR_SERVER }; // Sets the skill for the bots (0 = easiest, 3 = hardest)
|
||||||
cvar_t avh_botusemapdefaults = { kvBotUseMapDefaults,"0", FCVAR_SERVER }; // If bot auto mode == 1 then the min players will be taken from the config
|
cvar_t avh_botusemapdefaults = { kvBotUseMapDefaults,"0", FCVAR_SERVER }; // If bot auto mode == 1 then the min players will be taken from the config
|
||||||
cvar_t avh_botcommandermode = { kvBotCommanderMode,"0", FCVAR_SERVER }; // 0 = Bots never command, 1 = If nobody takes charge, 2 = Only if no humans on team
|
cvar_t avh_botcommandermode = { kvBotCommanderMode,"0", FCVAR_SERVER }; // 0 = Bots never command, 1 = If nobody takes charge, 2 = Only if no humans on team
|
||||||
|
cvar_t avh_botdebugmode = { kvBotDebugMode,"0", FCVAR_SERVER }; // 0 = Regular play, 1 = Drone mode, 2 = Test Navigation mode
|
||||||
|
|
||||||
|
|
||||||
//playtest cvars
|
//playtest cvars
|
||||||
|
@ -222,6 +223,7 @@ void GameDLLInit( void )
|
||||||
CVAR_REGISTER(&avh_botusemapdefaults);
|
CVAR_REGISTER(&avh_botusemapdefaults);
|
||||||
CVAR_REGISTER(&avh_botskill);
|
CVAR_REGISTER(&avh_botskill);
|
||||||
CVAR_REGISTER(&avh_botcommandermode);
|
CVAR_REGISTER(&avh_botcommandermode);
|
||||||
|
CVAR_REGISTER(&avh_botdebugmode);
|
||||||
|
|
||||||
// Register AvH variables
|
// Register AvH variables
|
||||||
CVAR_REGISTER (&avh_drawdamage);
|
CVAR_REGISTER (&avh_drawdamage);
|
||||||
|
|
|
@ -897,6 +897,10 @@ bool AICOMM_IsRequestValid(ai_commander_request* Request)
|
||||||
return !PlayerHasWeapon(PlayerRef, WEAPON_MARINE_HMG)
|
return !PlayerHasWeapon(PlayerRef, WEAPON_MARINE_HMG)
|
||||||
&& !AITAC_ItemExistsInLocation(Requestor->v.origin, DEPLOYABLE_ITEM_HMG, RequestorTeam, AI_REACHABILITY_MARINE, 0.0f, UTIL_MetresToGoldSrcUnits(5.0f), false)
|
&& !AITAC_ItemExistsInLocation(Requestor->v.origin, DEPLOYABLE_ITEM_HMG, RequestorTeam, AI_REACHABILITY_MARINE, 0.0f, UTIL_MetresToGoldSrcUnits(5.0f), false)
|
||||||
&& AITAC_IsCompletedStructureOfTypeNearLocation(RequestorTeam, STRUCTURE_MARINE_ADVARMOURY, Requestor->v.origin, UTIL_MetresToGoldSrcUnits(5.0f));
|
&& AITAC_IsCompletedStructureOfTypeNearLocation(RequestorTeam, STRUCTURE_MARINE_ADVARMOURY, Requestor->v.origin, UTIL_MetresToGoldSrcUnits(5.0f));
|
||||||
|
case BUILD_GRENADE_GUN:
|
||||||
|
return !PlayerHasWeapon(PlayerRef, WEAPON_MARINE_GL)
|
||||||
|
&& !AITAC_ItemExistsInLocation(Requestor->v.origin, DEPLOYABLE_ITEM_GRENADELAUNCHER, RequestorTeam, AI_REACHABILITY_MARINE, 0.0f, UTIL_MetresToGoldSrcUnits(5.0f), false)
|
||||||
|
&& AITAC_IsCompletedStructureOfTypeNearLocation(RequestorTeam, STRUCTURE_MARINE_ADVARMOURY, Requestor->v.origin, UTIL_MetresToGoldSrcUnits(5.0f));
|
||||||
case BUILD_MINES:
|
case BUILD_MINES:
|
||||||
return !PlayerHasWeapon(PlayerRef, WEAPON_MARINE_MINES)
|
return !PlayerHasWeapon(PlayerRef, WEAPON_MARINE_MINES)
|
||||||
&& !AITAC_ItemExistsInLocation(Requestor->v.origin, DEPLOYABLE_ITEM_MINES, RequestorTeam, AI_REACHABILITY_MARINE, 0.0f, UTIL_MetresToGoldSrcUnits(5.0f), false)
|
&& !AITAC_ItemExistsInLocation(Requestor->v.origin, DEPLOYABLE_ITEM_MINES, RequestorTeam, AI_REACHABILITY_MARINE, 0.0f, UTIL_MetresToGoldSrcUnits(5.0f), false)
|
||||||
|
@ -952,8 +956,6 @@ bool AICOMM_CheckForNextBuildAction(AvHAIPlayer* pBot)
|
||||||
|
|
||||||
AvHAIBuildableStructure* BaseArmoury = AITAC_FindClosestDeployableToLocation(CommChair->v.origin, &StructureFilter);
|
AvHAIBuildableStructure* BaseArmoury = AITAC_FindClosestDeployableToLocation(CommChair->v.origin, &StructureFilter);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
if (!BaseArmoury && !FNullEnt(BaseBuilder))
|
if (!BaseArmoury && !FNullEnt(BaseBuilder))
|
||||||
{
|
{
|
||||||
|
|
||||||
|
@ -2529,7 +2531,45 @@ bool AICOMM_CheckForNextSupportAction(AvHAIPlayer* pBot)
|
||||||
|
|
||||||
NextRequest->bResponded = bSuccess;
|
NextRequest->bResponded = bSuccess;
|
||||||
return true;
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (NextRequest->RequestType == BUILD_GRENADE_GUN)
|
||||||
|
{
|
||||||
|
if (pBot->Player->GetResources() < BALANCE_VAR(kGrenadeLauncherCost)) { return false; }
|
||||||
|
|
||||||
|
DeployableSearchFilter ArmouryFilter;
|
||||||
|
ArmouryFilter.DeployableTeam = CommanderTeam;
|
||||||
|
ArmouryFilter.DeployableTypes = STRUCTURE_MARINE_ADVARMOURY;
|
||||||
|
ArmouryFilter.IncludeStatusFlags = STRUCTURE_STATUS_COMPLETED;
|
||||||
|
ArmouryFilter.ExcludeStatusFlags = STRUCTURE_STATUS_RECYCLING;
|
||||||
|
|
||||||
|
AvHAIBuildableStructure* NearestArmoury = AITAC_FindClosestDeployableToLocation(Requestor->v.origin, &ArmouryFilter);
|
||||||
|
|
||||||
|
if (!NearestArmoury)
|
||||||
|
{
|
||||||
|
NextRequest->bResponded = true;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
Vector DeployLocation = UTIL_GetRandomPointOnNavmeshInRadius(GetBaseNavProfile(STRUCTURE_BASE_NAV_PROFILE), NearestArmoury->Location, UTIL_MetresToGoldSrcUnits(4.0f));
|
||||||
|
|
||||||
|
if (vIsZero(DeployLocation))
|
||||||
|
{
|
||||||
|
DeployLocation = UTIL_GetRandomPointOnNavmeshInRadius(GetBaseNavProfile(MARINE_BASE_NAV_PROFILE), NearestArmoury->Location, UTIL_MetresToGoldSrcUnits(4.0f));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (vIsZero(DeployLocation))
|
||||||
|
{
|
||||||
|
NextRequest->bResponded = true;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool bSuccess = AICOMM_DeployItem(pBot, DEPLOYABLE_ITEM_GRENADELAUNCHER, DeployLocation);
|
||||||
|
|
||||||
|
NextRequest->ResponseAttempts++;
|
||||||
|
|
||||||
|
NextRequest->bResponded = bSuccess;
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (NextRequest->RequestType == BUILD_PHASEGATE)
|
if (NextRequest->RequestType == BUILD_PHASEGATE)
|
||||||
|
@ -3002,7 +3042,6 @@ bool AICOMM_ShouldBeacon(AvHAIPlayer* pBot)
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void AICOMM_ReceiveChatRequest(AvHAIPlayer* Commander, edict_t* Requestor, const char* Request)
|
void AICOMM_ReceiveChatRequest(AvHAIPlayer* Commander, edict_t* Requestor, const char* Request)
|
||||||
|
@ -3021,6 +3060,10 @@ void AICOMM_ReceiveChatRequest(AvHAIPlayer* Commander, edict_t* Requestor, const
|
||||||
{
|
{
|
||||||
NewRequestType = BUILD_HMG;
|
NewRequestType = BUILD_HMG;
|
||||||
}
|
}
|
||||||
|
else if (!stricmp(Request, "gl"))
|
||||||
|
{
|
||||||
|
NewRequestType = BUILD_GRENADE_GUN;
|
||||||
|
}
|
||||||
else if (!stricmp(Request, "mines"))
|
else if (!stricmp(Request, "mines"))
|
||||||
{
|
{
|
||||||
NewRequestType = BUILD_MINES;
|
NewRequestType = BUILD_MINES;
|
||||||
|
|
|
@ -563,6 +563,7 @@ typedef struct _NAV_STATUS
|
||||||
|
|
||||||
Vector LastNavMeshCheckPosition = g_vecZero;
|
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 LastNavMeshPosition = g_vecZero; // Tracks the last place the bot was on the nav mesh. Useful if accidentally straying off it
|
||||||
|
Vector LastOpenLocation = g_vecZero; // Tracks the last place the bot had enough room to move around people. Useful if in a vent and need to back up somewhere to let another player past.
|
||||||
|
|
||||||
int CurrentMoveType = MOVETYPE_NONE; // Tracks the edict's current movement type
|
int CurrentMoveType = MOVETYPE_NONE; // Tracks the edict's current movement type
|
||||||
|
|
||||||
|
|
|
@ -20,12 +20,12 @@ bool UTIL_CommanderTrace(const edict_t* pEdict, const Vector& start, const Vecto
|
||||||
return (hit.flFraction >= 1.0f);
|
return (hit.flFraction >= 1.0f);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool UTIL_QuickTrace(const edict_t* pEdict, const Vector& start, const Vector& end)
|
bool UTIL_QuickTrace(const edict_t* pEdict, const Vector& start, const Vector& end, bool bAllowStartSolid)
|
||||||
{
|
{
|
||||||
TraceResult hit;
|
TraceResult hit;
|
||||||
edict_t* IgnoreEdict = (!FNullEnt(pEdict)) ? pEdict->v.pContainingEntity : NULL;
|
edict_t* IgnoreEdict = (!FNullEnt(pEdict)) ? pEdict->v.pContainingEntity : NULL;
|
||||||
UTIL_TraceLine(start, end, ignore_monsters, ignore_glass, IgnoreEdict, &hit);
|
UTIL_TraceLine(start, end, ignore_monsters, ignore_glass, IgnoreEdict, &hit);
|
||||||
return (hit.flFraction >= 1.0f && !hit.fAllSolid);
|
return (hit.flFraction >= 1.0f && !hit.fAllSolid && (bAllowStartSolid || !hit.fStartSolid));
|
||||||
}
|
}
|
||||||
|
|
||||||
bool UTIL_QuickHullTrace(const edict_t* pEdict, const Vector& start, const Vector& end, bool bAllowStartSolid)
|
bool UTIL_QuickHullTrace(const edict_t* pEdict, const Vector& start, const Vector& end, bool bAllowStartSolid)
|
||||||
|
@ -175,12 +175,12 @@ Vector UTIL_GetFloorUnderEntity(const edict_t* Edict)
|
||||||
return Edict->v.origin;
|
return Edict->v.origin;
|
||||||
}
|
}
|
||||||
|
|
||||||
Vector UTIL_GetClosestPointOnEntityToLocation(const Vector Location, edict_t* Entity)
|
Vector UTIL_GetClosestPointOnEntityToLocation(const Vector Location, const edict_t* Entity)
|
||||||
{
|
{
|
||||||
return Vector(clampf(Location.x, Entity->v.absmin.x, Entity->v.absmax.x), clampf(Location.y, Entity->v.absmin.y, Entity->v.absmax.y), clampf(Location.z, Entity->v.absmin.z, Entity->v.absmax.z));
|
return Vector(clampf(Location.x, Entity->v.absmin.x, Entity->v.absmax.x), clampf(Location.y, Entity->v.absmin.y, Entity->v.absmax.y), clampf(Location.z, Entity->v.absmin.z, Entity->v.absmax.z));
|
||||||
}
|
}
|
||||||
|
|
||||||
Vector UTIL_GetClosestPointOnEntityToLocation(const Vector Location, edict_t* Entity, const Vector EntityLocation)
|
Vector UTIL_GetClosestPointOnEntityToLocation(const Vector Location, const edict_t* Entity, const Vector EntityLocation)
|
||||||
{
|
{
|
||||||
Vector MinVec = EntityLocation - (Entity->v.size * 0.5f);
|
Vector MinVec = EntityLocation - (Entity->v.size * 0.5f);
|
||||||
Vector MaxVec = EntityLocation + (Entity->v.size * 0.5f);
|
Vector MaxVec = EntityLocation + (Entity->v.size * 0.5f);
|
||||||
|
|
|
@ -7,7 +7,7 @@
|
||||||
#include "AvHAIConstants.h"
|
#include "AvHAIConstants.h"
|
||||||
|
|
||||||
bool UTIL_CommanderTrace(const edict_t* pEdict, const Vector& start, const Vector& end);
|
bool UTIL_CommanderTrace(const edict_t* pEdict, const Vector& start, const Vector& end);
|
||||||
bool UTIL_QuickTrace(const edict_t* pEdict, const Vector& start, const Vector& end);
|
bool UTIL_QuickTrace(const edict_t* pEdict, const Vector& start, const Vector& end, bool bAllowStartSolid = false);
|
||||||
bool UTIL_QuickHullTrace(const edict_t* pEdict, const Vector& start, const Vector& end, bool bAllowStartSolid = false);
|
bool UTIL_QuickHullTrace(const edict_t* pEdict, const Vector& start, const Vector& end, bool bAllowStartSolid = false);
|
||||||
bool UTIL_QuickHullTrace(const edict_t* pEdict, const Vector& start, const Vector& end, int hullNum, bool bAllowStartSolid = false);
|
bool UTIL_QuickHullTrace(const edict_t* pEdict, const Vector& start, const Vector& end, int hullNum, bool bAllowStartSolid = false);
|
||||||
edict_t* UTIL_TraceEntity(const edict_t* pEdict, const Vector& start, const Vector& end);
|
edict_t* UTIL_TraceEntity(const edict_t* pEdict, const Vector& start, const Vector& end);
|
||||||
|
@ -19,8 +19,8 @@ Vector UTIL_GetEntityGroundLocation(const edict_t* pEntity);
|
||||||
Vector UTIL_GetCentreOfEntity(const edict_t* Entity);
|
Vector UTIL_GetCentreOfEntity(const edict_t* Entity);
|
||||||
Vector UTIL_GetFloorUnderEntity(const edict_t* Edict);
|
Vector UTIL_GetFloorUnderEntity(const edict_t* Edict);
|
||||||
|
|
||||||
Vector UTIL_GetClosestPointOnEntityToLocation(const Vector UserLocation, edict_t* Entity);
|
Vector UTIL_GetClosestPointOnEntityToLocation(const Vector UserLocation, const edict_t* Entity);
|
||||||
Vector UTIL_GetClosestPointOnEntityToLocation(const Vector Location, edict_t* Entity, const Vector EntityLocation);
|
Vector UTIL_GetClosestPointOnEntityToLocation(const Vector Location, const edict_t* Entity, const Vector EntityLocation);
|
||||||
|
|
||||||
AvHAIDeployableStructureType IUSER3ToStructureType(const int inIUSER3);
|
AvHAIDeployableStructureType IUSER3ToStructureType(const int inIUSER3);
|
||||||
|
|
||||||
|
|
|
@ -65,6 +65,61 @@ bool vBBOverlaps2D(const Vector MinBBA, const Vector MaxBBA, const Vector MinBBB
|
||||||
&& (MinBBA.y < MaxBBB.y && MaxBBA.y > MinBBB.y));
|
&& (MinBBA.y < MaxBBB.y && MaxBBA.y > MinBBB.y));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Given three collinear points p, q, r, the function checks if
|
||||||
|
// point q lies on line segment 'pr'
|
||||||
|
bool onSegment(Vector p, Vector q, Vector r)
|
||||||
|
{
|
||||||
|
if (q.x <= fmaxf(p.x, r.x) && q.x >= fminf(p.x, r.x) &&
|
||||||
|
q.y <= fmaxf(p.y, r.y) && q.y >= fminf(p.y, r.y))
|
||||||
|
return true;
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// To find orientation of ordered triplet (p, q, r).
|
||||||
|
// The function returns following values
|
||||||
|
// 0 --> p, q and r are collinear
|
||||||
|
// 1 --> Clockwise
|
||||||
|
// 2 --> Counterclockwise
|
||||||
|
int orientation(Vector p, Vector q, Vector r)
|
||||||
|
{
|
||||||
|
// See https://www.geeksforgeeks.org/orientation-3-ordered-points/
|
||||||
|
// for details of below formula.
|
||||||
|
int val = (q.y - p.y) * (r.x - q.x) -
|
||||||
|
(q.x - p.x) * (r.y - q.y);
|
||||||
|
|
||||||
|
if (val == 0) return 0; // collinear
|
||||||
|
|
||||||
|
return (val > 0) ? 1 : 2; // clock or counterclock wise
|
||||||
|
}
|
||||||
|
|
||||||
|
bool vIntersects2D(const Vector LineAStart, const Vector LineAEnd, const Vector LineBStart, const Vector LineBEnd)
|
||||||
|
{
|
||||||
|
int o1 = orientation(LineAStart, LineAEnd, LineBStart);
|
||||||
|
int o2 = orientation(LineAStart, LineAEnd, LineBEnd);
|
||||||
|
int o3 = orientation(LineBStart, LineBEnd, LineAStart);
|
||||||
|
int o4 = orientation(LineBStart, LineBEnd, LineAEnd);
|
||||||
|
|
||||||
|
// General case
|
||||||
|
if (o1 != o2 && o3 != o4)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
// Special Cases
|
||||||
|
// p1, q1 and p2 are collinear and p2 lies on segment p1q1
|
||||||
|
if (o1 == 0 && onSegment(LineAStart, LineBStart, LineAEnd)) return true;
|
||||||
|
|
||||||
|
// p1, q1 and q2 are collinear and q2 lies on segment p1q1
|
||||||
|
if (o2 == 0 && onSegment(LineAStart, LineBEnd, LineAEnd)) return true;
|
||||||
|
|
||||||
|
// p2, q2 and p1 are collinear and p1 lies on segment p2q2
|
||||||
|
if (o3 == 0 && onSegment(LineBStart, LineAStart, LineBEnd)) return true;
|
||||||
|
|
||||||
|
// p2, q2 and q1 are collinear and q1 lies on segment p2q2
|
||||||
|
if (o4 == 0 && onSegment(LineBStart, LineAEnd, LineBEnd)) return true;
|
||||||
|
|
||||||
|
return false; // Doesn't fall in any of the above cases
|
||||||
|
}
|
||||||
|
|
||||||
Vector vClosestPointOnBB(const Vector Point, const Vector MinBB, const Vector MaxBB)
|
Vector vClosestPointOnBB(const Vector Point, const Vector MinBB, const Vector MaxBB)
|
||||||
{
|
{
|
||||||
return Vector(clampf(Point.x, MinBB.x, MaxBB.x), clampf(Point.y, MinBB.y, MaxBB.y), clampf(Point.z, MinBB.z, MaxBB.z));
|
return Vector(clampf(Point.x, MinBB.x, MaxBB.x), clampf(Point.y, MinBB.y, MaxBB.y), clampf(Point.z, MinBB.z, MaxBB.z));
|
||||||
|
|
|
@ -118,6 +118,9 @@ Vector UTIL_GetSurfaceNormal(const Vector v1, const Vector v2, const Vector v3);
|
||||||
bool vPointOverlaps3D(const Vector Point, const Vector MinBB, const Vector MaxBB);
|
bool vPointOverlaps3D(const Vector Point, const Vector MinBB, const Vector MaxBB);
|
||||||
bool vPointOverlaps2D(const Vector Point, const Vector MinBB, const Vector MaxBB);
|
bool vPointOverlaps2D(const Vector Point, const Vector MinBB, const Vector MaxBB);
|
||||||
bool vBBOverlaps2D(const Vector MinBBA, const Vector MaxBBA, const Vector MinBBB, const Vector MaxBBB);
|
bool vBBOverlaps2D(const Vector MinBBA, const Vector MaxBBA, const Vector MinBBB, const Vector MaxBBB);
|
||||||
|
// For the two lines provided, returns true if they cross each other on the X and Y axis
|
||||||
|
bool vIntersects2D(const Vector LineAStart, const Vector LineAEnd, const Vector LineBStart, const Vector LineBEnd);
|
||||||
|
|
||||||
|
|
||||||
Vector vClosestPointOnBB(const Vector Point, const Vector MinBB, const Vector MaxBB);
|
Vector vClosestPointOnBB(const Vector Point, const Vector MinBB, const Vector MaxBB);
|
||||||
|
|
||||||
|
|
|
@ -313,15 +313,21 @@ void AIDEBUG_DrawOffMeshConnections(float DrawTime)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void UTIL_UpdateTileCache()
|
bool UTIL_UpdateTileCache()
|
||||||
{
|
{
|
||||||
|
bTileCacheUpToDate = true;
|
||||||
|
|
||||||
for (int i = 0; i < MAX_NAV_MESHES; i++)
|
for (int i = 0; i < MAX_NAV_MESHES; i++)
|
||||||
{
|
{
|
||||||
if (NavMeshes[i].tileCache)
|
if (NavMeshes[i].tileCache)
|
||||||
{
|
{
|
||||||
NavMeshes[i].tileCache->update(0.0f, NavMeshes[i].navMesh, &bTileCacheUpToDate);
|
bool bUpToDate;
|
||||||
|
NavMeshes[i].tileCache->update(0.0f, NavMeshes[i].navMesh, &bUpToDate);
|
||||||
|
if (!bUpToDate) { bTileCacheUpToDate = false; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return bTileCacheUpToDate;
|
||||||
}
|
}
|
||||||
|
|
||||||
Vector UTIL_AdjustPointAwayFromNavWall(const Vector Location, const float MaxDistanceFromWall)
|
Vector UTIL_AdjustPointAwayFromNavWall(const Vector Location, const float MaxDistanceFromWall)
|
||||||
|
@ -1274,16 +1280,16 @@ Vector AdjustPointForPathfinding(const Vector Point)
|
||||||
{
|
{
|
||||||
Vector TraceStart = ProjectedPoint + Vector(0.0f, 0.0f, 32.0f);
|
Vector TraceStart = ProjectedPoint + Vector(0.0f, 0.0f, 32.0f);
|
||||||
Vector TraceEnd = TraceStart - Vector(0.0f, 0.0f, 50.0f);
|
Vector TraceEnd = TraceStart - Vector(0.0f, 0.0f, 50.0f);
|
||||||
Vector NewPoint = UTIL_GetHullTraceHitLocation(TraceStart, TraceEnd, head_hull);
|
Vector NewPoint = UTIL_GetHullTraceHitLocation(TraceStart, TraceEnd, point_hull);
|
||||||
|
|
||||||
if (!vIsZero(NewPoint)) { return NewPoint; }
|
if (!vIsZero(NewPoint)) { return NewPoint; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
Vector TraceStart = ProjectedPoint + Vector(0.0f, 0.0f, 32.0f);
|
Vector TraceStart = ProjectedPoint + Vector(0.0f, 0.0f, 5.0f);
|
||||||
Vector TraceEnd = TraceStart - Vector(0.0f, 0.0f, 50.0f);
|
Vector TraceEnd = TraceStart - Vector(0.0f, 0.0f, 32.0f);
|
||||||
Vector NewPoint = UTIL_GetHullTraceHitLocation(TraceStart, TraceEnd, head_hull);
|
Vector NewPoint = UTIL_GetHullTraceHitLocation(TraceStart, TraceEnd, point_hull);
|
||||||
|
|
||||||
if (!vIsZero(NewPoint)) { return NewPoint; }
|
if (!vIsZero(NewPoint)) { return NewPoint; }
|
||||||
}
|
}
|
||||||
|
@ -1369,31 +1375,14 @@ dtStatus FindFlightPathToPoint(const nav_profile &NavProfile, Vector FromLocatio
|
||||||
|
|
||||||
m_navQuery->closestPointOnPoly(PolyPath[nPathCount - 1], EndNearest, epos, 0);
|
m_navQuery->closestPointOnPoly(PolyPath[nPathCount - 1], EndNearest, epos, 0);
|
||||||
|
|
||||||
float DistToEnd = dtVdist(EndNearest, epos);
|
if (dtVdistSqr(EndNearest, epos) > sqrf(MaxAcceptableDistance))
|
||||||
|
|
||||||
if (DistToEnd > MaxAcceptableDistance)
|
|
||||||
{
|
{
|
||||||
// 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
|
return DT_FAILURE;
|
||||||
Vector StartTrace = Vector(EndNearest[0], -EndNearest[2], EndNearest[1]);
|
}
|
||||||
StartTrace.z += 20.0f;
|
else
|
||||||
|
{
|
||||||
TraceResult hit;
|
dtVcopy(EndNearest, epos);
|
||||||
|
|
||||||
UTIL_TraceHull(StartTrace, ToLocation, ignore_monsters, head_hull, nullptr, &hit);
|
|
||||||
|
|
||||||
float Reached = (!hit.fAllSolid && !hit.fStartSolid) ? hit.flFraction : 0.0f;
|
|
||||||
|
|
||||||
float DesiredDist = vDist3D(StartTrace, ToLocation);
|
|
||||||
float ActualDist = DesiredDist * Reached;
|
|
||||||
|
|
||||||
// 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_ALL_CROSSINGS);
|
status = m_navQuery->findStraightPath(StartNearest, EndNearest, PolyPath, nPathCount, StraightPath, straightPathFlags, StraightPolyPath, &nVertCount, MAX_AI_PATH_SIZE, DT_STRAIGHTPATH_ALL_CROSSINGS);
|
||||||
|
@ -1559,7 +1548,7 @@ Vector UTIL_FindHighestSuccessfulTracePoint(const Vector TraceFrom, const Vector
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (NextPoint != ZERO_VECTOR && UTIL_QuickHullTrace(nullptr, CurrentTarget, NextPoint, head_hull))
|
if (!vIsZero(NextPoint) && UTIL_QuickHullTrace(nullptr, CurrentTarget, NextPoint, head_hull, false))
|
||||||
{
|
{
|
||||||
CurrentHighest = CurrentTarget;
|
CurrentHighest = CurrentTarget;
|
||||||
}
|
}
|
||||||
|
@ -1841,7 +1830,6 @@ dtStatus FindPathClosestToPoint(AvHAIPlayer* pBot, const BotMoveStyle MoveStyle,
|
||||||
// At this point we have our path. Copy it to the path store
|
// At this point we have our path. Copy it to the path store
|
||||||
int nIndex = 0;
|
int nIndex = 0;
|
||||||
TraceResult hit;
|
TraceResult hit;
|
||||||
Vector TraceStart;
|
|
||||||
|
|
||||||
pBot->BotNavInfo.SpecialMovementFlags = 0;
|
pBot->BotNavInfo.SpecialMovementFlags = 0;
|
||||||
|
|
||||||
|
@ -1860,16 +1848,11 @@ dtStatus FindPathClosestToPoint(AvHAIPlayer* pBot, const BotMoveStyle MoveStyle,
|
||||||
|
|
||||||
NextPathNode.Location = UTIL_AdjustPointAwayFromNavWall(NextPathNode.Location, 16.0f);
|
NextPathNode.Location = UTIL_AdjustPointAwayFromNavWall(NextPathNode.Location, 16.0f);
|
||||||
|
|
||||||
TraceStart.x = NextPathNode.Location.x;
|
|
||||||
TraceStart.y = NextPathNode.Location.y;
|
|
||||||
TraceStart.z = NextPathNode.Location.z + 18.0f;
|
|
||||||
|
|
||||||
NextPathNode.Location = AdjustPointForPathfinding(NextPathNode.Location);
|
NextPathNode.Location = AdjustPointForPathfinding(NextPathNode.Location);
|
||||||
|
|
||||||
if ((CurrFlags != SAMPLE_POLYFLAGS_JUMP && CurrFlags != SAMPLE_POLYFLAGS_WALLCLIMB) || NextPathNode.FromLocation.z > NextPathNode.Location.z)
|
if ((CurrFlags != SAMPLE_POLYFLAGS_JUMP && CurrFlags != SAMPLE_POLYFLAGS_WALLCLIMB) || NextPathNode.FromLocation.z > NextPathNode.Location.z)
|
||||||
{
|
{
|
||||||
|
NextPathNode.Location.z += GetPlayerOriginOffsetFromFloor(pBot->Edict, (CurrArea == SAMPLE_POLYAREA_CROUCH)).z;
|
||||||
NextPathNode.Location.z += 17.0f;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pBot->BotNavInfo.SpecialMovementFlags |= CurrFlags;
|
pBot->BotNavInfo.SpecialMovementFlags |= CurrFlags;
|
||||||
|
@ -1897,54 +1880,6 @@ dtStatus FindPathClosestToPoint(AvHAIPlayer* pBot, const BotMoveStyle MoveStyle,
|
||||||
NextPathNode.requiredZ += 5.0f;
|
NextPathNode.requiredZ += 5.0f;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*if (IsPlayerSkulk(pBot->Edict) && CurrFlags == SAMPLE_POLYFLAGS_LADDER)
|
|
||||||
{
|
|
||||||
bool bIsGoingUpLadder = (NextPathNode.Location.z > NodeFromLocation.z);
|
|
||||||
|
|
||||||
Vector NearestLadderTopPoint = UTIL_GetNearestLadderTopPoint(NextPathNode.FromLocation);
|
|
||||||
Vector NearestLadderCentre = UTIL_GetNearestLadderCentrePoint(NextPathNode.FromLocation);
|
|
||||||
|
|
||||||
Vector LadderNormal = UTIL_GetVectorNormal2D(NextPathNode.FromLocation - NearestLadderCentre);
|
|
||||||
|
|
||||||
Vector OnLadderPoint = NearestLadderTopPoint;
|
|
||||||
OnLadderPoint.z = FromLocation.z;
|
|
||||||
OnLadderPoint = OnLadderPoint + (LadderNormal * 16.0f);
|
|
||||||
|
|
||||||
bot_path_node GetOnLadderNode;
|
|
||||||
GetOnLadderNode.area = CurrArea;
|
|
||||||
GetOnLadderNode.flag = SAMPLE_POLYFLAGS_WALLCLIMB;
|
|
||||||
GetOnLadderNode.FromLocation = FromLocation;
|
|
||||||
GetOnLadderNode.Location = OnLadderPoint;
|
|
||||||
GetOnLadderNode.requiredZ = FromLocation.z;
|
|
||||||
|
|
||||||
path.push_back(GetOnLadderNode);
|
|
||||||
|
|
||||||
bot_path_node EndLadderNode;
|
|
||||||
EndLadderNode.area = CurrArea;
|
|
||||||
EndLadderNode.flag = SAMPLE_POLYFLAGS_WALLCLIMB;
|
|
||||||
EndLadderNode.FromLocation = OnLadderPoint;
|
|
||||||
|
|
||||||
Vector EndClimbPoint = NearestLadderTopPoint;
|
|
||||||
EndClimbPoint.z = NewRequiredZ;
|
|
||||||
|
|
||||||
if (vDist2DSq(EndClimbPoint, OnLadderPoint) < sqrf(8.0f))
|
|
||||||
{
|
|
||||||
EndClimbPoint = EndClimbPoint - (LadderNormal * 8.0f);
|
|
||||||
}
|
|
||||||
|
|
||||||
EndLadderNode.Location = EndClimbPoint;
|
|
||||||
EndLadderNode.requiredZ = NewRequiredZ;
|
|
||||||
|
|
||||||
|
|
||||||
path.push_back(EndLadderNode);
|
|
||||||
|
|
||||||
FromLocation = EndClimbPoint;
|
|
||||||
|
|
||||||
CurrFlags = SAMPLE_POLYFLAGS_WALLCLIMB;
|
|
||||||
NextPathNode.FromLocation = FromLocation;
|
|
||||||
|
|
||||||
}*/
|
|
||||||
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -2029,120 +1964,182 @@ bool UTIL_PointIsReachable(const nav_profile &NavProfile, const Vector FromLocat
|
||||||
|
|
||||||
bool HasBotReachedPathPoint(const AvHAIPlayer* pBot)
|
bool HasBotReachedPathPoint(const AvHAIPlayer* pBot)
|
||||||
{
|
{
|
||||||
if (pBot->BotNavInfo.CurrentPath.size() == 0)
|
if (pBot->BotNavInfo.CurrentPath.size() == 0 || pBot->BotNavInfo.CurrentPathPoint == pBot->BotNavInfo.CurrentPath.end())
|
||||||
{
|
{
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (pBot->BotNavInfo.CurrentPathPoint == pBot->BotNavInfo.CurrentPath.end())
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
Vector CurrentPos = (pBot->BotNavInfo.IsOnGround) ? pBot->Edict->v.origin : pBot->CurrentFloorPosition;
|
|
||||||
|
|
||||||
edict_t* pEdict = pBot->Edict;
|
|
||||||
|
|
||||||
SamplePolyFlags CurrentNavFlag = (SamplePolyFlags)pBot->BotNavInfo.CurrentPathPoint->flag;
|
SamplePolyFlags CurrentNavFlag = (SamplePolyFlags)pBot->BotNavInfo.CurrentPathPoint->flag;
|
||||||
Vector MoveFrom = pBot->BotNavInfo.CurrentPathPoint->FromLocation;
|
Vector MoveFrom = pBot->BotNavInfo.CurrentPathPoint->FromLocation;
|
||||||
Vector MoveTo = pBot->BotNavInfo.CurrentPathPoint->Location;
|
Vector MoveTo = pBot->BotNavInfo.CurrentPathPoint->Location;
|
||||||
|
float RequiredClimbHeight = pBot->BotNavInfo.CurrentPathPoint->requiredZ;
|
||||||
|
|
||||||
|
Vector NextMoveLocation = ZERO_VECTOR;
|
||||||
|
SamplePolyFlags NextMoveFlag = SAMPLE_POLYFLAGS_DISABLED;
|
||||||
|
|
||||||
vector<bot_path_node>::iterator NextPathPoint = next(pBot->BotNavInfo.CurrentPathPoint);
|
vector<bot_path_node>::iterator NextPathPoint = next(pBot->BotNavInfo.CurrentPathPoint);
|
||||||
|
|
||||||
bool bIsAtFinalPathPoint = (NextPathPoint == pBot->BotNavInfo.CurrentPath.end());
|
if (NextPathPoint != pBot->BotNavInfo.CurrentPath.end())
|
||||||
|
{
|
||||||
Vector ClosestPointToPath = vClosestPointOnLine2D(MoveFrom, MoveTo, pEdict->v.origin);
|
NextMoveLocation = NextPathPoint->Location;
|
||||||
|
NextMoveFlag = (SamplePolyFlags)NextPathPoint->flag;
|
||||||
bool bDestIsDirectlyReachable = UTIL_PointIsDirectlyReachable(CurrentPos, MoveTo);
|
}
|
||||||
bool bAtOrPastDestination = vEquals2D(ClosestPointToPath, MoveTo, 8.0f) && bDestIsDirectlyReachable;
|
|
||||||
|
|
||||||
dtPolyRef BotPoly = pBot->BotNavInfo.CurrentPoly;
|
|
||||||
dtPolyRef DestinationPoly = pBot->BotNavInfo.CurrentPathPoint->poly;
|
|
||||||
|
|
||||||
float playerRadius = GetPlayerRadius(pBot->Player);
|
|
||||||
|
|
||||||
switch (CurrentNavFlag)
|
switch (CurrentNavFlag)
|
||||||
{
|
{
|
||||||
case SAMPLE_POLYFLAGS_WALK:
|
case SAMPLE_POLYFLAGS_WALK:
|
||||||
{
|
return HasBotCompletedWalkMove(pBot, MoveFrom, MoveTo, NextMoveLocation, NextMoveFlag);
|
||||||
if (!bIsAtFinalPathPoint)
|
case SAMPLE_POLYFLAGS_WELD:
|
||||||
{
|
case SAMPLE_POLYFLAGS_DOOR:
|
||||||
return (bAtOrPastDestination || (vDist2D(pEdict->v.origin, MoveTo) <= 8.0f && (fabs(pBot->CurrentFloorPosition.z - MoveTo.z) < 50.0f)));
|
case SAMPLE_POLYFLAGS_TEAM1STRUCTURE:
|
||||||
}
|
case SAMPLE_POLYFLAGS_TEAM2STRUCTURE:
|
||||||
else
|
return HasBotCompletedObstacleMove(pBot, MoveFrom, MoveTo, NextMoveLocation, NextMoveFlag);
|
||||||
{
|
case SAMPLE_POLYFLAGS_LADDER:
|
||||||
return ((vDist2D(pEdict->v.origin, MoveTo) < playerRadius && bDestIsDirectlyReachable) || bAtOrPastDestination);
|
return HasBotCompletedLadderMove(pBot, MoveFrom, MoveTo, NextMoveLocation, NextMoveFlag);
|
||||||
}
|
case SAMPLE_POLYFLAGS_FALL:
|
||||||
}
|
return HasBotCompletedFallMove(pBot, MoveFrom, MoveTo, NextMoveLocation, NextMoveFlag);
|
||||||
case SAMPLE_POLYFLAGS_BLOCKED:
|
case SAMPLE_POLYFLAGS_WALLCLIMB:
|
||||||
case SAMPLE_POLYFLAGS_TEAM1STRUCTURE:
|
return HasBotCompletedClimbMove(pBot, MoveFrom, MoveTo, RequiredClimbHeight, NextMoveLocation, NextMoveFlag);
|
||||||
case SAMPLE_POLYFLAGS_TEAM2STRUCTURE:
|
case SAMPLE_POLYFLAGS_JUMP:
|
||||||
return bAtOrPastDestination;
|
case SAMPLE_POLYFLAGS_DUCKJUMP:
|
||||||
case SAMPLE_POLYFLAGS_FALL:
|
case SAMPLE_POLYFLAGS_BLOCKED:
|
||||||
case SAMPLE_POLYFLAGS_JUMP:
|
return HasBotCompletedJumpMove(pBot, MoveFrom, MoveTo, NextMoveLocation, NextMoveFlag);
|
||||||
{
|
case SAMPLE_POLYFLAGS_TEAM1PHASEGATE:
|
||||||
if (!bIsAtFinalPathPoint)
|
case SAMPLE_POLYFLAGS_TEAM2PHASEGATE:
|
||||||
{
|
return HasBotCompletedPhaseGateMove(pBot, MoveFrom, MoveTo, NextMoveLocation, NextMoveFlag);
|
||||||
if (pBot->BotNavInfo.IsOnGround && fabsf(pEdict->v.origin.z - MoveTo.z) > 50.0f) { return false; }
|
case SAMPLE_POLYFLAGS_LIFT:
|
||||||
|
return HasBotCompletedLiftMove(pBot, MoveFrom, MoveTo, NextMoveLocation, NextMoveFlag);
|
||||||
Vector thisMoveDir = UTIL_GetVectorNormal2D(MoveTo - MoveFrom);
|
default:
|
||||||
Vector nextMoveDir = UTIL_GetVectorNormal2D(next(pBot->BotNavInfo.CurrentPathPoint)->Location - MoveTo);
|
return HasBotCompletedWalkMove(pBot, MoveFrom, MoveTo, NextMoveLocation, NextMoveFlag);
|
||||||
|
|
||||||
float DirectionDot = UTIL_GetDotProduct(thisMoveDir, nextMoveDir);
|
|
||||||
|
|
||||||
if (DirectionDot >= -0.5f)
|
|
||||||
{
|
|
||||||
return bAtOrPastDestination && UTIL_PointIsDirectlyReachable(pBot, pBot->CurrentFloorPosition, NextPathPoint->Location) && UTIL_QuickTrace(pBot->Edict, pBot->Edict->v.origin, NextPathPoint->Location);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
return bAtOrPastDestination && pBot->BotNavInfo.IsOnGround && fabs(pBot->CurrentFloorPosition.z - MoveTo.z) < 50.0f;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
return (vDist2D(pEdict->v.origin, MoveTo) <= playerRadius && fabsf(pEdict->v.origin.z - MoveTo.z) < 50.0f && pBot->BotNavInfo.IsOnGround);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
case SAMPLE_POLYFLAGS_WALLCLIMB:
|
|
||||||
{
|
|
||||||
if (!bIsAtFinalPathPoint && next(pBot->BotNavInfo.CurrentPathPoint)->flag == SAMPLE_POLYFLAGS_WALLCLIMB)
|
|
||||||
{
|
|
||||||
Vector ClosestPointToPath = vClosestPointOnLine(MoveFrom, MoveTo, pEdict->v.origin);
|
|
||||||
|
|
||||||
return vEquals(ClosestPointToPath, MoveTo, GetPlayerRadius(pBot->Player));
|
|
||||||
}
|
|
||||||
|
|
||||||
return bAtOrPastDestination && fabs(pEdict->v.origin.z - MoveTo.z) < 50.0f;
|
|
||||||
}
|
|
||||||
case SAMPLE_POLYFLAGS_LADDER:
|
|
||||||
{
|
|
||||||
if (MoveTo.z > MoveFrom.z)
|
|
||||||
{
|
|
||||||
return ((BotPoly == DestinationPoly) && UTIL_QuickTrace(pEdict, pEdict->v.origin, MoveTo));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
return (fabs(pBot->CollisionHullBottomLocation.z - MoveTo.z) < 50.0f);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
case SAMPLE_POLYFLAGS_TEAM1PHASEGATE:
|
|
||||||
case SAMPLE_POLYFLAGS_TEAM2PHASEGATE:
|
|
||||||
return (vDist2DSq(pBot->CurrentFloorPosition, MoveTo) < sqrf(32.0f));
|
|
||||||
case SAMPLE_POLYFLAGS_LIFT:
|
|
||||||
return bAtOrPastDestination;
|
|
||||||
default:
|
|
||||||
return (bAtOrPastDestination && UTIL_QuickTrace(pEdict, pEdict->v.origin, MoveTo));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return HasBotCompletedWalkMove(pBot, MoveFrom, MoveTo, NextMoveLocation, NextMoveFlag);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool HasBotCompletedLadderMove(AvHAIPlayer* pBot, Vector MoveStart, Vector MoveEnd)
|
bool HasBotCompletedWalkMove(const AvHAIPlayer* pBot, Vector MoveStart, Vector MoveEnd, Vector NextMoveDestination, SamplePolyFlags NextMoveFlag)
|
||||||
|
{
|
||||||
|
bool bNextPointReachable = false;
|
||||||
|
|
||||||
|
if (NextMoveFlag != SAMPLE_POLYFLAGS_DISABLED)
|
||||||
|
{
|
||||||
|
bNextPointReachable = UTIL_PointIsDirectlyReachable(pBot->CollisionHullBottomLocation, NextMoveDestination);
|
||||||
|
}
|
||||||
|
|
||||||
|
return vPointOverlaps3D(MoveEnd, pBot->Edict->v.absmin, pBot->Edict->v.absmax) || (bNextPointReachable && vDist2DSq(pBot->Edict->v.origin, MoveEnd) < sqrf(GetPlayerRadius(pBot->Edict) * 2.0f));
|
||||||
|
}
|
||||||
|
|
||||||
|
bool HasBotCompletedObstacleMove(const AvHAIPlayer* pBot, Vector MoveStart, Vector MoveEnd, Vector NextMoveDestination, SamplePolyFlags NextMoveFlag)
|
||||||
|
{
|
||||||
|
return vPointOverlaps3D(MoveEnd, pBot->Edict->v.absmin, pBot->Edict->v.absmax);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool HasBotCompletedLadderMove(const AvHAIPlayer* pBot, Vector MoveStart, Vector MoveEnd, Vector NextMoveDestination, SamplePolyFlags NextMoveFlag)
|
||||||
{
|
{
|
||||||
if (IsPlayerOnLadder(pBot->Edict)) { return false; }
|
if (IsPlayerOnLadder(pBot->Edict)) { return false; }
|
||||||
|
|
||||||
return UTIL_PointIsDirectlyReachable(pBot->CollisionHullBottomLocation, MoveEnd);
|
if (NextMoveFlag != SAMPLE_POLYFLAGS_DISABLED)
|
||||||
|
{
|
||||||
|
if (pBot->BotNavInfo.IsOnGround)
|
||||||
|
{
|
||||||
|
if (UTIL_PointIsDirectlyReachable(pBot->CollisionHullBottomLocation, NextMoveDestination)) { return true; }
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (vDist2DSq(pBot->Edict->v.origin, MoveEnd) < sqrf(GetPlayerRadius(pBot->Edict)) && UTIL_PointIsDirectlyReachable(pBot->CurrentFloorPosition, NextMoveDestination)) { return true; }
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
return vPointOverlaps3D(MoveEnd, pBot->Edict->v.absmin, pBot->Edict->v.absmax);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool HasBotCompletedFallMove(const AvHAIPlayer* pBot, Vector MoveStart, Vector MoveEnd, Vector NextMoveDestination, SamplePolyFlags NextMoveFlag)
|
||||||
|
{
|
||||||
|
if (NextMoveFlag != SAMPLE_POLYFLAGS_DISABLED)
|
||||||
|
{
|
||||||
|
Vector ThisMoveDir = UTIL_GetVectorNormal2D(MoveEnd - MoveStart);
|
||||||
|
Vector NextMoveDir = UTIL_GetVectorNormal2D(NextMoveDestination - MoveEnd);
|
||||||
|
|
||||||
|
float MoveDot = UTIL_GetDotProduct2D(ThisMoveDir, NextMoveDir);
|
||||||
|
|
||||||
|
if (MoveDot > 0.0f)
|
||||||
|
{
|
||||||
|
if (UTIL_PointIsDirectlyReachable(pBot->CurrentFloorPosition, NextMoveDestination)
|
||||||
|
&& UTIL_QuickTrace(pBot->Edict, pBot->Edict->v.origin, NextMoveDestination)
|
||||||
|
&& fabsf(pBot->CollisionHullBottomLocation.z - MoveEnd.z) < 100.0f) { return true; }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return vPointOverlaps3D(MoveEnd, pBot->Edict->v.absmin, pBot->Edict->v.absmax);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool HasBotCompletedClimbMove(const AvHAIPlayer* pBot, Vector MoveStart, Vector MoveEnd, float RequiredClimbHeight, Vector NextMoveDestination, SamplePolyFlags NextMoveFlag)
|
||||||
|
{
|
||||||
|
Vector PositionInMove = vClosestPointOnLine2D(MoveStart, MoveEnd, pBot->Edict->v.origin);
|
||||||
|
|
||||||
|
if (NextMoveFlag != SAMPLE_POLYFLAGS_DISABLED)
|
||||||
|
{
|
||||||
|
Vector ThisMoveDir = UTIL_GetVectorNormal2D(MoveEnd - MoveStart);
|
||||||
|
Vector NextMoveDir = UTIL_GetVectorNormal2D(NextMoveDestination - MoveEnd);
|
||||||
|
|
||||||
|
float MoveDot = UTIL_GetDotProduct2D(ThisMoveDir, NextMoveDir);
|
||||||
|
|
||||||
|
if (MoveDot > 0.0f)
|
||||||
|
{
|
||||||
|
if (pBot->Edict->v.origin.z >= RequiredClimbHeight && !pBot->BotNavInfo.IsOnGround)
|
||||||
|
{
|
||||||
|
if (UTIL_QuickTrace(pBot->Edict, pBot->Edict->v.origin, NextMoveDestination)
|
||||||
|
&& fabsf(pBot->CollisionHullBottomLocation.z - MoveEnd.z) < 100.0f)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!vEquals2D(PositionInMove, MoveEnd, 2.0f)) { return false; }
|
||||||
|
|
||||||
|
return vPointOverlaps3D(MoveEnd, pBot->Edict->v.absmin, pBot->Edict->v.absmax) && UTIL_PointIsDirectlyReachable(pBot->CurrentFloorPosition, NextMoveDestination);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool HasBotCompletedJumpMove(const AvHAIPlayer* pBot, Vector MoveStart, Vector MoveEnd, Vector NextMoveDestination, SamplePolyFlags NextMoveFlag)
|
||||||
|
{
|
||||||
|
Vector PositionInMove = vClosestPointOnLine2D(MoveStart, MoveEnd, pBot->Edict->v.origin);
|
||||||
|
|
||||||
|
if (!vEquals2D(PositionInMove, MoveEnd, 2.0f)) { return false; }
|
||||||
|
|
||||||
|
if (NextMoveFlag != SAMPLE_POLYFLAGS_DISABLED)
|
||||||
|
{
|
||||||
|
Vector ThisMoveDir = UTIL_GetVectorNormal2D(MoveEnd - MoveStart);
|
||||||
|
Vector NextMoveDir = UTIL_GetVectorNormal2D(NextMoveDestination - MoveEnd);
|
||||||
|
|
||||||
|
float MoveDot = UTIL_GetDotProduct2D(ThisMoveDir, NextMoveDir);
|
||||||
|
|
||||||
|
if (MoveDot >= 0.0f)
|
||||||
|
{
|
||||||
|
Vector HullTraceEnd = MoveEnd;
|
||||||
|
HullTraceEnd.z = pBot->Edict->v.origin.z;
|
||||||
|
|
||||||
|
if (UTIL_PointIsDirectlyReachable(pBot->CurrentFloorPosition, NextMoveDestination)
|
||||||
|
&& UTIL_QuickHullTrace(pBot->Edict, pBot->Edict->v.origin, HullTraceEnd, head_hull, false)
|
||||||
|
&& fabsf(pBot->CollisionHullBottomLocation.z - MoveEnd.z) < 100.0f)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return vPointOverlaps3D(MoveEnd, pBot->Edict->v.absmin, pBot->Edict->v.absmax);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool HasBotCompletedPhaseGateMove(const AvHAIPlayer* pBot, Vector MoveStart, Vector MoveEnd, Vector NextMoveDestination, SamplePolyFlags NextMoveFlag)
|
||||||
|
{
|
||||||
|
return vPointOverlaps3D(MoveEnd, pBot->Edict->v.absmin, pBot->Edict->v.absmax);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool HasBotCompletedLiftMove(const AvHAIPlayer* pBot, Vector MoveStart, Vector MoveEnd, Vector NextMoveDestination, SamplePolyFlags NextMoveFlag)
|
||||||
|
{
|
||||||
|
return vPointOverlaps3D(MoveEnd, pBot->Edict->v.absmin, pBot->Edict->v.absmax);
|
||||||
}
|
}
|
||||||
|
|
||||||
void CheckAndHandleDoorObstruction(AvHAIPlayer* pBot)
|
void CheckAndHandleDoorObstruction(AvHAIPlayer* pBot)
|
||||||
|
@ -3249,6 +3246,29 @@ void LadderMove(AvHAIPlayer* pBot, const Vector StartPoint, const Vector EndPoin
|
||||||
if (IsPlayerSkulk(pBot->Edict))
|
if (IsPlayerSkulk(pBot->Edict))
|
||||||
{
|
{
|
||||||
pBot->Button &= ~IN_DUCK;
|
pBot->Button &= ~IN_DUCK;
|
||||||
|
|
||||||
|
edict_t* Ladder = UTIL_GetNearestLadderAtPoint(StartPoint);
|
||||||
|
|
||||||
|
if (!FNullEnt(Ladder))
|
||||||
|
{
|
||||||
|
Vector LadderStart = Ladder->v.absmin;
|
||||||
|
Vector LadderEnd = Ladder->v.absmax;
|
||||||
|
LadderEnd.z = LadderStart.z;
|
||||||
|
|
||||||
|
// Basically, if we're directly climbing up or down the ladder, treat it like a wall. The below test will be false if the ladder is to one side
|
||||||
|
if (vIntersects2D(StartPoint, EndPoint, LadderStart, LadderEnd))
|
||||||
|
{
|
||||||
|
if (bIsGoingUpLadder)
|
||||||
|
{
|
||||||
|
WallClimbMove(pBot, StartPoint, EndPoint, RequiredClimbHeight);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
FallMove(pBot, StartPoint, EndPoint);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (IsPlayerOnLadder(pBot->Edict))
|
if (IsPlayerOnLadder(pBot->Edict))
|
||||||
|
@ -3489,6 +3509,12 @@ void LadderMove(AvHAIPlayer* pBot, const Vector StartPoint, const Vector EndPoin
|
||||||
{
|
{
|
||||||
LookLocation = EndPoint + (CurrentLadderNormal * 100.0f);
|
LookLocation = EndPoint + (CurrentLadderNormal * 100.0f);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// We're close enough to the end that we can jump off the ladder
|
||||||
|
if (UTIL_QuickTrace(pBot->Edict, pBot->Edict->v.origin, EndPoint) && (pBot->CollisionHullBottomLocation.z - EndPoint.z < 100.0f))
|
||||||
|
{
|
||||||
|
BotJump(pBot);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -3504,6 +3530,16 @@ void LadderMove(AvHAIPlayer* pBot, const Vector StartPoint, const Vector EndPoin
|
||||||
|
|
||||||
// We're not yet on the ladder
|
// We're not yet on the ladder
|
||||||
|
|
||||||
|
if (!pBot->BotNavInfo.IsOnGround && !bIsGoingUpLadder)
|
||||||
|
{
|
||||||
|
// We're close enough to the end that we can jump off the ladder
|
||||||
|
if (UTIL_QuickTrace(pBot->Edict, pBot->Edict->v.origin, EndPoint) && (pBot->CollisionHullBottomLocation.z - EndPoint.z < 100.0f))
|
||||||
|
{
|
||||||
|
pBot->desiredMovementDir = UTIL_GetVectorNormal2D(EndPoint - pBot->Edict->v.origin);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// If we're going down the ladder and are approaching it, just keep moving towards it
|
// If we're going down the ladder and are approaching it, just keep moving towards it
|
||||||
if ((pBot->BotNavInfo.IsOnGround || IsPlayerSkulk(pBot->Edict)) && !bIsGoingUpLadder)
|
if ((pBot->BotNavInfo.IsOnGround || IsPlayerSkulk(pBot->Edict)) && !bIsGoingUpLadder)
|
||||||
{
|
{
|
||||||
|
@ -3888,113 +3924,156 @@ void PhaseGateMove(AvHAIPlayer* pBot, const Vector StartPoint, const Vector EndP
|
||||||
|
|
||||||
bool IsBotOffPath(const AvHAIPlayer* pBot)
|
bool IsBotOffPath(const AvHAIPlayer* pBot)
|
||||||
{
|
{
|
||||||
|
if (pBot->BotNavInfo.CurrentPath.size() == 0 || pBot->BotNavInfo.CurrentPathPoint == pBot->BotNavInfo.CurrentPath.end())
|
||||||
// Can't be off the path if we don't have one...
|
|
||||||
if (pBot->BotNavInfo.CurrentPath.size() == 0 || pBot->BotNavInfo.CurrentPathPoint == pBot->BotNavInfo.CurrentPath.end()) { return false; }
|
|
||||||
|
|
||||||
if (pBot->BotNavInfo.CurrentPathPoint->flag == SAMPLE_POLYFLAGS_LIFT) { return false; }
|
|
||||||
|
|
||||||
// If we're trying to use a phase gate, then we're fine as long as there is a phase gate within reach at the start and end teleport points
|
|
||||||
if (pBot->BotNavInfo.CurrentPathPoint->flag == SAMPLE_POLYFLAGS_TEAM1PHASEGATE || pBot->BotNavInfo.CurrentPathPoint->flag == SAMPLE_POLYFLAGS_TEAM2PHASEGATE)
|
|
||||||
{
|
{
|
||||||
DeployableSearchFilter PGFilter;
|
return true;
|
||||||
PGFilter.DeployableTypes = STRUCTURE_MARINE_PHASEGATE;
|
|
||||||
PGFilter.MaxSearchRadius = UTIL_MetresToGoldSrcUnits(2.0f);
|
|
||||||
PGFilter.IncludeStatusFlags = STRUCTURE_STATUS_COMPLETED;
|
|
||||||
PGFilter.ExcludeStatusFlags = STRUCTURE_STATUS_RECYCLING;
|
|
||||||
PGFilter.DeployableTeam = (AvHTeamNumber)pBot->Edict->v.team;
|
|
||||||
|
|
||||||
// The phase gate we're meant to be using isn't here any more!
|
|
||||||
if (!AITAC_DeployableExistsAtLocation(pBot->Edict->v.origin, &PGFilter))
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// The phase gate we're meant to be warping to isn't there any more!
|
|
||||||
if (!AITAC_DeployableExistsAtLocation(pBot->BotNavInfo.CurrentPathPoint->Location, &PGFilter))
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
edict_t* pEdict = pBot->Edict;
|
SamplePolyFlags CurrentNavFlag = (SamplePolyFlags)pBot->BotNavInfo.CurrentPathPoint->flag;
|
||||||
|
Vector MoveFrom = pBot->BotNavInfo.CurrentPathPoint->FromLocation;
|
||||||
Vector MoveTo = pBot->BotNavInfo.CurrentPathPoint->Location;
|
Vector MoveTo = pBot->BotNavInfo.CurrentPathPoint->Location;
|
||||||
Vector MoveFrom = pBot->CurrentFloorPosition;
|
|
||||||
|
|
||||||
float PlayerRadiusSq = sqrf(GetPlayerRadius(pBot->Player));
|
Vector NextMoveLocation = ZERO_VECTOR;
|
||||||
float PlayerHeight = GetPlayerHeight(pBot->Edict, false);
|
SamplePolyFlags NextMoveFlag = SAMPLE_POLYFLAGS_DISABLED;
|
||||||
|
|
||||||
Vector vForward = UTIL_GetVectorNormal2D(MoveTo - MoveFrom);
|
vector<bot_path_node>::iterator NextPathPoint = next(pBot->BotNavInfo.CurrentPathPoint);
|
||||||
|
|
||||||
Vector PointOnPath = vClosestPointOnLine2D(MoveFrom, MoveTo, pBot->Edict->v.origin);
|
if (NextPathPoint != pBot->BotNavInfo.CurrentPath.end())
|
||||||
|
|
||||||
if (pBot->BotNavInfo.CurrentPathPoint->flag == SAMPLE_POLYFLAGS_WALLCLIMB)
|
|
||||||
{
|
{
|
||||||
return (vEquals(PointOnPath, MoveTo, 2.0f) && !IsPlayerClimbingWall(pBot->Edict) && pBot->CollisionHullTopLocation.z < MoveTo.z);
|
NextMoveLocation = NextPathPoint->Location;
|
||||||
|
NextMoveFlag = (SamplePolyFlags)NextPathPoint->flag;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Give us a chance to land before deciding we're off the path
|
switch (CurrentNavFlag)
|
||||||
if (!pBot->BotNavInfo.IsOnGround) { return false; }
|
|
||||||
|
|
||||||
if (pBot->BotNavInfo.CurrentPathPoint->flag == SAMPLE_POLYFLAGS_WALK)
|
|
||||||
{
|
{
|
||||||
|
case SAMPLE_POLYFLAGS_WALK:
|
||||||
if (vDist2DSq(pBot->Edict->v.origin, PointOnPath) > sqrf(100.0f)) { return true; }
|
return IsBotOffWalkNode(pBot, MoveFrom, MoveTo, NextMoveLocation, NextMoveFlag);
|
||||||
|
case SAMPLE_POLYFLAGS_WELD:
|
||||||
bool bAtMoveStart = vEquals(PointOnPath, MoveFrom, GetPlayerRadius(pBot->Player));
|
case SAMPLE_POLYFLAGS_DOOR:
|
||||||
|
case SAMPLE_POLYFLAGS_TEAM1STRUCTURE:
|
||||||
|
case SAMPLE_POLYFLAGS_TEAM2STRUCTURE:
|
||||||
// If we're on the from or to move points, but the height is significantly different, we must be under or over the path somehow
|
return IsBotOffObstacleNode(pBot, MoveFrom, MoveTo, NextMoveLocation, NextMoveFlag);
|
||||||
if (bAtMoveStart && fabs(pBot->CurrentFloorPosition.z - MoveFrom.z) > PlayerHeight)
|
case SAMPLE_POLYFLAGS_LADDER:
|
||||||
{
|
return IsBotOffLadderNode(pBot, MoveFrom, MoveTo, NextMoveLocation, NextMoveFlag);
|
||||||
return true;
|
case SAMPLE_POLYFLAGS_FALL:
|
||||||
}
|
return IsBotOffFallNode(pBot, MoveFrom, MoveTo, NextMoveLocation, NextMoveFlag);
|
||||||
|
case SAMPLE_POLYFLAGS_WALLCLIMB:
|
||||||
bool bAtMoveEnd = vEquals(PointOnPath, MoveTo, GetPlayerRadius(pBot->Player));
|
return IsBotOffClimbNode(pBot, MoveFrom, MoveTo, NextMoveLocation, NextMoveFlag);
|
||||||
|
case SAMPLE_POLYFLAGS_JUMP:
|
||||||
if (bAtMoveEnd && fabsf(pBot->CurrentFloorPosition.z - MoveTo.z) > PlayerHeight)
|
case SAMPLE_POLYFLAGS_DUCKJUMP:
|
||||||
{
|
case SAMPLE_POLYFLAGS_BLOCKED:
|
||||||
return true;
|
return IsBotOffJumpNode(pBot, MoveFrom, MoveTo, NextMoveLocation, NextMoveFlag);
|
||||||
}
|
case SAMPLE_POLYFLAGS_TEAM1PHASEGATE:
|
||||||
|
case SAMPLE_POLYFLAGS_TEAM2PHASEGATE:
|
||||||
float MaxDist = (bAtMoveStart || bAtMoveEnd) ? 50.0f : 200.0f;
|
return IsBotOffPhaseGateNode(pBot, MoveFrom, MoveTo, NextMoveLocation, NextMoveFlag);
|
||||||
|
case SAMPLE_POLYFLAGS_LIFT:
|
||||||
if (vDistanceFromLine2D(MoveFrom, MoveTo, pBot->CurrentFloorPosition) > MaxDist)
|
return IsBotOffLiftNode(pBot, MoveFrom, MoveTo, NextMoveLocation, NextMoveFlag);
|
||||||
{
|
default:
|
||||||
return true;
|
return IsBotOffWalkNode(pBot, MoveFrom, MoveTo, NextMoveLocation, NextMoveFlag);
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (pBot->BotNavInfo.CurrentPathPoint->flag == SAMPLE_POLYFLAGS_JUMP)
|
return IsBotOffWalkNode(pBot, MoveFrom, MoveTo, NextMoveLocation, NextMoveFlag);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
bool IsBotOffLadderNode(const AvHAIPlayer* pBot, Vector MoveStart, Vector MoveEnd, Vector NextMoveDestination, SamplePolyFlags NextMoveFlag)
|
||||||
|
{
|
||||||
|
if (!IsPlayerOnLadder(pBot->Edict))
|
||||||
{
|
{
|
||||||
Vector ExactJumpTarget = UTIL_GetGroundLocation(MoveTo);
|
if (IsPlayerClimbingWall(pBot->Edict)) { return true; }
|
||||||
|
|
||||||
if (pBot->BotNavInfo.IsOnGround && (ExactJumpTarget.z - pBot->CurrentFloorPosition.z) > max_player_jump_height)
|
if (pBot->BotNavInfo.IsOnGround)
|
||||||
{
|
{
|
||||||
return true;
|
if (!UTIL_PointIsDirectlyReachable(GetPlayerBottomOfCollisionHull(pBot->Edict), MoveStart) && !UTIL_PointIsDirectlyReachable(GetPlayerBottomOfCollisionHull(pBot->Edict), MoveEnd)) { return true; }
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (pBot->BotNavInfo.CurrentPathPoint->flag == SAMPLE_POLYFLAGS_FALL)
|
|
||||||
{
|
|
||||||
if (vEquals(PointOnPath, MoveTo, 2.0f) && fabs(pBot->CurrentFloorPosition.z - MoveTo.z) > PlayerHeight)
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool IsBotOffWalkNode(const AvHAIPlayer* pBot, Vector MoveStart, Vector MoveEnd, Vector NextMoveDestination, SamplePolyFlags NextMoveFlag)
|
||||||
|
{
|
||||||
|
if (!pBot->BotNavInfo.IsOnGround) { return false; }
|
||||||
|
|
||||||
|
Vector NearestPointOnLine = vClosestPointOnLine2D(MoveStart, MoveEnd, pBot->Edict->v.origin);
|
||||||
|
|
||||||
|
if (vDist2DSq(pBot->Edict->v.origin, NearestPointOnLine) > sqrf(GetPlayerRadius(pBot->Edict) * 3.0f)) { return true; }
|
||||||
|
|
||||||
|
if (vEquals2D(NearestPointOnLine, MoveStart) && !UTIL_PointIsDirectlyReachable(pBot->CollisionHullBottomLocation, MoveStart)) { return true; }
|
||||||
|
if (vEquals2D(NearestPointOnLine, MoveEnd) && !UTIL_PointIsDirectlyReachable(pBot->CollisionHullBottomLocation, MoveEnd)) { return true; }
|
||||||
|
|
||||||
|
return false;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
bool IsBotOffFallNode(const AvHAIPlayer* pBot, Vector MoveStart, Vector MoveEnd, Vector NextMoveDestination, SamplePolyFlags NextMoveFlag)
|
||||||
|
{
|
||||||
|
if (!pBot->BotNavInfo.IsOnGround) { return false; }
|
||||||
|
|
||||||
|
Vector NearestPointOnLine = vClosestPointOnLine2D(MoveStart, MoveEnd, pBot->Edict->v.origin);
|
||||||
|
|
||||||
|
if (!UTIL_PointIsDirectlyReachable(pBot->CurrentFloorPosition, MoveStart) && !UTIL_PointIsDirectlyReachable(pBot->CurrentFloorPosition, MoveEnd)) { return true; }
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool IsBotOffClimbNode(const AvHAIPlayer* pBot, Vector MoveStart, Vector MoveEnd, Vector NextMoveDestination, SamplePolyFlags NextMoveFlag)
|
||||||
|
{
|
||||||
|
if (pBot->BotNavInfo.IsOnGround)
|
||||||
|
{
|
||||||
|
return (!UTIL_PointIsDirectlyReachable(GetPlayerBottomOfCollisionHull(pBot->Edict), MoveStart) && !UTIL_PointIsDirectlyReachable(GetPlayerBottomOfCollisionHull(pBot->Edict), MoveEnd));
|
||||||
|
}
|
||||||
|
|
||||||
|
Vector ClosestPointOnLine = vClosestPointOnLine2D(MoveStart, MoveEnd, pBot->Edict->v.origin);
|
||||||
|
|
||||||
|
return vDist2DSq(pBot->Edict->v.origin, ClosestPointOnLine) > sqrf(GetPlayerRadius(pBot->Edict) * 3.0f);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool IsBotOffJumpNode(const AvHAIPlayer* pBot, Vector MoveStart, Vector MoveEnd, Vector NextMoveDestination, SamplePolyFlags NextMoveFlag)
|
||||||
|
{
|
||||||
|
if (!pBot->BotNavInfo.IsOnGround) { return false; }
|
||||||
|
|
||||||
|
Vector ClosestPointOnLine = vClosestPointOnLine2D(MoveStart, MoveEnd, pBot->Edict->v.origin);
|
||||||
|
|
||||||
|
if (vEquals2D(ClosestPointOnLine, MoveStart) || vEquals2D(ClosestPointOnLine, MoveEnd))
|
||||||
|
{
|
||||||
|
return (!UTIL_PointIsDirectlyReachable(GetPlayerBottomOfCollisionHull(pBot->Edict), MoveStart) && !UTIL_PointIsDirectlyReachable(GetPlayerBottomOfCollisionHull(pBot->Edict), MoveEnd));
|
||||||
|
}
|
||||||
|
|
||||||
|
return vDist2DSq(pBot->Edict->v.origin, ClosestPointOnLine) > sqrf(GetPlayerRadius(pBot->Edict) * 2.0f);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool IsBotOffPhaseGateNode(const AvHAIPlayer* pBot, Vector MoveStart, Vector MoveEnd, Vector NextMoveDestination, SamplePolyFlags NextMoveFlag)
|
||||||
|
{
|
||||||
|
if (vDist2DSq(pBot->Edict->v.origin, MoveStart) > sqrf(UTIL_MetresToGoldSrcUnits(3.0f)) && vDist2DSq(pBot->Edict->v.origin, MoveEnd) > sqrf(UTIL_MetresToGoldSrcUnits(3.0f))) { return true; }
|
||||||
|
|
||||||
|
DeployableSearchFilter PGFilter;
|
||||||
|
PGFilter.DeployableTeam = pBot->Player->GetTeam();
|
||||||
|
PGFilter.IncludeStatusFlags = STRUCTURE_STATUS_COMPLETED;
|
||||||
|
PGFilter.ExcludeStatusFlags = STRUCTURE_STATUS_RECYCLING;
|
||||||
|
PGFilter.MaxSearchRadius = UTIL_MetresToGoldSrcUnits(2.0f);
|
||||||
|
|
||||||
|
bool StartPGExists = AITAC_DeployableExistsAtLocation(MoveStart, &PGFilter);
|
||||||
|
|
||||||
|
if (!StartPGExists) { return true; }
|
||||||
|
|
||||||
|
bool EndPGExists = AITAC_DeployableExistsAtLocation(MoveEnd, &PGFilter);
|
||||||
|
|
||||||
|
if (!EndPGExists) { return true; }
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool IsBotOffLiftNode(const AvHAIPlayer* pBot, Vector MoveStart, Vector MoveEnd, Vector NextMoveDestination, SamplePolyFlags NextMoveFlag)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool IsBotOffObstacleNode(const AvHAIPlayer* pBot, Vector MoveStart, Vector MoveEnd, Vector NextMoveDestination, SamplePolyFlags NextMoveFlag)
|
||||||
|
{
|
||||||
|
return IsBotOffJumpNode(pBot, MoveStart, MoveEnd, NextMoveDestination, NextMoveFlag);
|
||||||
|
}
|
||||||
|
|
||||||
void BlinkClimbMove(AvHAIPlayer* pBot, const Vector StartPoint, const Vector EndPoint, float RequiredClimbHeight)
|
void BlinkClimbMove(AvHAIPlayer* pBot, const Vector StartPoint, const Vector EndPoint, float RequiredClimbHeight)
|
||||||
{
|
{
|
||||||
edict_t* pEdict = pBot->Edict;
|
edict_t* pEdict = pBot->Edict;
|
||||||
|
@ -4025,6 +4104,16 @@ void BlinkClimbMove(AvHAIPlayer* pBot, const Vector StartPoint, const Vector End
|
||||||
// Only blink if we're below the target climb height
|
// Only blink if we're below the target climb height
|
||||||
if (pEdict->v.origin.z < RequiredClimbHeight)
|
if (pEdict->v.origin.z < RequiredClimbHeight)
|
||||||
{
|
{
|
||||||
|
float HeightToClimb = (fabsf(pEdict->v.origin.z - RequiredClimbHeight));
|
||||||
|
|
||||||
|
if (HeightToClimb > (GetPlayerHeight(pBot->Edict, false) * 2.0f))
|
||||||
|
{
|
||||||
|
if (GetPlayerEnergy(pBot->Edict) < 0.15f && pBot->BotNavInfo.IsOnGround)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Vector CurrVelocity = UTIL_GetVectorNormal2D(pBot->Edict->v.velocity);
|
Vector CurrVelocity = UTIL_GetVectorNormal2D(pBot->Edict->v.velocity);
|
||||||
|
|
||||||
float Dot = UTIL_GetDotProduct2D(MoveDir, CurrVelocity);
|
float Dot = UTIL_GetDotProduct2D(MoveDir, CurrVelocity);
|
||||||
|
@ -4043,6 +4132,11 @@ void BlinkClimbMove(AvHAIPlayer* pBot, const Vector StartPoint, const Vector End
|
||||||
|
|
||||||
if (pBot->Edict->v.velocity.z < DesiredZVelocity || pBot->Edict->v.velocity.z < 300.0f)
|
if (pBot->Edict->v.velocity.z < DesiredZVelocity || pBot->Edict->v.velocity.z < 300.0f)
|
||||||
{
|
{
|
||||||
|
// We're going to cheat and give the bot the necessary energy to make the move. Better the fade cheats a bit than gets stuck somewhere
|
||||||
|
if (GetPlayerEnergy(pBot->Edict) < 0.1f)
|
||||||
|
{
|
||||||
|
pBot->Player->Energize(0.1f);
|
||||||
|
}
|
||||||
BotMoveLookAt(pBot, EndPoint + Vector(0.0f, 0.0f, 100.0f));
|
BotMoveLookAt(pBot, EndPoint + Vector(0.0f, 0.0f, 100.0f));
|
||||||
pBot->Button |= IN_ATTACK2;
|
pBot->Button |= IN_ATTACK2;
|
||||||
}
|
}
|
||||||
|
@ -5759,9 +5853,9 @@ void SkipAheadInFlightPath(AvHAIPlayer* pBot)
|
||||||
|
|
||||||
void BotFollowFlightPath(AvHAIPlayer* pBot)
|
void BotFollowFlightPath(AvHAIPlayer* pBot)
|
||||||
{
|
{
|
||||||
if (pBot->BotNavInfo.CurrentPath.size() == 0)
|
if (pBot->BotNavInfo.CurrentPath.size() == 0 || pBot->BotNavInfo.CurrentPathPoint == pBot->BotNavInfo.CurrentPath.end())
|
||||||
{
|
{
|
||||||
ClearBotStuck(pBot);
|
ClearBotPath(pBot);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -5800,7 +5894,9 @@ void BotFollowFlightPath(AvHAIPlayer* pBot)
|
||||||
SkipAheadInFlightPath(pBot);
|
SkipAheadInFlightPath(pBot);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!UTIL_QuickTrace(pBot->Edict, pBot->Edict->v.origin, BotNavInfo->CurrentPathPoint->Location + Vector(0.0f, 0.0f, 5.0f)))
|
ClosestPointToPath = vClosestPointOnLine(BotNavInfo->CurrentPathPoint->FromLocation, BotNavInfo->CurrentPathPoint->Location, pEdict->v.origin);
|
||||||
|
|
||||||
|
if (vDist3DSq(pBot->Edict->v.origin, ClosestPointToPath) > sqrf(GetPlayerRadius(pBot->Edict) * 3.0f))
|
||||||
{
|
{
|
||||||
ClearBotPath(pBot);
|
ClearBotPath(pBot);
|
||||||
return;
|
return;
|
||||||
|
@ -5812,8 +5908,6 @@ void BotFollowFlightPath(AvHAIPlayer* pBot)
|
||||||
unsigned char CurrentMoveArea = BotNavInfo->CurrentPathPoint->area;
|
unsigned char CurrentMoveArea = BotNavInfo->CurrentPathPoint->area;
|
||||||
unsigned char NextMoveArea = (next(BotNavInfo->CurrentPathPoint) != BotNavInfo->CurrentPath.end()) ? next(BotNavInfo->CurrentPathPoint)->area : CurrentMoveArea;
|
unsigned char NextMoveArea = (next(BotNavInfo->CurrentPathPoint) != BotNavInfo->CurrentPath.end()) ? next(BotNavInfo->CurrentPathPoint)->area : CurrentMoveArea;
|
||||||
|
|
||||||
ClosestPointToPath = vClosestPointOnLine(MoveFrom, CurrentMoveDest, pEdict->v.origin);
|
|
||||||
|
|
||||||
Vector MoveDir = UTIL_GetVectorNormal(CurrentMoveDest - MoveFrom);
|
Vector MoveDir = UTIL_GetVectorNormal(CurrentMoveDest - MoveFrom);
|
||||||
|
|
||||||
float CurrentSpeed = vSize3D(pEdict->v.velocity);
|
float CurrentSpeed = vSize3D(pEdict->v.velocity);
|
||||||
|
@ -5837,7 +5931,7 @@ void BotFollowFlightPath(AvHAIPlayer* pBot)
|
||||||
|
|
||||||
if (!bMustHugGround || MoveFrom.z <= CurrentMoveDest.z)
|
if (!bMustHugGround || MoveFrom.z <= CurrentMoveDest.z)
|
||||||
{
|
{
|
||||||
if (CurrentSpeed < sqrf(500.f))
|
if (CurrentSpeed < 500.f && GetPlayerEnergy(pBot->Edict) > 0.1f)
|
||||||
{
|
{
|
||||||
if (!(pEdict->v.oldbuttons & IN_JUMP))
|
if (!(pEdict->v.oldbuttons & IN_JUMP))
|
||||||
{
|
{
|
||||||
|
@ -5907,6 +6001,13 @@ void BotFollowSwimPath(AvHAIPlayer* pBot)
|
||||||
ClearBotPath(pBot);
|
ClearBotPath(pBot);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (pBot->BotNavInfo.CurrentPathPoint->flag == SAMPLE_POLYFLAGS_WALK)
|
||||||
|
{
|
||||||
|
pBot->BotNavInfo.CurrentPathPoint->FromLocation = pBot->CurrentFloorPosition;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool TargetPointIsInWater = (UTIL_PointContents(BotNavInfo->CurrentPathPoint->Location) == CONTENTS_WATER || UTIL_PointContents(BotNavInfo->CurrentPathPoint->Location) == CONTENTS_SLIME);
|
bool TargetPointIsInWater = (UTIL_PointContents(BotNavInfo->CurrentPathPoint->Location) == CONTENTS_WATER || UTIL_PointContents(BotNavInfo->CurrentPathPoint->Location) == CONTENTS_SLIME);
|
||||||
|
@ -5997,6 +6098,17 @@ void BotFollowPath(AvHAIPlayer* pBot)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (IsPlayerStandingOnPlayer(pBot->Edict) && pBot->BotNavInfo.CurrentPathPoint->flag != SAMPLE_POLYFLAGS_WALLCLIMB && pBot->BotNavInfo.CurrentPathPoint->flag != SAMPLE_POLYFLAGS_LADDER)
|
||||||
|
{
|
||||||
|
if (pBot->Edict->v.groundentity->v.velocity.Length2D() > 10.0f)
|
||||||
|
{
|
||||||
|
pBot->desiredMovementDir = UTIL_GetVectorNormal2D(-pBot->Edict->v.groundentity->v.velocity);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
MoveToWithoutNav(pBot, pBot->BotNavInfo.CurrentPathPoint->Location);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (IsBotOffPath(pBot))
|
if (IsBotOffPath(pBot))
|
||||||
{
|
{
|
||||||
pBot->BotNavInfo.StuckInfo.bPathFollowFailed = true;
|
pBot->BotNavInfo.StuckInfo.bPathFollowFailed = true;
|
||||||
|
@ -6440,9 +6552,6 @@ void HandlePlayerAvoidance(AvHAIPlayer* pBot, const Vector MoveDestination)
|
||||||
|
|
||||||
float TraceLength = OtherPersonDistFromLine + (fmaxf(MyRadius, OtherPlayerRadius) * 2.0f);
|
float TraceLength = OtherPersonDistFromLine + (fmaxf(MyRadius, OtherPlayerRadius) * 2.0f);
|
||||||
|
|
||||||
UTIL_DrawLine(INDEXENT(1), pBot->Edict->v.origin, pBot->Edict->v.origin + (PreferredMoveDir * TraceLength), 0, 128, 0);
|
|
||||||
UTIL_DrawLine(INDEXENT(1), pBot->Edict->v.origin, pBot->Edict->v.origin - (PreferredMoveDir * TraceLength), 255, 0, 0);
|
|
||||||
|
|
||||||
|
|
||||||
// First see if we have enough room to move in our preferred avoidance direction
|
// First see if we have enough room to move in our preferred avoidance direction
|
||||||
if (UTIL_TraceNav(pBot->BotNavInfo.NavProfile, BotLocation, BotLocation + (PreferredMoveDir * TraceLength), 0.0f))
|
if (UTIL_TraceNav(pBot->BotNavInfo.NavProfile, BotLocation, BotLocation + (PreferredMoveDir * TraceLength), 0.0f))
|
||||||
|
@ -6458,17 +6567,14 @@ void HandlePlayerAvoidance(AvHAIPlayer* pBot, const Vector MoveDestination)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool bCanBackUp = UTIL_TraceNav(pBot->BotNavInfo.NavProfile, BotLocation, BotLocation - (MoveDir * (MyRadius * 2.0f)), 0.0f);
|
// If we have a point we can go back to, and we can reach it, then go for it. Otherwise, keep pushing on and hope the other guy moves
|
||||||
|
if (!vIsZero(pBot->BotNavInfo.LastOpenLocation))
|
||||||
if (!bCanBackUp)
|
|
||||||
{
|
{
|
||||||
bCanBackUp = UTIL_QuickHullTrace(pBot->Edict, pBot->Edict->v.origin, pBot->Edict->v.origin - (MoveDir * (MyRadius * 2.0f)), head_hull);
|
if (UTIL_PointIsReachable(pBot->BotNavInfo.NavProfile, pBot->Edict->v.origin, pBot->BotNavInfo.LastOpenLocation, GetPlayerRadius(pBot->Edict)))
|
||||||
}
|
{
|
||||||
|
NAV_SetMoveMovementTask(pBot, pBot->BotNavInfo.LastOpenLocation, nullptr);
|
||||||
// Back up since we can't go either side, but only if we can back up. Otherwise, we push forward and demand the OTHER guy back up
|
return;
|
||||||
if (UTIL_GetDotProduct2D(MoveDir, OtherMoveDir) < 0.0f && bCanBackUp)
|
}
|
||||||
{
|
|
||||||
pBot->desiredMovementDir = MoveDir * -1.0f;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -6574,7 +6680,6 @@ float UTIL_FindZHeightForWallClimb(const Vector ClimbStart, const Vector ClimbEn
|
||||||
|
|
||||||
Vector CurrTraceStart = StartTrace;
|
Vector CurrTraceStart = StartTrace;
|
||||||
|
|
||||||
|
|
||||||
UTIL_TraceHull(StartTrace, EndTrace, ignore_monsters, HullNum, nullptr, &hit);
|
UTIL_TraceHull(StartTrace, EndTrace, ignore_monsters, HullNum, nullptr, &hit);
|
||||||
|
|
||||||
if (hit.flFraction >= 1.0f && !hit.fAllSolid && !hit.fStartSolid)
|
if (hit.flFraction >= 1.0f && !hit.fAllSolid && !hit.fStartSolid)
|
||||||
|
@ -6701,7 +6806,7 @@ void BotMovementInputs(AvHAIPlayer* pBot)
|
||||||
pBot->Button |= IN_MOVELEFT;
|
pBot->Button |= IN_MOVELEFT;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (pBot->BotNavInfo.CurrentPath.size() == 0 || pBot->BotNavInfo.CurrentPathPoint->flag != SAMPLE_POLYFLAGS_LADDER)
|
if (pBot->BotNavInfo.CurrentPath.size() == 0 || pBot->BotNavInfo.CurrentPathPoint == pBot->BotNavInfo.CurrentPath.end() || pBot->BotNavInfo.CurrentPathPoint->flag != SAMPLE_POLYFLAGS_LADDER)
|
||||||
{
|
{
|
||||||
if (pBot->Player->IsOnLadder())
|
if (pBot->Player->IsOnLadder())
|
||||||
{
|
{
|
||||||
|
|
|
@ -209,8 +209,25 @@ bool BotIsAtLocation(const AvHAIPlayer* pBot, const Vector Destination);
|
||||||
void NewMove(AvHAIPlayer* pBot);
|
void NewMove(AvHAIPlayer* pBot);
|
||||||
// Returns true if the bot has completed the current movement along their path
|
// Returns true if the bot has completed the current movement along their path
|
||||||
bool HasBotReachedPathPoint(const AvHAIPlayer* pBot);
|
bool HasBotReachedPathPoint(const AvHAIPlayer* pBot);
|
||||||
|
bool HasBotCompletedLadderMove(const AvHAIPlayer* pBot, Vector MoveStart, Vector MoveEnd, Vector NextMoveDestination, SamplePolyFlags NextMoveFlag);
|
||||||
|
bool HasBotCompletedWalkMove(const AvHAIPlayer* pBot, Vector MoveStart, Vector MoveEnd, Vector NextMoveDestination, SamplePolyFlags NextMoveFlag);
|
||||||
|
bool HasBotCompletedFallMove(const AvHAIPlayer* pBot, Vector MoveStart, Vector MoveEnd, Vector NextMoveDestination, SamplePolyFlags NextMoveFlag);
|
||||||
|
bool HasBotCompletedClimbMove(const AvHAIPlayer* pBot, Vector MoveStart, Vector MoveEnd, float RequiredClimbHeight, Vector NextMoveDestination, SamplePolyFlags NextMoveFlag);
|
||||||
|
bool HasBotCompletedJumpMove(const AvHAIPlayer* pBot, Vector MoveStart, Vector MoveEnd, Vector NextMoveDestination, SamplePolyFlags NextMoveFlag);
|
||||||
|
bool HasBotCompletedPhaseGateMove(const AvHAIPlayer* pBot, Vector MoveStart, Vector MoveEnd, Vector NextMoveDestination, SamplePolyFlags NextMoveFlag);
|
||||||
|
bool HasBotCompletedLiftMove(const AvHAIPlayer* pBot, Vector MoveStart, Vector MoveEnd, Vector NextMoveDestination, SamplePolyFlags NextMoveFlag);
|
||||||
|
bool HasBotCompletedObstacleMove(const AvHAIPlayer* pBot, Vector MoveStart, Vector MoveEnd, Vector NextMoveDestination, SamplePolyFlags NextMoveFlag);
|
||||||
|
|
||||||
// Returns true if the bot is considered to have strayed off the path (e.g. missed a jump and fallen)
|
// Returns true if the bot is considered to have strayed off the path (e.g. missed a jump and fallen)
|
||||||
bool IsBotOffPath(const AvHAIPlayer* pBot);
|
bool IsBotOffPath(const AvHAIPlayer* pBot);
|
||||||
|
bool IsBotOffLadderNode(const AvHAIPlayer* pBot, Vector MoveStart, Vector MoveEnd, Vector NextMoveDestination, SamplePolyFlags NextMoveFlag);
|
||||||
|
bool IsBotOffWalkNode(const AvHAIPlayer* pBot, Vector MoveStart, Vector MoveEnd, Vector NextMoveDestination, SamplePolyFlags NextMoveFlag);
|
||||||
|
bool IsBotOffFallNode(const AvHAIPlayer* pBot, Vector MoveStart, Vector MoveEnd, Vector NextMoveDestination, SamplePolyFlags NextMoveFlag);
|
||||||
|
bool IsBotOffClimbNode(const AvHAIPlayer* pBot, Vector MoveStart, Vector MoveEnd, Vector NextMoveDestination, SamplePolyFlags NextMoveFlag);
|
||||||
|
bool IsBotOffJumpNode(const AvHAIPlayer* pBot, Vector MoveStart, Vector MoveEnd, Vector NextMoveDestination, SamplePolyFlags NextMoveFlag);
|
||||||
|
bool IsBotOffPhaseGateNode(const AvHAIPlayer* pBot, Vector MoveStart, Vector MoveEnd, Vector NextMoveDestination, SamplePolyFlags NextMoveFlag);
|
||||||
|
bool IsBotOffLiftNode(const AvHAIPlayer* pBot, Vector MoveStart, Vector MoveEnd, Vector NextMoveDestination, SamplePolyFlags NextMoveFlag);
|
||||||
|
bool IsBotOffObstacleNode(const AvHAIPlayer* pBot, Vector MoveStart, Vector MoveEnd, Vector NextMoveDestination, SamplePolyFlags NextMoveFlag);
|
||||||
|
|
||||||
// Called by NewMove, determines the movement direction and inputs required to walk/crouch between start and end points
|
// Called by NewMove, determines the movement direction and inputs required to walk/crouch between start and end points
|
||||||
void GroundMove(AvHAIPlayer* pBot, const Vector StartPoint, const Vector EndPoint);
|
void GroundMove(AvHAIPlayer* pBot, const Vector StartPoint, const Vector EndPoint);
|
||||||
|
@ -263,7 +280,7 @@ void ClearBotMovement(AvHAIPlayer* pBot);
|
||||||
bool IsBotStuck(AvHAIPlayer* pBot, const Vector MoveDestination);
|
bool IsBotStuck(AvHAIPlayer* pBot, const Vector MoveDestination);
|
||||||
|
|
||||||
// Called every bot frame (default is 60fps). Ensures the tile cache is updated after obstacles are placed
|
// Called every bot frame (default is 60fps). Ensures the tile cache is updated after obstacles are placed
|
||||||
void UTIL_UpdateTileCache();
|
bool UTIL_UpdateTileCache();
|
||||||
|
|
||||||
void AIDEBUG_DrawOffMeshConnections(float DrawTime);
|
void AIDEBUG_DrawOffMeshConnections(float DrawTime);
|
||||||
|
|
||||||
|
|
|
@ -1628,6 +1628,49 @@ void StartNewBotFrame(AvHAIPlayer* pBot)
|
||||||
if (UTIL_PointIsReachable(pBot->BotNavInfo.NavProfile, AITAC_GetTeamStartingLocation(pBot->Player->GetTeam()), pBot->CurrentFloorPosition, 16.0f))
|
if (UTIL_PointIsReachable(pBot->BotNavInfo.NavProfile, AITAC_GetTeamStartingLocation(pBot->Player->GetTeam()), pBot->CurrentFloorPosition, 16.0f))
|
||||||
{
|
{
|
||||||
pBot->BotNavInfo.LastNavMeshPosition = pBot->CurrentFloorPosition;
|
pBot->BotNavInfo.LastNavMeshPosition = pBot->CurrentFloorPosition;
|
||||||
|
|
||||||
|
if (pBot->BotNavInfo.IsOnGround)
|
||||||
|
{
|
||||||
|
Vector ForwardVector = UTIL_GetForwardVector2D(pBot->Edict->v.angles);
|
||||||
|
Vector RightVector = UTIL_GetCrossProduct(ForwardVector, UP_VECTOR);
|
||||||
|
|
||||||
|
Vector TraceEndPoints[4];
|
||||||
|
|
||||||
|
TraceEndPoints[0] = pBot->Edict->v.origin + (ForwardVector * (GetPlayerRadius(pBot->Edict) * 2.0f));
|
||||||
|
TraceEndPoints[1] = pBot->Edict->v.origin - (ForwardVector * (GetPlayerRadius(pBot->Edict) * 2.0f));
|
||||||
|
TraceEndPoints[2] = pBot->Edict->v.origin + (RightVector * (GetPlayerRadius(pBot->Edict) * 2.0f));
|
||||||
|
TraceEndPoints[3] = pBot->Edict->v.origin - (RightVector * (GetPlayerRadius(pBot->Edict) * 2.0f));
|
||||||
|
|
||||||
|
int NumDirectionsChecked = 0;
|
||||||
|
bool bHasRoom = true;
|
||||||
|
|
||||||
|
while (NumDirectionsChecked < 4 && bHasRoom)
|
||||||
|
{
|
||||||
|
Vector EndTrace = TraceEndPoints[NumDirectionsChecked];
|
||||||
|
Vector EndNavTrace = EndTrace;
|
||||||
|
EndNavTrace.z = pBot->CollisionHullBottomLocation.z;
|
||||||
|
|
||||||
|
if (!UTIL_QuickTrace(pBot->Edict, pBot->Edict->v.origin, EndTrace))
|
||||||
|
{
|
||||||
|
bHasRoom = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!UTIL_TraceNav(pBot->BotNavInfo.NavProfile, pBot->CollisionHullBottomLocation, EndNavTrace, 0.0f))
|
||||||
|
{
|
||||||
|
bHasRoom = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
NumDirectionsChecked++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (bHasRoom)
|
||||||
|
{
|
||||||
|
pBot->BotNavInfo.LastOpenLocation = pBot->CurrentFloorPosition;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pBot->BotNavInfo.LastNavMeshCheckPosition = pBot->CurrentFloorPosition;
|
pBot->BotNavInfo.LastNavMeshCheckPosition = pBot->CurrentFloorPosition;
|
||||||
|
@ -4952,7 +4995,7 @@ void TestNavThink(AvHAIPlayer* pBot)
|
||||||
|
|
||||||
if (!RandomNode) { return; }
|
if (!RandomNode) { return; }
|
||||||
|
|
||||||
Vector RandomPoint = RandomNode->Location;
|
RandomPoint = RandomNode->Location;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -4965,6 +5008,10 @@ void TestNavThink(AvHAIPlayer* pBot)
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
if (!vIsZero(pBot->BotNavInfo.LastNavMeshPosition))
|
||||||
|
{
|
||||||
|
MoveToWithoutNav(pBot, pBot->BotNavInfo.LastNavMeshPosition);
|
||||||
|
}
|
||||||
AITASK_ClearBotTask(pBot, &pBot->PrimaryBotTask);
|
AITASK_ClearBotTask(pBot, &pBot->PrimaryBotTask);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,6 +7,7 @@
|
||||||
#include "AvHAIWeaponHelper.h"
|
#include "AvHAIWeaponHelper.h"
|
||||||
#include "AvHAIHelper.h"
|
#include "AvHAIHelper.h"
|
||||||
#include "AvHAICommander.h"
|
#include "AvHAICommander.h"
|
||||||
|
#include "AvHAIPlayerUtil.h"
|
||||||
#include "../AvHGamerules.h"
|
#include "../AvHGamerules.h"
|
||||||
#include "../dlls/client.h"
|
#include "../dlls/client.h"
|
||||||
#include <time.h>
|
#include <time.h>
|
||||||
|
@ -21,6 +22,7 @@ extern cvar_t avh_botsenabled;
|
||||||
extern cvar_t avh_botminplayers;
|
extern cvar_t avh_botminplayers;
|
||||||
extern cvar_t avh_botusemapdefaults;
|
extern cvar_t avh_botusemapdefaults;
|
||||||
extern cvar_t avh_botcommandermode;
|
extern cvar_t avh_botcommandermode;
|
||||||
|
extern cvar_t avh_botdebugmode;
|
||||||
|
|
||||||
float LastAIPlayerCountUpdate = 0.0f;
|
float LastAIPlayerCountUpdate = 0.0f;
|
||||||
|
|
||||||
|
@ -31,9 +33,6 @@ float AIStartedTime = 0.0f; // Used to give 5-second grace period before adding
|
||||||
bool bHasRoundStarted = false;
|
bool bHasRoundStarted = false;
|
||||||
bool bMapDataInitialised = false;
|
bool bMapDataInitialised = false;
|
||||||
|
|
||||||
bool bTestNavigation = false;
|
|
||||||
bool bDroneMode = false;
|
|
||||||
|
|
||||||
float NextCommanderAllowedTimeTeamA = 0.0f;
|
float NextCommanderAllowedTimeTeamA = 0.0f;
|
||||||
float NextCommanderAllowedTimeTeamB = 0.0f;
|
float NextCommanderAllowedTimeTeamB = 0.0f;
|
||||||
|
|
||||||
|
@ -46,6 +45,10 @@ AvHAIPlayer* DebugAIPlayer = nullptr;
|
||||||
|
|
||||||
vector<bot_path_node> DebugPath;
|
vector<bot_path_node> DebugPath;
|
||||||
|
|
||||||
|
bool bPlayerSpawned = false;
|
||||||
|
|
||||||
|
float CountdownStartedTime = 0.0f;
|
||||||
|
|
||||||
string BotNames[MAX_PLAYERS] = { "MrRobot",
|
string BotNames[MAX_PLAYERS] = { "MrRobot",
|
||||||
"Wall-E",
|
"Wall-E",
|
||||||
"BeepBoop",
|
"BeepBoop",
|
||||||
|
@ -119,7 +122,7 @@ void AIMGR_UpdateAIPlayerCounts()
|
||||||
// Don't add or remove bots too quickly, otherwise it can cause lag or even overflows
|
// Don't add or remove bots too quickly, otherwise it can cause lag or even overflows
|
||||||
if (gpGlobals->time - LastAIPlayerCountUpdate < 0.2f) { return; }
|
if (gpGlobals->time - LastAIPlayerCountUpdate < 0.2f) { return; }
|
||||||
|
|
||||||
if (gpGlobals->time - AIStartedTime < AI_GRACE_PERIOD) { return; }
|
if (!AIMGR_ShouldStartPlayerBalancing()) { return; }
|
||||||
|
|
||||||
// If game has ended, kick bots that have dropped back to the ready room
|
// If game has ended, kick bots that have dropped back to the ready room
|
||||||
if (GetGameRules()->GetVictoryTeam() != TEAM_IND)
|
if (GetGameRules()->GetVictoryTeam() != TEAM_IND)
|
||||||
|
@ -634,10 +637,42 @@ void AIMGR_UpdateAIPlayers()
|
||||||
|
|
||||||
if (bot->BotNavInfo.CurrentPath.size() > 0 && bot->BotNavInfo.CurrentPathPoint != bot->BotNavInfo.CurrentPath.end())
|
if (bot->BotNavInfo.CurrentPath.size() > 0 && bot->BotNavInfo.CurrentPathPoint != bot->BotNavInfo.CurrentPath.end())
|
||||||
{
|
{
|
||||||
UTIL_DrawLine(INDEXENT(1), bot->Edict->v.origin, bot->BotNavInfo.CurrentPathPoint->Location, 0, 255, 255);
|
UTIL_DrawLine(INDEXENT(1), bot->Edict->v.origin, bot->BotNavInfo.CurrentPathPoint->FromLocation, 255, 0, 0);
|
||||||
|
UTIL_DrawLine(INDEXENT(1), bot->Edict->v.origin, bot->BotNavInfo.CurrentPathPoint->Location, 0, 128, 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!vIsZero(DebugVector1) && !vIsZero(DebugVector2))
|
||||||
|
{
|
||||||
|
UTIL_DrawLine(INDEXENT(1), DebugVector1, DebugVector2);
|
||||||
|
|
||||||
|
edict_t* PlayerEdict = INDEXENT(1);
|
||||||
|
|
||||||
|
bool bOnGround = (INDEXENT(1)->v.flags & FL_ONGROUND) || IsPlayerOnLadder(PlayerEdict);
|
||||||
|
bool Result = false;
|
||||||
|
|
||||||
|
if (!IsPlayerOnLadder(PlayerEdict))
|
||||||
|
{
|
||||||
|
|
||||||
|
if (IsPlayerClimbingWall(PlayerEdict)) { Result = true; }
|
||||||
|
|
||||||
|
if (bOnGround)
|
||||||
|
{
|
||||||
|
if (!UTIL_PointIsDirectlyReachable(GetPlayerBottomOfCollisionHull(PlayerEdict), DebugVector1) && !UTIL_PointIsDirectlyReachable(GetPlayerBottomOfCollisionHull(PlayerEdict), DebugVector2)) { Result = true; }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Result)
|
||||||
|
{
|
||||||
|
UTIL_DrawHUDText(PlayerEdict, 0, 0.1f, 0.1f, 255, 255, 255, "TRUE");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
UTIL_DrawHUDText(PlayerEdict, 0, 0.1f, 0.1f, 255, 255, 255, "FALSE");
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
if (bHasRoundStarted)
|
if (bHasRoundStarted)
|
||||||
{
|
{
|
||||||
AvHTeamNumber TeamANumber = GetGameRules()->GetTeamANumber();
|
AvHTeamNumber TeamANumber = GetGameRules()->GetTeamANumber();
|
||||||
|
@ -674,11 +709,11 @@ void AIMGR_UpdateAIPlayers()
|
||||||
|
|
||||||
UpdateBotChat(bot);
|
UpdateBotChat(bot);
|
||||||
|
|
||||||
if (bDroneMode)
|
if (avh_botdebugmode.value == 1)
|
||||||
{
|
{
|
||||||
DroneThink(bot);
|
DroneThink(bot);
|
||||||
}
|
}
|
||||||
else if (bTestNavigation)
|
else if (avh_botdebugmode.value == 2)
|
||||||
{
|
{
|
||||||
TestNavThink(bot);
|
TestNavThink(bot);
|
||||||
}
|
}
|
||||||
|
@ -902,12 +937,19 @@ void AIMGR_ResetRound()
|
||||||
|
|
||||||
UTIL_UpdateDoors(true);
|
UTIL_UpdateDoors(true);
|
||||||
|
|
||||||
UTIL_UpdateTileCache();
|
bool bTileCacheFullyUpdated = UTIL_UpdateTileCache();
|
||||||
|
|
||||||
|
while (!bTileCacheFullyUpdated)
|
||||||
|
{
|
||||||
|
bTileCacheFullyUpdated = UTIL_UpdateTileCache();
|
||||||
|
}
|
||||||
|
|
||||||
ALERT(at_console, "AI Manager Reset Round\n");
|
ALERT(at_console, "AI Manager Reset Round\n");
|
||||||
|
|
||||||
bHasRoundStarted = false;
|
bHasRoundStarted = false;
|
||||||
bMapDataInitialised = true;
|
bMapDataInitialised = true;
|
||||||
|
|
||||||
|
CountdownStartedTime = 0.0f;
|
||||||
}
|
}
|
||||||
|
|
||||||
void AIMGR_RoundStarted()
|
void AIMGR_RoundStarted()
|
||||||
|
@ -936,6 +978,8 @@ void AIMGR_RoundStarted()
|
||||||
{
|
{
|
||||||
AIMGR_SetCommanderAllowedTime(TeamBNumber, 0.0f);
|
AIMGR_SetCommanderAllowedTime(TeamBNumber, 0.0f);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
AITAC_OnNavMeshModified();
|
||||||
}
|
}
|
||||||
|
|
||||||
void AIMGR_SetCommanderAllowedTime(AvHTeamNumber Team, float NewValue)
|
void AIMGR_SetCommanderAllowedTime(AvHTeamNumber Team, float NewValue)
|
||||||
|
@ -1009,6 +1053,8 @@ void AIMGR_NewMap()
|
||||||
AIMGR_BotPrecache();
|
AIMGR_BotPrecache();
|
||||||
|
|
||||||
bHasRoundStarted = false;
|
bHasRoundStarted = false;
|
||||||
|
|
||||||
|
bPlayerSpawned = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
AvHAIPlayer* AIMGR_GetAICommander(AvHTeamNumber Team)
|
AvHAIPlayer* AIMGR_GetAICommander(AvHTeamNumber Team)
|
||||||
|
@ -1118,9 +1164,19 @@ vector<AvHPlayer*> AIMGR_GetNonAIPlayersOnTeam(AvHTeamNumber Team)
|
||||||
return TeamPlayers;
|
return TeamPlayers;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool AIMGR_ShouldStartPlayerBalancing()
|
||||||
|
{
|
||||||
|
return (bPlayerSpawned && gpGlobals->time - AIStartedTime > AI_GRACE_PERIOD) || (gpGlobals->time - AIStartedTime > AI_MAX_START_TIMEOUT);
|
||||||
|
}
|
||||||
|
|
||||||
void AIMGR_UpdateAIMapData()
|
void AIMGR_UpdateAIMapData()
|
||||||
{
|
{
|
||||||
if (bMapDataInitialised && gpGlobals->time - AIStartedTime > AI_GRACE_PERIOD)
|
if (GetGameRules()->GetCountdownStarted() && CountdownStartedTime == 0.0f)
|
||||||
|
{
|
||||||
|
CountdownStartedTime = gpGlobals->time;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (bMapDataInitialised && (CountdownStartedTime > 0.0f && (gpGlobals->time - 1.0f) > CountdownStartedTime))
|
||||||
{
|
{
|
||||||
AITAC_UpdateMapAIData();
|
AITAC_UpdateMapAIData();
|
||||||
UTIL_UpdateTileCache();
|
UTIL_UpdateTileCache();
|
||||||
|
@ -1158,34 +1214,6 @@ void AIMGR_SetDebugAIPlayer(edict_t* AIPlayer)
|
||||||
DebugAIPlayer = nullptr;
|
DebugAIPlayer = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
void AIMGR_SetTestNavMode(bool bNewValue)
|
|
||||||
{
|
|
||||||
if (bNewValue)
|
|
||||||
{
|
|
||||||
bDroneMode = false;
|
|
||||||
}
|
|
||||||
bTestNavigation = bNewValue;
|
|
||||||
}
|
|
||||||
|
|
||||||
void AIMGR_SetDroneMode(bool bNewValue)
|
|
||||||
{
|
|
||||||
if (bNewValue)
|
|
||||||
{
|
|
||||||
bTestNavigation = false;
|
|
||||||
}
|
|
||||||
bDroneMode = bNewValue;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool AIMGR_GetTestNavMode()
|
|
||||||
{
|
|
||||||
return bTestNavigation;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool AIMGR_GetDroneMode()
|
|
||||||
{
|
|
||||||
return bTestNavigation;
|
|
||||||
}
|
|
||||||
|
|
||||||
void AIMGR_ReceiveCommanderRequest(AvHTeamNumber Team, edict_t* Requestor, const char* Request)
|
void AIMGR_ReceiveCommanderRequest(AvHTeamNumber Team, edict_t* Requestor, const char* Request)
|
||||||
{
|
{
|
||||||
AvHTeam* TeamRef = GetGameRules()->GetTeam(Team);
|
AvHTeam* TeamRef = GetGameRules()->GetTeam(Team);
|
||||||
|
@ -1202,3 +1230,13 @@ void AIMGR_ReceiveCommanderRequest(AvHTeamNumber Team, edict_t* Requestor, const
|
||||||
AICOMM_ReceiveChatRequest(BotCommander, Requestor, Request);
|
AICOMM_ReceiveChatRequest(BotCommander, Requestor, Request);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void AIMGR_ClientConnected(edict_t* NewClient)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void AIMGR_PlayerSpawned()
|
||||||
|
{
|
||||||
|
bPlayerSpawned = true;
|
||||||
|
}
|
|
@ -6,8 +6,10 @@
|
||||||
|
|
||||||
// Max rate bot can run its logic, default is 1/60th second. WARNING: Increasing the rate past 100hz causes bots to move and turn slowly due to GoldSrc limits!
|
// Max rate bot can run its logic, default is 1/60th second. WARNING: Increasing the rate past 100hz causes bots to move and turn slowly due to GoldSrc limits!
|
||||||
static const double BOT_MIN_FRAME_TIME = (1.0 / 60.0);
|
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
|
// Once the first human player has joined the game, how long to wait before adding bots
|
||||||
static const float AI_GRACE_PERIOD = 5.0f;
|
static const float AI_GRACE_PERIOD = 5.0f;
|
||||||
|
// Max time to wait before spawning players if none connect (e.g. empty dedicated server)
|
||||||
|
static const float AI_MAX_START_TIMEOUT = 20.0f;
|
||||||
|
|
||||||
void AIMGR_BotPrecache();
|
void AIMGR_BotPrecache();
|
||||||
|
|
||||||
|
@ -46,6 +48,7 @@ int AIMGR_GetNumAIPlayers();
|
||||||
int AIMGR_AIPlayerExistsOnTeam(AvHTeamNumber Team);
|
int AIMGR_AIPlayerExistsOnTeam(AvHTeamNumber Team);
|
||||||
|
|
||||||
void AIMGR_UpdateAIMapData();
|
void AIMGR_UpdateAIMapData();
|
||||||
|
bool AIMGR_ShouldStartPlayerBalancing();
|
||||||
|
|
||||||
AvHAICommanderMode AIMGR_GetCommanderMode();
|
AvHAICommanderMode AIMGR_GetCommanderMode();
|
||||||
|
|
||||||
|
@ -90,12 +93,9 @@ void AIMGR_ClearBotData();
|
||||||
AvHAIPlayer* AIMGR_GetDebugAIPlayer();
|
AvHAIPlayer* AIMGR_GetDebugAIPlayer();
|
||||||
void AIMGR_SetDebugAIPlayer(edict_t* AIPlayer);
|
void AIMGR_SetDebugAIPlayer(edict_t* AIPlayer);
|
||||||
|
|
||||||
void AIMGR_SetTestNavMode(bool bNewValue);
|
|
||||||
bool AIMGR_GetTestNavMode();
|
|
||||||
|
|
||||||
void AIMGR_SetDroneMode(bool bNewValue);
|
|
||||||
bool AIMGR_GetDroneMode();
|
|
||||||
|
|
||||||
void AIMGR_ReceiveCommanderRequest(AvHTeamNumber Team, edict_t* Requestor, const char* Request);
|
void AIMGR_ReceiveCommanderRequest(AvHTeamNumber Team, edict_t* Requestor, const char* Request);
|
||||||
|
|
||||||
|
void AIMGR_ClientConnected(edict_t* NewClient);
|
||||||
|
void AIMGR_PlayerSpawned();
|
||||||
|
|
||||||
#endif
|
#endif
|
|
@ -145,17 +145,10 @@ bool IsPlayerOnLadder(const edict_t* Player)
|
||||||
|
|
||||||
if (FNullEnt(NearestLadder)) { return false; }
|
if (FNullEnt(NearestLadder)) { return false; }
|
||||||
|
|
||||||
if (vPointOverlaps3D(Player->v.origin, NearestLadder->v.absmin, NearestLadder->v.absmax)) { return true; }
|
Vector NearestPointOnLadder = UTIL_GetClosestPointOnEntityToLocation(Player->v.origin, NearestLadder);
|
||||||
|
Vector NearestPointOnPlayer = UTIL_GetClosestPointOnEntityToLocation(NearestPointOnLadder, Player);
|
||||||
|
|
||||||
trace_t TraceResult;
|
return (vDist2DSq(NearestPointOnLadder, NearestPointOnPlayer) <= sqrf(4.0f));
|
||||||
|
|
||||||
Vector TraceStart = Player->v.origin;
|
|
||||||
Vector TraceEnd = UTIL_GetCentreOfEntity(NearestLadder);
|
|
||||||
TraceEnd.z = TraceStart.z;
|
|
||||||
|
|
||||||
NS_TraceLine(TraceStart, TraceEnd, 1, PM_WORLD_ONLY, -1, true, TraceResult);
|
|
||||||
|
|
||||||
return (TraceResult.fraction < 0.01f);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return (Player->v.movetype == MOVETYPE_FLY);
|
return (Player->v.movetype == MOVETYPE_FLY);
|
||||||
|
@ -784,6 +777,11 @@ bool IsPlayerReloading(const AvHPlayer* Player)
|
||||||
return (theBasePlayerWeapon->m_fInReload > 0 || theBasePlayerWeapon->m_fInSpecialReload > 0);
|
return (theBasePlayerWeapon->m_fInReload > 0 || theBasePlayerWeapon->m_fInSpecialReload > 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool IsPlayerStandingOnPlayer(const edict_t* Player)
|
||||||
|
{
|
||||||
|
return (IsEdictPlayer(Player->v.groundentity));
|
||||||
|
}
|
||||||
|
|
||||||
AvHUser3 GetPlayerActiveClass(const AvHPlayer* Player)
|
AvHUser3 GetPlayerActiveClass(const AvHPlayer* Player)
|
||||||
{
|
{
|
||||||
if (Player->pev->iuser3 == AVH_USER3_ALIEN_EMBRYO) // If player is gestating...
|
if (Player->pev->iuser3 == AVH_USER3_ALIEN_EMBRYO) // If player is gestating...
|
||||||
|
|
|
@ -150,6 +150,8 @@ float GetPlayerCloakAmount(const edict_t* Player);
|
||||||
|
|
||||||
bool IsPlayerReloading(const AvHPlayer* Player);
|
bool IsPlayerReloading(const AvHPlayer* Player);
|
||||||
|
|
||||||
|
bool IsPlayerStandingOnPlayer(const edict_t* Player);
|
||||||
|
|
||||||
// If the player is gestating, will return the target evolution. Otherwise, returns the iuser3
|
// If the player is gestating, will return the target evolution. Otherwise, returns the iuser3
|
||||||
AvHUser3 GetPlayerActiveClass(const AvHPlayer* Player);
|
AvHUser3 GetPlayerActiveClass(const AvHPlayer* Player);
|
||||||
|
|
||||||
|
|
|
@ -47,7 +47,7 @@ float last_structure_refresh_time = 0.0f;
|
||||||
float last_item_refresh_time = 0.0f;
|
float last_item_refresh_time = 0.0f;
|
||||||
|
|
||||||
// Increments by 1 every time the structure list is refreshed. Used to detect if structures have been destroyed and no longer show up
|
// Increments by 1 every time the structure list is refreshed. Used to detect if structures have been destroyed and no longer show up
|
||||||
unsigned int StructureRefreshFrame = 0;
|
unsigned int StructureRefreshFrame = 1;
|
||||||
// Increments by 1 every time the item list is refreshed. Used to detect if items have been removed from play and no longer show up
|
// Increments by 1 every time the item list is refreshed. Used to detect if items have been removed from play and no longer show up
|
||||||
unsigned int ItemRefreshFrame = 0;
|
unsigned int ItemRefreshFrame = 0;
|
||||||
|
|
||||||
|
@ -850,6 +850,7 @@ Vector AITAC_GetTeamStartingLocation(AvHTeamNumber Team)
|
||||||
{
|
{
|
||||||
Vector CommChairLocation = AITAC_GetCommChairLocation(TeamANum);
|
Vector CommChairLocation = AITAC_GetCommChairLocation(TeamANum);
|
||||||
TeamAStartingLocation = (!vIsZero(CommChairLocation)) ? CommChairLocation : TeamStartLocation;
|
TeamAStartingLocation = (!vIsZero(CommChairLocation)) ? CommChairLocation : TeamStartLocation;
|
||||||
|
TeamAStartingLocation = UTIL_ProjectPointToNavmesh(TeamAStartingLocation, GetBaseNavProfile(STRUCTURE_BASE_NAV_PROFILE));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -885,12 +886,13 @@ Vector AITAC_GetTeamStartingLocation(AvHTeamNumber Team)
|
||||||
|
|
||||||
if (InfantryPortal)
|
if (InfantryPortal)
|
||||||
{
|
{
|
||||||
TeamAStartingLocation = InfantryPortal->Location;
|
TeamBStartingLocation = InfantryPortal->Location;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
Vector CommChairLocation = AITAC_GetCommChairLocation(TeamBNum);
|
Vector CommChairLocation = AITAC_GetCommChairLocation(TeamBNum);
|
||||||
TeamAStartingLocation = (!vIsZero(CommChairLocation)) ? CommChairLocation : TeamStartLocation;
|
TeamBStartingLocation = (!vIsZero(CommChairLocation)) ? CommChairLocation : TeamStartLocation;
|
||||||
|
TeamBStartingLocation = UTIL_ProjectPointToNavmesh(TeamBStartingLocation, GetBaseNavProfile(STRUCTURE_BASE_NAV_PROFILE));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -1507,6 +1509,9 @@ void AITAC_CheckNavMeshModified()
|
||||||
|
|
||||||
void AITAC_OnNavMeshModified()
|
void AITAC_OnNavMeshModified()
|
||||||
{
|
{
|
||||||
|
TeamAStartingLocation = ZERO_VECTOR;
|
||||||
|
TeamBStartingLocation = ZERO_VECTOR;
|
||||||
|
|
||||||
for (auto it = TeamAStructureMap.begin(); it != TeamAStructureMap.end(); it++)
|
for (auto it = TeamAStructureMap.begin(); it != TeamAStructureMap.end(); it++)
|
||||||
{
|
{
|
||||||
it->second.bReachabilityMarkedDirty = true;
|
it->second.bReachabilityMarkedDirty = true;
|
||||||
|
@ -2352,6 +2357,19 @@ void AITAC_LinkDeployedItemToAction(AvHAIPlayer* CommanderBot, const AvHAIDroppe
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void AITAC_ClearStructureNavData()
|
||||||
|
{
|
||||||
|
for (auto& it : TeamAStructureMap)
|
||||||
|
{
|
||||||
|
AITAC_OnStructureDestroyed(&it.second);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (auto& it : TeamBStructureMap)
|
||||||
|
{
|
||||||
|
AITAC_OnStructureDestroyed(&it.second);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void AITAC_ClearMapAIData()
|
void AITAC_ClearMapAIData()
|
||||||
{
|
{
|
||||||
UTIL_ClearLocalizations();
|
UTIL_ClearLocalizations();
|
||||||
|
@ -2360,12 +2378,19 @@ void AITAC_ClearMapAIData()
|
||||||
|
|
||||||
AITAC_ClearHiveInfo();
|
AITAC_ClearHiveInfo();
|
||||||
|
|
||||||
|
AITAC_ClearStructureNavData();
|
||||||
|
|
||||||
|
while (!bTileCacheUpToDate)
|
||||||
|
{
|
||||||
|
UTIL_UpdateTileCache();
|
||||||
|
}
|
||||||
|
|
||||||
MarineDroppedItemMap.clear();
|
MarineDroppedItemMap.clear();
|
||||||
TeamAStructureMap.clear();
|
TeamAStructureMap.clear();
|
||||||
TeamBStructureMap.clear();
|
TeamBStructureMap.clear();
|
||||||
|
|
||||||
StructureRefreshFrame = 0;
|
StructureRefreshFrame = 1;
|
||||||
ItemRefreshFrame = 0;
|
ItemRefreshFrame = 1;
|
||||||
|
|
||||||
last_structure_refresh_time = 0.0f;
|
last_structure_refresh_time = 0.0f;
|
||||||
last_item_refresh_time = 0.0f;
|
last_item_refresh_time = 0.0f;
|
||||||
|
|
|
@ -88,6 +88,8 @@ void AITAC_ClearMapAIData();
|
||||||
// Clear out all the hive information
|
// Clear out all the hive information
|
||||||
void AITAC_ClearHiveInfo();
|
void AITAC_ClearHiveInfo();
|
||||||
|
|
||||||
|
void AITAC_ClearStructureNavData();
|
||||||
|
|
||||||
bool AITAC_AlienHiveNeedsReinforcing(const AvHAIHiveDefinition* Hive);
|
bool AITAC_AlienHiveNeedsReinforcing(const AvHAIHiveDefinition* Hive);
|
||||||
|
|
||||||
void AITAC_RefreshMarineItems();
|
void AITAC_RefreshMarineItems();
|
||||||
|
|
|
@ -1430,6 +1430,18 @@ BOOL AvHGamerules::ClientCommand( CBasePlayer *pPlayer, const char *pcmd )
|
||||||
|
|
||||||
theSuccess = true;
|
theSuccess = true;
|
||||||
}
|
}
|
||||||
|
else if (FStrEq(pcmd, "setdebugvector1"))
|
||||||
|
{
|
||||||
|
AIDEBUG_SetDebugVector1(UTIL_GetFloorUnderEntity(theAvHPlayer->edict()));
|
||||||
|
|
||||||
|
theSuccess = true;
|
||||||
|
}
|
||||||
|
else if (FStrEq(pcmd, "setdebugvector2"))
|
||||||
|
{
|
||||||
|
AIDEBUG_SetDebugVector2(UTIL_GetFloorUnderEntity(theAvHPlayer->edict()));
|
||||||
|
|
||||||
|
theSuccess = true;
|
||||||
|
}
|
||||||
else if (FStrEq(pcmd, "cometome"))
|
else if (FStrEq(pcmd, "cometome"))
|
||||||
{
|
{
|
||||||
vector<AvHAIPlayer*> AIPlayers = AIMGR_GetAllAIPlayers();
|
vector<AvHAIPlayer*> AIPlayers = AIMGR_GetAllAIPlayers();
|
||||||
|
@ -1442,6 +1454,107 @@ BOOL AvHGamerules::ClientCommand( CBasePlayer *pPlayer, const char *pcmd )
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
theSuccess = true;
|
||||||
|
}
|
||||||
|
else if (FStrEq(pcmd, "showteamstarts"))
|
||||||
|
{
|
||||||
|
Vector TeamAStart = AITAC_GetTeamStartingLocation(TEAM_ONE);
|
||||||
|
Vector TeamBStart = AITAC_GetTeamStartingLocation(TEAM_TWO);
|
||||||
|
|
||||||
|
UTIL_DrawLine(INDEXENT(1), theAvHPlayer->pev->origin, TeamAStart, 20.0f, 0, 0, 255);
|
||||||
|
UTIL_DrawLine(INDEXENT(1), theAvHPlayer->pev->origin, TeamBStart, 20.0f, 0, 128, 0);
|
||||||
|
|
||||||
|
theSuccess = true;
|
||||||
|
}
|
||||||
|
else if (FStrEq(pcmd, "testoffwalknode"))
|
||||||
|
{
|
||||||
|
Vector MoveFrom = AIDEBUG_GetDebugVector1();
|
||||||
|
Vector MoveTo = AIDEBUG_GetDebugVector2();
|
||||||
|
|
||||||
|
if (!vIsZero(MoveFrom) && !vIsZero(MoveTo))
|
||||||
|
{
|
||||||
|
bool bOnGround = (theAvHPlayer->pev->flags & FL_ONGROUND) || IsPlayerOnLadder(theAvHPlayer->edict());
|
||||||
|
bool Result = false;
|
||||||
|
|
||||||
|
if (!bOnGround)
|
||||||
|
{
|
||||||
|
Result = false;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Vector NearestPointOnLine = vClosestPointOnLine2D(MoveFrom, MoveTo, theAvHPlayer->pev->origin);
|
||||||
|
|
||||||
|
if (vDist2DSq(theAvHPlayer->pev->origin, NearestPointOnLine) > sqrf(GetPlayerRadius(theAvHPlayer->edict()) * 3.0f)) { Result = true; }
|
||||||
|
|
||||||
|
if (vEquals2D(NearestPointOnLine, MoveFrom) && !UTIL_PointIsDirectlyReachable(GetPlayerBottomOfCollisionHull(theAvHPlayer->edict()), MoveFrom)) { Result = true; }
|
||||||
|
if (vEquals2D(NearestPointOnLine, MoveTo) && !UTIL_PointIsDirectlyReachable(GetPlayerBottomOfCollisionHull(theAvHPlayer->edict()), MoveTo)) { Result = true; }
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Result)
|
||||||
|
{
|
||||||
|
UTIL_SayText("TRUE\n", theAvHPlayer);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
UTIL_SayText("FALSE\n", theAvHPlayer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
theSuccess = true;
|
||||||
|
}
|
||||||
|
else if (FStrEq(pcmd, "testoffclimbnode"))
|
||||||
|
{
|
||||||
|
Vector MoveStart = AIDEBUG_GetDebugVector1();
|
||||||
|
Vector MoveEnd = AIDEBUG_GetDebugVector2();
|
||||||
|
|
||||||
|
if (!vIsZero(MoveStart) && !vIsZero(MoveEnd))
|
||||||
|
{
|
||||||
|
bool bOnGround = (theAvHPlayer->pev->flags & FL_ONGROUND) || IsPlayerOnLadder(theAvHPlayer->edict());
|
||||||
|
bool Result = false;
|
||||||
|
|
||||||
|
edict_t* PlayerEdict = theAvHPlayer->edict();
|
||||||
|
|
||||||
|
if (bOnGround)
|
||||||
|
{
|
||||||
|
if (!UTIL_PointIsDirectlyReachable(GetPlayerBottomOfCollisionHull(PlayerEdict), MoveStart) && !UTIL_PointIsDirectlyReachable(GetPlayerBottomOfCollisionHull(PlayerEdict), MoveEnd))
|
||||||
|
{
|
||||||
|
Result = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Vector ClosestPointOnLine = vClosestPointOnLine2D(MoveStart, MoveEnd, PlayerEdict->v.origin);
|
||||||
|
|
||||||
|
Result = vDist2DSq(PlayerEdict->v.origin, ClosestPointOnLine) > sqrf(GetPlayerRadius(PlayerEdict) * 3.0f);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Result)
|
||||||
|
{
|
||||||
|
UTIL_SayText("TRUE\n", theAvHPlayer);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
UTIL_SayText("FALSE\n", theAvHPlayer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
theSuccess = true;
|
||||||
|
}
|
||||||
|
else if (FStrEq(pcmd, "amonladder"))
|
||||||
|
{
|
||||||
|
if (IsPlayerOnLadder(theAvHPlayer->edict()))
|
||||||
|
{
|
||||||
|
UTIL_SayText("TRUE\n", theAvHPlayer);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
UTIL_SayText("FALSE\n", theAvHPlayer);
|
||||||
|
}
|
||||||
|
|
||||||
theSuccess = true;
|
theSuccess = true;
|
||||||
}
|
}
|
||||||
else if( FStrEq( pcmd, kcRemoveUpgrade) )
|
else if( FStrEq( pcmd, kcRemoveUpgrade) )
|
||||||
|
|
|
@ -392,39 +392,6 @@ AvHGamerules::AvHGamerules() : mTeamA(TEAM_ONE), mTeamB(TEAM_TWO)
|
||||||
AIMGR_RemoveAIPlayerFromTeam(DesiredTeam);
|
AIMGR_RemoveAIPlayerFromTeam(DesiredTeam);
|
||||||
});
|
});
|
||||||
|
|
||||||
REGISTER_SERVER_FUNCTION("sv_testainavigation", []()
|
|
||||||
{
|
|
||||||
if (avh_botsenabled.value == 0)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool bNewTestValue = !AIMGR_GetTestNavMode();
|
|
||||||
|
|
||||||
AIMGR_SetTestNavMode(bNewTestValue);
|
|
||||||
});
|
|
||||||
REGISTER_SERVER_FUNCTION("sv_aidronemode", []()
|
|
||||||
{
|
|
||||||
if (avh_botsenabled.value == 0)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool bNewTestValue = !AIMGR_GetDroneMode();
|
|
||||||
|
|
||||||
AIMGR_SetDroneMode(bNewTestValue);
|
|
||||||
});
|
|
||||||
REGISTER_SERVER_FUNCTION("sv_stopaidebug", []()
|
|
||||||
{
|
|
||||||
if (avh_botsenabled.value == 0)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
AIMGR_SetTestNavMode(false);
|
|
||||||
AIMGR_SetDroneMode(false);
|
|
||||||
});
|
|
||||||
|
|
||||||
g_VoiceGameMgr.Init(&gVoiceHelper, gpGlobals->maxClients);
|
g_VoiceGameMgr.Init(&gVoiceHelper, gpGlobals->maxClients);
|
||||||
|
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
|
@ -2193,6 +2160,8 @@ void AvHGamerules::PlayerSpawn( CBasePlayer *pPlayer )
|
||||||
//theAvHPlayer->InitializeFromTeam();
|
//theAvHPlayer->InitializeFromTeam();
|
||||||
//this->GetTeam(theAvHPlayer->GetTeam())->AddPlayer(theAvHPlayer->entindex(), theAvHPlayer->GetRole());
|
//this->GetTeam(theAvHPlayer->GetTeam())->AddPlayer(theAvHPlayer->entindex(), theAvHPlayer->GetRole());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
AIMGR_PlayerSpawned();
|
||||||
}
|
}
|
||||||
|
|
||||||
void AvHGamerules::PlayerThink( CBasePlayer *pPlayer )
|
void AvHGamerules::PlayerThink( CBasePlayer *pPlayer )
|
||||||
|
|
|
@ -148,6 +148,7 @@ float ns_cvar_float(const cvar_t *cvar);
|
||||||
#define kvBotSkill "mp_botskill"
|
#define kvBotSkill "mp_botskill"
|
||||||
#define kvBotAutoMode "mp_botautomode"
|
#define kvBotAutoMode "mp_botautomode"
|
||||||
#define kvBotCommanderMode "mp_botcommandermode"
|
#define kvBotCommanderMode "mp_botcommandermode"
|
||||||
|
#define kvBotDebugMode "mp_botdebugmode"
|
||||||
|
|
||||||
#define kvEasterEggChance "mp_eastereggchance"
|
#define kvEasterEggChance "mp_eastereggchance"
|
||||||
#define kvUplink "mp_uplink"
|
#define kvUplink "mp_uplink"
|
||||||
|
|
Loading…
Reference in a new issue