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));
case BUILD_SCAN:
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:
return true;
}
@ -2330,69 +2334,72 @@ bool AICOMM_BuildInfantryPortal(AvHAIPlayer* pBot, edict_t* CommChair)
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);
DeployableSearchFilter ExistingPortalFilter;
ExistingPortalFilter.DeployableTypes = STRUCTURE_MARINE_INFANTRYPORTAL;
ExistingPortalFilter.MaxSearchRadius = UTIL_MetresToGoldSrcUnits(10.0f);
ExistingPortalFilter.DeployableTeam = pBot->Player->GetTeam();
ExistingPortalFilter.ReachabilityFlags = AI_REACHABILITY_MARINE;
ExistingPortalFilter.ReachabilityTeam = pBot->Player->GetTeam();
AvHAIBuildableStructure ExistingInfantryPortal = AITAC_FindClosestDeployableToLocation(CommChair->v.origin, &ExistingPortalFilter);
// First see if we can place the next infantry portal next to the first one
if (ExistingInfantryPortal.IsValid())
{
BuildLocation = UTIL_GetRandomPointOnNavmeshInDonutIgnoreReachability(GetBaseNavProfile(STRUCTURE_BASE_NAV_PROFILE), ExistingInfantryPortal.edict->v.origin, UTIL_MetresToGoldSrcUnits(2.0f), UTIL_MetresToGoldSrcUnits(3.0f));
if (!vIsZero(BuildLocation))
{
bool bSuccess = AICOMM_DeployStructure(pBot, STRUCTURE_MARINE_INFANTRYPORTAL, BuildLocation, STRUCTURE_PURPOSE_BASE);
if (bSuccess) { return true; }
}
}
Vector SearchPoint = ZERO_VECTOR;
DeployableSearchFilter ResNodeFilter;
ResNodeFilter.ReachabilityFlags = AI_REACHABILITY_MARINE;
ResNodeFilter.ReachabilityTeam = pBot->Player->GetTeam();
const AvHAIResourceNode* ResNode = AITAC_FindNearestResourceNodeToLocation(CommChair->v.origin, &ResNodeFilter);
if (ResNode)
{
SearchPoint = ResNode->Location;
}
else
{
return false;
}
Vector NearestPointToChair = FindClosestNavigablePointToDestination(GetBaseNavProfile(MARINE_BASE_NAV_PROFILE), SearchPoint, CommChair->v.origin, UTIL_MetresToGoldSrcUnits(5.0f));
if (!vIsZero(NearestPointToChair))
{
float Distance = vDist2D(NearestPointToChair, CommChair->v.origin);
float RandomDist = UTIL_MetresToGoldSrcUnits(5.0f) - Distance;
BuildLocation = UTIL_GetRandomPointOnNavmeshInRadiusIgnoreReachability(GetBaseNavProfile(STRUCTURE_BASE_NAV_PROFILE), NearestPointToChair, RandomDist);
if (!vIsZero(BuildLocation))
{
bool bSuccess = AICOMM_DeployStructure(pBot, STRUCTURE_MARINE_INFANTRYPORTAL, BuildLocation, STRUCTURE_PURPOSE_BASE);
if (bSuccess) { return true; }
}
}
BuildLocation = UTIL_GetRandomPointOnNavmeshInRadiusIgnoreReachability(GetBaseNavProfile(STRUCTURE_BASE_NAV_PROFILE), CommChair->v.origin, UTIL_MetresToGoldSrcUnits(5.0f));
if (bSuccess) { return true; }
}
DeployableSearchFilter ExistingPortalFilter;
ExistingPortalFilter.DeployableTypes = STRUCTURE_MARINE_INFANTRYPORTAL;
ExistingPortalFilter.MaxSearchRadius = UTIL_MetresToGoldSrcUnits(10.0f);
ExistingPortalFilter.DeployableTeam = pBot->Player->GetTeam();
ExistingPortalFilter.ReachabilityFlags = AI_REACHABILITY_MARINE;
ExistingPortalFilter.ReachabilityTeam = pBot->Player->GetTeam();
AvHAIBuildableStructure ExistingInfantryPortal = AITAC_FindClosestDeployableToLocation(CommChair->v.origin, &ExistingPortalFilter);
// First see if we can place the next infantry portal next to the first one
if (ExistingInfantryPortal.IsValid())
{
BuildLocation = UTIL_GetRandomPointOnNavmeshInDonutIgnoreReachability(GetBaseNavProfile(STRUCTURE_BASE_NAV_PROFILE), ExistingInfantryPortal.edict->v.origin, UTIL_MetresToGoldSrcUnits(2.0f), UTIL_MetresToGoldSrcUnits(3.0f));
if (!vIsZero(BuildLocation))
{
bool bSuccess = AICOMM_DeployStructure(pBot, STRUCTURE_MARINE_INFANTRYPORTAL, BuildLocation, STRUCTURE_PURPOSE_BASE);
if (bSuccess) { return true; }
}
}
Vector SearchPoint = ZERO_VECTOR;
DeployableSearchFilter ResNodeFilter;
ResNodeFilter.ReachabilityFlags = AI_REACHABILITY_MARINE;
ResNodeFilter.ReachabilityTeam = pBot->Player->GetTeam();
const AvHAIResourceNode* ResNode = AITAC_FindNearestResourceNodeToLocation(CommChair->v.origin, &ResNodeFilter);
if (ResNode)
{
SearchPoint = ResNode->Location;
}
else
{
return false;
}
Vector NearestPointToChair = FindClosestNavigablePointToDestination(GetBaseNavProfile(MARINE_BASE_NAV_PROFILE), SearchPoint, CommChair->v.origin, BALANCE_VAR(kCommandStationBuildDistance));
if (!vIsZero(NearestPointToChair))
{
float Distance = vDist2D(NearestPointToChair, CommChair->v.origin);
float RandomDist = UTIL_MetresToGoldSrcUnits(5.0f) - Distance;
BuildLocation = UTIL_GetRandomPointOnNavmeshInRadiusIgnoreReachability(GetBaseNavProfile(STRUCTURE_BASE_NAV_PROFILE), NearestPointToChair, RandomDist);
if (!vIsZero(BuildLocation))
{
bool bSuccess = AICOMM_DeployStructure(pBot, STRUCTURE_MARINE_INFANTRYPORTAL, BuildLocation, STRUCTURE_PURPOSE_BASE);
if (bSuccess) { return true; }
}
}
BuildLocation = UTIL_GetRandomPointOnNavmeshInRadiusIgnoreReachability(GetBaseNavProfile(STRUCTURE_BASE_NAV_PROFILE), CommChair->v.origin, BALANCE_VAR(kCommandStationBuildDistance));
if (vIsZero(BuildLocation)) { return false; }
return AICOMM_DeployStructure(pBot, STRUCTURE_MARINE_INFANTRYPORTAL, BuildLocation, STRUCTURE_PURPOSE_BASE);
@ -3055,7 +3062,6 @@ bool AICOMM_CheckForNextSupportAction(AvHAIPlayer* pBot)
}
if (NextRequest->RequestType == BUILD_PHASEGATE && !AITAC_ResearchIsComplete(CommanderTeam, TECH_RESEARCH_PHASETECH))
{
char msg[128];
@ -3065,7 +3071,7 @@ bool AICOMM_CheckForNextSupportAction(AvHAIPlayer* pBot)
return false;
}
if (NextRequest->RequestType == BUILD_OBSERVATORY && !AITAC_ResearchIsComplete(CommanderTeam, TECH_RESEARCH_PHASETECH))
if (NextRequest->RequestType == BUILD_OBSERVATORY || NextRequest->RequestType == BUILD_ARMSLAB)
{
DeployableSearchFilter ArmouryFilter;
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;
AvHAIDeployableStructureType StructureToDeploy = STRUCTURE_NONE;
@ -3115,6 +3154,18 @@ bool AICOMM_CheckForNextSupportAction(AvHAIPlayer* pBot)
RequiredRes = BALANCE_VAR(kPhaseGateCost);
StructureToDeploy = STRUCTURE_MARINE_PHASEGATE;
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:
break;
}
@ -3139,11 +3190,55 @@ bool AICOMM_CheckForNextSupportAction(AvHAIPlayer* pBot)
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));
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);
if (bSuccess)
@ -3712,6 +3807,22 @@ void AICOMM_ReceiveChatRequest(AvHAIPlayer* Commander, edict_t* Requestor, const
{
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; }

View file

@ -136,7 +136,7 @@ typedef enum
STRUCTURE_ALIEN_OFFENCECHAMBER = 1u << 19,
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_ALL_STRUCTURES = ((unsigned int)-1 & ~(STRUCTURE_MARINE_DEPLOYEDMINE))

View file

@ -1887,17 +1887,116 @@ void EndBotFrame(AvHAIPlayer* pBot)
void CustomThink(AvHAIPlayer* pBot)
{
AvHTeamNumber BotTeam = pBot->Player->GetTeam();
AvHTeamNumber EnemyTeam = AIMGR_GetEnemyTeam(BotTeam);
if (AIMGR_GetTeamType(EnemyTeam) == AVH_CLASS_TYPE_MARINE)
if (pBot->Player->GetResources() < 80.0f)
{
AITASK_SetAssaultMarineBaseTask(pBot, &pBot->PrimaryBotTask, AITAC_GetTeamStartingLocation(EnemyTeam), true);
pBot->Player->GiveResources(10.0f);
}
pBot->CurrentTask = &pBot->PrimaryBotTask;
BotProgressTask(pBot, pBot->CurrentTask);
AITASK_BotUpdateAndClearTasks(pBot);
if (pBot->CurrentTask->TaskType == TASK_REINFORCE_STRUCTURE)
{
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)
@ -5615,14 +5714,12 @@ void AIPlayerEndMatchThink(AvHAIPlayer* pBot)
{
if (IsPlayerMarine(pBot->Player))
{
MarineCombatThink(pBot);
if (MarineCombatThink(pBot)) { return; }
}
else
{
AlienCombatThink(pBot);
if (AlienCombatThink(pBot)) { return; }
}
return;
}
AvHTeamNumber BotTeam = pBot->Player->GetTeam();
@ -5667,16 +5764,16 @@ void AIPlayerDMThink(AvHAIPlayer* pBot)
{
if (IsPlayerMarine(pBot->Player))
{
MarineCombatThink(pBot);
if (MarineCombatThink(pBot)) { return; }
}
else
{
AlienCombatThink(pBot);
if (AlienCombatThink(pBot)) { return; }
}
return;
}
pBot->CurrentTask = &pBot->PrimaryBotTask;
AITASK_BotUpdateAndClearTasks(pBot);
if (pBot->CurrentTask->TaskType == TASK_NONE)

View file

@ -876,9 +876,9 @@ bool AITASK_IsReinforceStructureTaskStillValid(AvHAIPlayer* pBot, AvHAIPlayerTas
if (bActiveHiveWithoutTechExists) { return true; }
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.DeployableTeam = pBot->Player->GetTeam();
StructureFilter.DeployableTeam = BotTeam;
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
if (Task->ActiveBuildInfo.BuildStatus == BUILD_ATTEMPT_FAILED || Task->ActiveBuildInfo.BuildStatus == BUILD_ATTEMPT_SUCCESS)
{
Task->TaskStartedTime = gpGlobals->time;
Task->TaskLocation = ZERO_VECTOR;
Task->ActiveBuildInfo.BuildStatus = BUILD_ATTEMPT_NONE;
}
if (gpGlobals->time - Task->TaskStartedTime < 1.0f) { return; }
AvHTeamNumber BotTeam = pBot->Player->GetTeam();
Vector ReinforceLocation = UTIL_ProjectPointToNavmesh(UTIL_GetEntityGroundLocation(Task->TaskTarget), pBot->BotNavInfo.NavProfile);