From 881fe37cce5889665f94c8f49c84526f50c97a9a Mon Sep 17 00:00:00 2001 From: RGreenlees Date: Sat, 25 May 2024 16:35:50 +0100 Subject: [PATCH] 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 --- main/navmeshes/NavEditor/GoldsrcNavEditor.exe | Bin 261120 -> 261120 bytes main/source/mod/AvHAICommander.cpp | 235 +++++++++++++----- main/source/mod/AvHAIConstants.h | 2 +- main/source/mod/AvHAIPlayer.cpp | 125 ++++++++-- main/source/mod/AvHAITask.cpp | 7 +- 5 files changed, 290 insertions(+), 79 deletions(-) diff --git a/main/navmeshes/NavEditor/GoldsrcNavEditor.exe b/main/navmeshes/NavEditor/GoldsrcNavEditor.exe index 54dfb43d60014bbc1241b791eebfa73d3a1e9333..5b7a2c19214e00f05f23f27031e8a072d9867bae 100644 GIT binary patch delta 22551 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 G_J05XY{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,68 +2334,71 @@ 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)) { - - 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(); + bool bSuccess = AICOMM_DeployStructure(pBot, STRUCTURE_MARINE_INFANTRYPORTAL, BuildLocation, STRUCTURE_PURPOSE_BASE); - 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; } @@ -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; } diff --git a/main/source/mod/AvHAIConstants.h b/main/source/mod/AvHAIConstants.h index 679276fe..c89b17c4 100644 --- a/main/source/mod/AvHAIConstants.h +++ b/main/source/mod/AvHAIConstants.h @@ -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)) diff --git a/main/source/mod/AvHAIPlayer.cpp b/main/source/mod/AvHAIPlayer.cpp index 48c08a1b..ae9b17ce 100644 --- a/main/source/mod/AvHAIPlayer.cpp +++ b/main/source/mod/AvHAIPlayer.cpp @@ -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 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 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) diff --git a/main/source/mod/AvHAITask.cpp b/main/source/mod/AvHAITask.cpp index b9e8503c..c86b62fa 100644 --- a/main/source/mod/AvHAITask.cpp +++ b/main/source/mod/AvHAITask.cpp @@ -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 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);