Commander Placements Tweaks

* Commander won't get stuck trying to build base structures if using nav hints that are placed in bad spots (i.e. can't deploy structures where the nav hint is)
* Commander can now deploy prototype labs, arms labs and infantry portals on request
This commit is contained in:
RGreenlees 2024-05-25 16:35:50 +01:00 committed by pierow
parent 9452b8a0c3
commit 9a4a6b3660
5 changed files with 290 additions and 79 deletions

View file

@ -993,6 +993,10 @@ bool AICOMM_IsRequestValid(ai_commander_request* Request)
return !AITAC_IsStructureOfTypeNearLocation(RequestorTeam, STRUCTURE_MARINE_COMMCHAIR, Requestor->v.origin, UTIL_MetresToGoldSrcUnits(10.0f)); return !AITAC_IsStructureOfTypeNearLocation(RequestorTeam, STRUCTURE_MARINE_COMMCHAIR, Requestor->v.origin, UTIL_MetresToGoldSrcUnits(10.0f));
case BUILD_SCAN: case BUILD_SCAN:
return !AITAC_ItemExistsInLocation(Requestor->v.origin, DEPLOYABLE_ITEM_SCAN, RequestorTeam, AI_REACHABILITY_NONE, 0.0f, UTIL_MetresToGoldSrcUnits(5.0f), false); return !AITAC_ItemExistsInLocation(Requestor->v.origin, DEPLOYABLE_ITEM_SCAN, RequestorTeam, AI_REACHABILITY_NONE, 0.0f, UTIL_MetresToGoldSrcUnits(5.0f), false);
case BUILD_ARMSLAB:
return !AITAC_IsStructureOfTypeNearLocation(RequestorTeam, STRUCTURE_MARINE_ARMSLAB, Requestor->v.origin, UTIL_MetresToGoldSrcUnits(10.0f));
case BUILD_PROTOTYPE_LAB:
return !AITAC_IsStructureOfTypeNearLocation(RequestorTeam, STRUCTURE_MARINE_PROTOTYPELAB, Requestor->v.origin, UTIL_MetresToGoldSrcUnits(10.0f));
default: default:
return true; return true;
} }
@ -2330,8 +2334,12 @@ bool AICOMM_BuildInfantryPortal(AvHAIPlayer* pBot, edict_t* CommChair)
Vector BuildLocation = AITAC_GetRandomBuildHintInLocation(STRUCTURE_MARINE_INFANTRYPORTAL, CommChair->v.origin, BALANCE_VAR(kCommandStationBuildDistance)); Vector BuildLocation = AITAC_GetRandomBuildHintInLocation(STRUCTURE_MARINE_INFANTRYPORTAL, CommChair->v.origin, BALANCE_VAR(kCommandStationBuildDistance));
if (vIsZero(BuildLocation)) if (!vIsZero(BuildLocation))
{ {
bool bSuccess = AICOMM_DeployStructure(pBot, STRUCTURE_MARINE_INFANTRYPORTAL, BuildLocation, STRUCTURE_PURPOSE_BASE);
if (bSuccess) { return true; }
}
DeployableSearchFilter ExistingPortalFilter; DeployableSearchFilter ExistingPortalFilter;
ExistingPortalFilter.DeployableTypes = STRUCTURE_MARINE_INFANTRYPORTAL; ExistingPortalFilter.DeployableTypes = STRUCTURE_MARINE_INFANTRYPORTAL;
@ -2372,7 +2380,7 @@ bool AICOMM_BuildInfantryPortal(AvHAIPlayer* pBot, edict_t* CommChair)
return false; return false;
} }
Vector NearestPointToChair = FindClosestNavigablePointToDestination(GetBaseNavProfile(MARINE_BASE_NAV_PROFILE), SearchPoint, CommChair->v.origin, UTIL_MetresToGoldSrcUnits(5.0f)); Vector NearestPointToChair = FindClosestNavigablePointToDestination(GetBaseNavProfile(MARINE_BASE_NAV_PROFILE), SearchPoint, CommChair->v.origin, BALANCE_VAR(kCommandStationBuildDistance));
if (!vIsZero(NearestPointToChair)) if (!vIsZero(NearestPointToChair))
{ {
@ -2390,8 +2398,7 @@ bool AICOMM_BuildInfantryPortal(AvHAIPlayer* pBot, edict_t* CommChair)
} }
BuildLocation = UTIL_GetRandomPointOnNavmeshInRadiusIgnoreReachability(GetBaseNavProfile(STRUCTURE_BASE_NAV_PROFILE), CommChair->v.origin, UTIL_MetresToGoldSrcUnits(5.0f)); BuildLocation = UTIL_GetRandomPointOnNavmeshInRadiusIgnoreReachability(GetBaseNavProfile(STRUCTURE_BASE_NAV_PROFILE), CommChair->v.origin, BALANCE_VAR(kCommandStationBuildDistance));
}
if (vIsZero(BuildLocation)) { return false; } if (vIsZero(BuildLocation)) { return false; }
@ -3055,7 +3062,6 @@ bool AICOMM_CheckForNextSupportAction(AvHAIPlayer* pBot)
} }
if (NextRequest->RequestType == BUILD_PHASEGATE && !AITAC_ResearchIsComplete(CommanderTeam, TECH_RESEARCH_PHASETECH)) if (NextRequest->RequestType == BUILD_PHASEGATE && !AITAC_ResearchIsComplete(CommanderTeam, TECH_RESEARCH_PHASETECH))
{ {
char msg[128]; char msg[128];
@ -3065,7 +3071,7 @@ bool AICOMM_CheckForNextSupportAction(AvHAIPlayer* pBot)
return false; return false;
} }
if (NextRequest->RequestType == BUILD_OBSERVATORY && !AITAC_ResearchIsComplete(CommanderTeam, TECH_RESEARCH_PHASETECH)) if (NextRequest->RequestType == BUILD_OBSERVATORY || NextRequest->RequestType == BUILD_ARMSLAB)
{ {
DeployableSearchFilter ArmouryFilter; DeployableSearchFilter ArmouryFilter;
ArmouryFilter.DeployableTeam = CommanderTeam; ArmouryFilter.DeployableTeam = CommanderTeam;
@ -3085,6 +3091,39 @@ bool AICOMM_CheckForNextSupportAction(AvHAIPlayer* pBot)
} }
} }
if (NextRequest->RequestType == BUILD_PROTOTYPE_LAB)
{
DeployableSearchFilter RequiredFilter;
RequiredFilter.DeployableTeam = CommanderTeam;
RequiredFilter.DeployableTypes = STRUCTURE_MARINE_ADVARMOURY;
RequiredFilter.IncludeStatusFlags = STRUCTURE_STATUS_COMPLETED;
RequiredFilter.ExcludeStatusFlags = STRUCTURE_STATUS_RECYCLING;
bool bHasArmoury = AITAC_DeployableExistsAtLocation(ZERO_VECTOR, &RequiredFilter);
if (!bHasArmoury)
{
char msg[128];
sprintf(msg, "We haven't got an advanced armory yet, %s. Ask again later.", STRING(Requestor->v.netname));
BotSay(pBot, true, 0.5f, msg);
NextRequest->bResponded = true;
return false;
}
RequiredFilter.DeployableTypes = STRUCTURE_MARINE_ARMSLAB;
bool bHasArmsLab = AITAC_DeployableExistsAtLocation(ZERO_VECTOR, &RequiredFilter);
if (!bHasArmsLab)
{
char msg[128];
sprintf(msg, "We haven't got an arms lab yet, %s. Ask again later.", STRING(Requestor->v.netname));
BotSay(pBot, true, 0.5f, msg);
NextRequest->bResponded = true;
return false;
}
}
float RequiredRes = 0.0f; float RequiredRes = 0.0f;
AvHAIDeployableStructureType StructureToDeploy = STRUCTURE_NONE; AvHAIDeployableStructureType StructureToDeploy = STRUCTURE_NONE;
@ -3115,6 +3154,18 @@ bool AICOMM_CheckForNextSupportAction(AvHAIPlayer* pBot)
RequiredRes = BALANCE_VAR(kPhaseGateCost); RequiredRes = BALANCE_VAR(kPhaseGateCost);
StructureToDeploy = STRUCTURE_MARINE_PHASEGATE; StructureToDeploy = STRUCTURE_MARINE_PHASEGATE;
break; break;
case BUILD_INFANTRYPORTAL:
RequiredRes = BALANCE_VAR(kInfantryPortalCost);
StructureToDeploy = STRUCTURE_MARINE_INFANTRYPORTAL;
break;
case BUILD_PROTOTYPE_LAB:
RequiredRes = BALANCE_VAR(kPrototypeLabCost);
StructureToDeploy = STRUCTURE_MARINE_PROTOTYPELAB;
break;
case BUILD_ARMSLAB:
RequiredRes = BALANCE_VAR(kArmsLabCost);
StructureToDeploy = STRUCTURE_MARINE_ARMSLAB;
break;
default: default:
break; break;
} }
@ -3139,11 +3190,55 @@ bool AICOMM_CheckForNextSupportAction(AvHAIPlayer* pBot)
return false; return false;
} }
Vector IdealDeployLocation = Requestor->v.origin + (UTIL_GetForwardVector2D(Requestor->v.angles) * 75.0f); float ProjectDistance = (NextRequest->RequestType == BUILD_INFANTRYPORTAL || NextRequest->RequestType == BUILD_SIEGE) ? 32.0f : 75.0f;
Vector IdealDeployLocation = Requestor->v.origin + (UTIL_GetForwardVector2D(Requestor->v.angles) * ProjectDistance);
Vector ProjectedDeployLocation = AdjustPointForPathfinding(IdealDeployLocation, GetBaseNavProfile(STRUCTURE_BASE_NAV_PROFILE)); Vector ProjectedDeployLocation = AdjustPointForPathfinding(IdealDeployLocation, GetBaseNavProfile(STRUCTURE_BASE_NAV_PROFILE));
if (!vIsZero(ProjectedDeployLocation)) if (!vIsZero(ProjectedDeployLocation))
{ {
if (NextRequest->RequestType == BUILD_INFANTRYPORTAL)
{
DeployableSearchFilter CCFilter;
CCFilter.DeployableTeam = CommanderTeam;
CCFilter.DeployableTypes = STRUCTURE_MARINE_COMMCHAIR;
CCFilter.IncludeStatusFlags = STRUCTURE_STATUS_COMPLETED;
CCFilter.ExcludeStatusFlags = STRUCTURE_STATUS_RECYCLING;
CCFilter.MaxSearchRadius = BALANCE_VAR(kCommandStationBuildDistance);
bool bHasChair = AITAC_DeployableExistsAtLocation(ProjectedDeployLocation, &CCFilter);
if (!bHasChair)
{
char msg[128];
sprintf(msg, "There isn't a comm chair there, %s. Ask again next to the CC", STRING(Requestor->v.netname));
BotSay(pBot, true, 0.5f, msg);
NextRequest->bResponded = true;
return false;
}
}
if (NextRequest->RequestType == BUILD_SIEGE)
{
DeployableSearchFilter TFFilter;
TFFilter.DeployableTeam = CommanderTeam;
TFFilter.DeployableTypes = STRUCTURE_MARINE_ADVTURRETFACTORY;
TFFilter.IncludeStatusFlags = STRUCTURE_STATUS_COMPLETED;
TFFilter.ExcludeStatusFlags = STRUCTURE_STATUS_RECYCLING;
TFFilter.MaxSearchRadius = BALANCE_VAR(kTurretFactoryBuildDistance);
bool bHasChair = AITAC_DeployableExistsAtLocation(ProjectedDeployLocation, &TFFilter);
if (!bHasChair)
{
char msg[128];
sprintf(msg, "There isn't a an advanced armory there, %s. Ask again next to one", STRING(Requestor->v.netname));
BotSay(pBot, true, 0.5f, msg);
NextRequest->bResponded = true;
return false;
}
}
bool bSuccess = AICOMM_DeployStructure(pBot, StructureToDeploy, ProjectedDeployLocation, STRUCTURE_PURPOSE_NONE); bool bSuccess = AICOMM_DeployStructure(pBot, StructureToDeploy, ProjectedDeployLocation, STRUCTURE_PURPOSE_NONE);
if (bSuccess) if (bSuccess)
@ -3712,6 +3807,22 @@ void AICOMM_ReceiveChatRequest(AvHAIPlayer* Commander, edict_t* Requestor, const
{ {
NewRequestType = BUILD_OBSERVATORY; NewRequestType = BUILD_OBSERVATORY;
} }
else if (!stricmp(Request, "pl") || !stricmp(Request, "protolab") || !stricmp(Request, "proto lab") || !stricmp(Request, "prototype lab"))
{
NewRequestType = BUILD_PROTOTYPE_LAB;
}
else if (!stricmp(Request, "ip") || !stricmp(Request, "portal") || !stricmp(Request, "inf portal") || !stricmp(Request, "infantry portal"))
{
NewRequestType = BUILD_INFANTRYPORTAL;
}
else if (!stricmp(Request, "al") || !stricmp(Request, "armslab") || !stricmp(Request, "arms lab"))
{
NewRequestType = BUILD_ARMSLAB;
}
else if (!stricmp(Request, "sc") || !stricmp(Request, "st") || !stricmp(Request, "siegeturret") || !stricmp(Request, "siege turret") || !stricmp(Request, "siegecannon") || !stricmp(Request, "siege cannon"))
{
NewRequestType = BUILD_SIEGE;
}
if (NewRequestType == MESSAGE_NULL) { return; } if (NewRequestType == MESSAGE_NULL) { return; }

View file

@ -136,7 +136,7 @@ typedef enum
STRUCTURE_ALIEN_OFFENCECHAMBER = 1u << 19, STRUCTURE_ALIEN_OFFENCECHAMBER = 1u << 19,
SEARCH_ALL_MARINE_STRUCTURES = 0xFFF, SEARCH_ALL_MARINE_STRUCTURES = 0xFFF,
SEARCH_ALL_ALIEN_STRUCTURES = 0xFC000, SEARCH_ALL_ALIEN_STRUCTURES = (STRUCTURE_ALIEN_HIVE | STRUCTURE_ALIEN_RESTOWER | STRUCTURE_ALIEN_DEFENCECHAMBER | STRUCTURE_ALIEN_SENSORYCHAMBER | STRUCTURE_ALIEN_MOVEMENTCHAMBER | STRUCTURE_ALIEN_OFFENCECHAMBER),
SEARCH_ANY_RES_TOWER = (STRUCTURE_MARINE_RESTOWER | STRUCTURE_ALIEN_RESTOWER), SEARCH_ANY_RES_TOWER = (STRUCTURE_MARINE_RESTOWER | STRUCTURE_ALIEN_RESTOWER),
SEARCH_ALL_STRUCTURES = ((unsigned int)-1 & ~(STRUCTURE_MARINE_DEPLOYEDMINE)) SEARCH_ALL_STRUCTURES = ((unsigned int)-1 & ~(STRUCTURE_MARINE_DEPLOYEDMINE))

View file

@ -1887,17 +1887,116 @@ void EndBotFrame(AvHAIPlayer* pBot)
void CustomThink(AvHAIPlayer* pBot) void CustomThink(AvHAIPlayer* pBot)
{ {
AvHTeamNumber BotTeam = pBot->Player->GetTeam(); if (pBot->Player->GetResources() < 80.0f)
AvHTeamNumber EnemyTeam = AIMGR_GetEnemyTeam(BotTeam);
if (AIMGR_GetTeamType(EnemyTeam) == AVH_CLASS_TYPE_MARINE)
{ {
AITASK_SetAssaultMarineBaseTask(pBot, &pBot->PrimaryBotTask, AITAC_GetTeamStartingLocation(EnemyTeam), true); pBot->Player->GiveResources(10.0f);
} }
pBot->CurrentTask = &pBot->PrimaryBotTask; pBot->CurrentTask = &pBot->PrimaryBotTask;
AITASK_BotUpdateAndClearTasks(pBot);
if (pBot->CurrentTask->TaskType == TASK_REINFORCE_STRUCTURE)
{
BotProgressTask(pBot, pBot->CurrentTask); BotProgressTask(pBot, pBot->CurrentTask);
return;
}
// No missing upgrade chambers to drop, let's look for empty hives we can start staking a claim to, to deny to the enemy
vector<AvHAIHiveDefinition*> AllHives = AITAC_GetAllHives();
AvHAIHiveDefinition* HiveToSecure = nullptr;
AvHTeamNumber BotTeam = pBot->Player->GetTeam();
AvHTeamNumber EnemyTeam = AIMGR_GetEnemyTeam(BotTeam);
float MinDist = 0.0f;
for (auto it = AllHives.begin(); it != AllHives.end(); it++)
{
AvHAIHiveDefinition* ThisHive = (*it);
if (ThisHive->Status == HIVE_STATUS_UNBUILT)
{
unsigned int StructureTypes = (STRUCTURE_MARINE_PHASEGATE | STRUCTURE_MARINE_TURRETFACTORY | STRUCTURE_MARINE_ADVTURRETFACTORY);
if (AIMGR_GetTeamType(EnemyTeam) == AVH_CLASS_TYPE_ALIEN)
{
StructureTypes = STRUCTURE_ALIEN_OFFENCECHAMBER;
}
DeployableSearchFilter EnemyStructureFilter;
EnemyStructureFilter.DeployableTeam = EnemyTeam;
EnemyStructureFilter.IncludeStatusFlags = STRUCTURE_STATUS_COMPLETED;
EnemyStructureFilter.ExcludeStatusFlags = STRUCTURE_STATUS_RECYCLING;
EnemyStructureFilter.DeployableTypes = StructureTypes;
EnemyStructureFilter.MaxSearchRadius = UTIL_MetresToGoldSrcUnits(10.0f);
bool bEnemyHaveFoothold = AITAC_DeployableExistsAtLocation(ThisHive->FloorLocation, &EnemyStructureFilter);
if (bEnemyHaveFoothold) { continue; }
if (AITAC_GetNumPlayersOfTeamInArea(EnemyTeam, ThisHive->FloorLocation, UTIL_MetresToGoldSrcUnits(10.0f), false, nullptr, AVH_USER3_COMMANDER_PLAYER) > 1) { continue; }
int OtherBuilders = AITAC_GetNumPlayersOfTeamAndClassInArea(EnemyTeam, ThisHive->FloorLocation, UTIL_MetresToGoldSrcUnits(10.0f), false, nullptr, AVH_USER3_ALIEN_PLAYER2);
if (OtherBuilders >= 2) { continue; }
DeployableSearchFilter ExistingReinforcementFilter;
ExistingReinforcementFilter.DeployableTeam = BotTeam;
ExistingReinforcementFilter.MaxSearchRadius = UTIL_MetresToGoldSrcUnits(10.0f);
ExistingReinforcementFilter.DeployableTypes = SEARCH_ALL_STRUCTURES;
vector<AvHAIBuildableStructure> AllReinforcingStructures = AITAC_FindAllDeployables(ThisHive->FloorLocation, &ExistingReinforcementFilter);
int NumOCs = 0;
int NumDCs = 0;
int NumMCs = 0;
int NumSCs = 0;
for (auto it = AllReinforcingStructures.begin(); it != AllReinforcingStructures.end(); it++)
{
switch ((*it).StructureType)
{
case STRUCTURE_ALIEN_OFFENCECHAMBER:
NumOCs++;
break;
case STRUCTURE_ALIEN_DEFENCECHAMBER:
NumDCs++;
break;
case STRUCTURE_ALIEN_MOVEMENTCHAMBER:
NumMCs++;
break;
case STRUCTURE_ALIEN_SENSORYCHAMBER:
NumSCs++;
break;
default:
break;
}
}
if (NumOCs < 3
|| (AITAC_TeamHiveWithTechExists(BotTeam, ALIEN_BUILD_DEFENSE_CHAMBER) && NumDCs < 2)
|| (AITAC_TeamHiveWithTechExists(BotTeam, ALIEN_BUILD_MOVEMENT_CHAMBER) && NumMCs < 1)
|| (AITAC_TeamHiveWithTechExists(BotTeam, ALIEN_BUILD_SENSORY_CHAMBER) && NumSCs < 1))
{
float ThisDist = vDist2DSq(pBot->Edict->v.origin, ThisHive->FloorLocation);
if (!HiveToSecure || ThisDist < MinDist)
{
HiveToSecure = ThisHive;
MinDist = ThisDist;
}
}
}
}
if (HiveToSecure)
{
AITASK_SetReinforceStructureTask(pBot, &pBot->PrimaryBotTask, HiveToSecure->HiveEdict, false);
return;
}
} }
void DroneThink(AvHAIPlayer* pBot) void DroneThink(AvHAIPlayer* pBot)
@ -5615,14 +5714,12 @@ void AIPlayerEndMatchThink(AvHAIPlayer* pBot)
{ {
if (IsPlayerMarine(pBot->Player)) if (IsPlayerMarine(pBot->Player))
{ {
MarineCombatThink(pBot); if (MarineCombatThink(pBot)) { return; }
} }
else else
{ {
AlienCombatThink(pBot); if (AlienCombatThink(pBot)) { return; }
} }
return;
} }
AvHTeamNumber BotTeam = pBot->Player->GetTeam(); AvHTeamNumber BotTeam = pBot->Player->GetTeam();
@ -5667,15 +5764,15 @@ void AIPlayerDMThink(AvHAIPlayer* pBot)
{ {
if (IsPlayerMarine(pBot->Player)) if (IsPlayerMarine(pBot->Player))
{ {
MarineCombatThink(pBot); if (MarineCombatThink(pBot)) { return; }
} }
else else
{ {
AlienCombatThink(pBot); if (AlienCombatThink(pBot)) { return; }
}
} }
return; pBot->CurrentTask = &pBot->PrimaryBotTask;
}
AITASK_BotUpdateAndClearTasks(pBot); AITASK_BotUpdateAndClearTasks(pBot);

View file

@ -876,9 +876,9 @@ bool AITASK_IsReinforceStructureTaskStillValid(AvHAIPlayer* pBot, AvHAIPlayerTas
if (bActiveHiveWithoutTechExists) { return true; } if (bActiveHiveWithoutTechExists) { return true; }
DeployableSearchFilter StructureFilter; DeployableSearchFilter StructureFilter;
StructureFilter.DeployableTypes = STRUCTURE_ALIEN_OFFENCECHAMBER | ALIEN_BUILD_DEFENSE_CHAMBER | ALIEN_BUILD_MOVEMENT_CHAMBER | ALIEN_BUILD_SENSORY_CHAMBER; StructureFilter.DeployableTypes = SEARCH_ALL_ALIEN_STRUCTURES;
StructureFilter.MaxSearchRadius = (IsEdictHive(Task->TaskTarget)) ? UTIL_MetresToGoldSrcUnits(10.0f) : UTIL_MetresToGoldSrcUnits(5.0f); StructureFilter.MaxSearchRadius = (IsEdictHive(Task->TaskTarget)) ? UTIL_MetresToGoldSrcUnits(10.0f) : UTIL_MetresToGoldSrcUnits(5.0f);
StructureFilter.DeployableTeam = pBot->Player->GetTeam(); StructureFilter.DeployableTeam = BotTeam;
vector<AvHAIBuildableStructure> AllNearbyStructures = AITAC_FindAllDeployables(Task->TaskTarget->v.origin, &StructureFilter); vector<AvHAIBuildableStructure> AllNearbyStructures = AITAC_FindAllDeployables(Task->TaskTarget->v.origin, &StructureFilter);
@ -1356,10 +1356,13 @@ void BotProgressReinforceStructureTask(AvHAIPlayer* pBot, AvHAIPlayerTask* Task)
// We had a go, whether it succeeded or not we should try a new location // We had a go, whether it succeeded or not we should try a new location
if (Task->ActiveBuildInfo.BuildStatus == BUILD_ATTEMPT_FAILED || Task->ActiveBuildInfo.BuildStatus == BUILD_ATTEMPT_SUCCESS) if (Task->ActiveBuildInfo.BuildStatus == BUILD_ATTEMPT_FAILED || Task->ActiveBuildInfo.BuildStatus == BUILD_ATTEMPT_SUCCESS)
{ {
Task->TaskStartedTime = gpGlobals->time;
Task->TaskLocation = ZERO_VECTOR; Task->TaskLocation = ZERO_VECTOR;
Task->ActiveBuildInfo.BuildStatus = BUILD_ATTEMPT_NONE; Task->ActiveBuildInfo.BuildStatus = BUILD_ATTEMPT_NONE;
} }
if (gpGlobals->time - Task->TaskStartedTime < 1.0f) { return; }
AvHTeamNumber BotTeam = pBot->Player->GetTeam(); AvHTeamNumber BotTeam = pBot->Player->GetTeam();
Vector ReinforceLocation = UTIL_ProjectPointToNavmesh(UTIL_GetEntityGroundLocation(Task->TaskTarget), pBot->BotNavInfo.NavProfile); Vector ReinforceLocation = UTIL_ProjectPointToNavmesh(UTIL_GetEntityGroundLocation(Task->TaskTarget), pBot->BotNavInfo.NavProfile);