diff --git a/main/navmeshes/ns_altair.nav b/main/navmeshes/ns_altair.nav index 3e5384ad..720f8ba3 100644 Binary files a/main/navmeshes/ns_altair.nav and b/main/navmeshes/ns_altair.nav differ diff --git a/main/navmeshes/ns_caged.nav b/main/navmeshes/ns_caged.nav index bbc22210..a2ae81fe 100644 Binary files a/main/navmeshes/ns_caged.nav and b/main/navmeshes/ns_caged.nav differ diff --git a/main/navmeshes/ns_eon.nav b/main/navmeshes/ns_eon.nav index af68ede3..ba5fa455 100644 Binary files a/main/navmeshes/ns_eon.nav and b/main/navmeshes/ns_eon.nav differ diff --git a/main/source/mod/AvHAICommander.cpp b/main/source/mod/AvHAICommander.cpp index ca0b2bf3..fd993289 100644 --- a/main/source/mod/AvHAICommander.cpp +++ b/main/source/mod/AvHAICommander.cpp @@ -2025,410 +2025,6 @@ const AvHAIResourceNode* AICOMM_GetNearestResourceNodeCapOpportunity(const AvHTe return Result; } -bool AICOMM_PerformNextSiegeHiveAction(AvHAIPlayer* pBot, const AvHAIHiveDefinition* HiveToSiege) -{ - AvHTeamNumber CommanderTeam = pBot->Player->GetTeam(); - - DeployableSearchFilter StructureFilter; - StructureFilter.DeployableTeam = CommanderTeam; - StructureFilter.ReachabilityFlags = AI_REACHABILITY_MARINE; - StructureFilter.ReachabilityTeam = CommanderTeam; - StructureFilter.ExcludeStatusFlags = STRUCTURE_STATUS_RECYCLING; - - StructureFilter.MaxSearchRadius = UTIL_MetresToGoldSrcUnits(25.0f); - - Vector SiegeLocation = ZERO_VECTOR; - - StructureFilter.DeployableTypes = STRUCTURE_MARINE_PHASEGATE; - AvHAIBuildableStructure ExistingPG = AITAC_FindClosestDeployableToLocation(HiveToSiege->Location, &StructureFilter); - - StructureFilter.DeployableTypes = (STRUCTURE_MARINE_TURRETFACTORY | STRUCTURE_MARINE_ADVTURRETFACTORY); - AvHAIBuildableStructure ExistingTF = AITAC_FindClosestDeployableToLocation(HiveToSiege->Location, &StructureFilter); - - StructureFilter.DeployableTypes = (STRUCTURE_MARINE_ARMOURY | STRUCTURE_MARINE_ADVARMOURY); - AvHAIBuildableStructure ExistingArmoury = AITAC_FindClosestDeployableToLocation(HiveToSiege->Location, &StructureFilter); - - edict_t* NearestBuilder = nullptr; - - // We only build one of these at a time, so we don't drop a bunch of structures and then our intrepid sieger gets killed and the aliens nom them all - if (ExistingPG.IsValid()) - { - if (ExistingPG.IsCompleted()) - { - SiegeLocation = ExistingPG.Location; - NearestBuilder = AITAC_GetClosestPlayerOnTeamWithLOS(CommanderTeam, ExistingPG.Location, UTIL_MetresToGoldSrcUnits(5.0f), pBot->Edict); - } - else - { - // Don't do anything else until we've finished building the phase gate - return false; - } - } - - if (ExistingTF.IsValid()) - { - if (ExistingTF.IsCompleted()) - { - if (vIsZero(SiegeLocation)) - { - SiegeLocation = ExistingTF.Location; - } - - if (FNullEnt(NearestBuilder)) - { - NearestBuilder = AITAC_GetClosestPlayerOnTeamWithLOS(CommanderTeam, ExistingTF.Location, UTIL_MetresToGoldSrcUnits(5.0f), pBot->Edict); - } - } - else - { - // Don't do anything else until we've finished building the turret factory - return false; - } - } - else - { - if (FNullEnt(NearestBuilder)) - { - NearestBuilder = AITAC_GetNearestHiddenPlayerInLocation(CommanderTeam, HiveToSiege->Location, UTIL_MetresToGoldSrcUnits(20.0f)); - } - } - - if (FNullEnt(NearestBuilder)) { return false; } - - bool bPhaseGatesAvailable = AITAC_PhaseGatesAvailable(CommanderTeam); - - if (vIsZero(SiegeLocation)) - { - SiegeLocation = NearestBuilder->v.origin; - } - - AvHAIDeployableStructureType NextStructure = STRUCTURE_NONE; - - if (!ExistingPG.IsValid() && bPhaseGatesAvailable) - { - NextStructure = STRUCTURE_MARINE_PHASEGATE; - } - else if (!ExistingTF.IsValid()) - { - NextStructure = STRUCTURE_MARINE_TURRETFACTORY; - } - else if (!ExistingArmoury.IsValid()) - { - NextStructure = STRUCTURE_MARINE_ARMOURY; - } - - if (NextStructure != STRUCTURE_NONE) - { - Vector NextBuildPosition = UTIL_GetRandomPointOnNavmeshInRadius(GetBaseNavProfile(STRUCTURE_BASE_NAV_PROFILE), SiegeLocation, UTIL_MetresToGoldSrcUnits(3.0f)); - - if (!vIsZero(NextBuildPosition) && vDist2DSq(NextBuildPosition, HiveToSiege->Location) < sqrf(UTIL_MetresToGoldSrcUnits(22.0f))) - { - AvHAIBuildableStructure* DeployedStructure = AICOMM_DeployStructure(pBot, NextStructure, NextBuildPosition, STRUCTURE_PURPOSE_SIEGE); - - if (DeployedStructure) { return true; } - } - - NextBuildPosition = UTIL_GetRandomPointOnNavmeshInRadiusIgnoreReachability(GetBaseNavProfile(STRUCTURE_BASE_NAV_PROFILE), SiegeLocation, UTIL_MetresToGoldSrcUnits(5.0f)); - - if (!vIsZero(NextBuildPosition) && vDist2DSq(NextBuildPosition, HiveToSiege->Location) < sqrf(UTIL_MetresToGoldSrcUnits(22.0f))) - { - AvHAIBuildableStructure* DeployedStructure = AICOMM_DeployStructure(pBot, NextStructure, NextBuildPosition, STRUCTURE_PURPOSE_SIEGE); - - if (DeployedStructure) { return true; } - } - - NextBuildPosition = UTIL_GetRandomPointOnNavmeshInRadius(GetBaseNavProfile(MARINE_BASE_NAV_PROFILE), SiegeLocation, UTIL_MetresToGoldSrcUnits(5.0f)); - - if (!vIsZero(NextBuildPosition) && vDist2DSq(NextBuildPosition, HiveToSiege->Location) < sqrf(UTIL_MetresToGoldSrcUnits(22.0f))) - { - AvHAIBuildableStructure* DeployedStructure = AICOMM_DeployStructure(pBot, NextStructure, NextBuildPosition, STRUCTURE_PURPOSE_SIEGE); - - if (DeployedStructure) { return true; } - } - - return false; - } - - if (!ExistingTF.IsValid()) { return false; } - - if ((ExistingTF.StructureStatusFlags & STRUCTURE_STATUS_RESEARCHING)) { return false; } - - if (ExistingTF.StructureType != STRUCTURE_MARINE_ADVTURRETFACTORY) - { - return AICOMM_UpgradeStructure(pBot, &ExistingTF); - } - - StructureFilter.DeployableTypes = STRUCTURE_MARINE_SIEGETURRET; - StructureFilter.MaxSearchRadius = UTIL_MetresToGoldSrcUnits(5.0f); - - int NumSiegeTurrets = AITAC_GetNumDeployablesNearLocation(ExistingTF.Location, &StructureFilter); - - if (NumSiegeTurrets == 0 || (NumSiegeTurrets < 3 && UTIL_IsStructureElectrified(ExistingTF.edict))) - { - Vector NextBuildPosition = UTIL_GetRandomPointOnNavmeshInRadius(GetBaseNavProfile(STRUCTURE_BASE_NAV_PROFILE), ExistingTF.Location, UTIL_MetresToGoldSrcUnits(5.0f)); - - if (!vIsZero(NextBuildPosition) && vDist2DSq(NextBuildPosition, HiveToSiege->Location) <= sqrf(BALANCE_VAR(kSiegeTurretRange))) - { - AvHAIBuildableStructure* DeployedStructure = AICOMM_DeployStructure(pBot, STRUCTURE_MARINE_SIEGETURRET, NextBuildPosition, STRUCTURE_PURPOSE_SIEGE); - - if (DeployedStructure) { return true; } - } - - NextBuildPosition = UTIL_GetRandomPointOnNavmeshInRadiusIgnoreReachability(GetBaseNavProfile(STRUCTURE_BASE_NAV_PROFILE), ExistingTF.Location, UTIL_MetresToGoldSrcUnits(5.0f)); - - if (!vIsZero(NextBuildPosition) && vDist2DSq(NextBuildPosition, HiveToSiege->Location) <= sqrf(BALANCE_VAR(kSiegeTurretRange))) - { - AvHAIBuildableStructure* DeployedStructure = AICOMM_DeployStructure(pBot, STRUCTURE_MARINE_SIEGETURRET, NextBuildPosition, STRUCTURE_PURPOSE_SIEGE); - - if (DeployedStructure) { return true; } - } - - NextBuildPosition = UTIL_GetRandomPointOnNavmeshInRadius(GetBaseNavProfile(MARINE_BASE_NAV_PROFILE), ExistingTF.Location, UTIL_MetresToGoldSrcUnits(5.0f)); - - if (!vIsZero(NextBuildPosition) && vDist2DSq(NextBuildPosition, HiveToSiege->Location) <= sqrf(BALANCE_VAR(kSiegeTurretRange))) - { - AvHAIBuildableStructure* DeployedStructure = AICOMM_DeployStructure(pBot, STRUCTURE_MARINE_SIEGETURRET, NextBuildPosition, STRUCTURE_PURPOSE_SIEGE); - - if (DeployedStructure) { return true; } - } - - } - - if (!UTIL_IsStructureElectrified(ExistingTF.edict)) - { - return AICOMM_ResearchTech(pBot, &ExistingTF, RESEARCH_ELECTRICAL); - } - - return false; - -} - -bool AICOMM_PerformNextSecureHiveAction(AvHAIPlayer* pBot, const AvHAIHiveDefinition* HiveToSecure) -{ - DeployableSearchFilter StructureFilter; - StructureFilter.DeployableTypes = STRUCTURE_MARINE_TURRETFACTORY | STRUCTURE_MARINE_ADVTURRETFACTORY | STRUCTURE_MARINE_PHASEGATE; - StructureFilter.MaxSearchRadius = UTIL_MetresToGoldSrcUnits(15.0f); - StructureFilter.DeployableTeam = pBot->Player->GetTeam(); - StructureFilter.ReachabilityFlags = AI_REACHABILITY_MARINE; - StructureFilter.ReachabilityTeam = pBot->Player->GetTeam(); - StructureFilter.ExcludeStatusFlags = STRUCTURE_STATUS_RECYCLING; - - AvHAIBuildableStructure ExistingStructure = AITAC_FindClosestDeployableToLocation(HiveToSecure->FloorLocation, &StructureFilter); - AvHAIBuildableStructure ExistingPG; - AvHAIBuildableStructure ExistingTF; - - Vector OutpostLocation = (ExistingStructure.IsValid() && (ExistingStructure.Purpose == STRUCTURE_PURPOSE_FORTIFY || ExistingStructure.Purpose == STRUCTURE_PURPOSE_BASE)) ? ExistingStructure.Location : HiveToSecure->FloorLocation; - - if (HiveToSecure->HiveResNodeRef && HiveToSecure->HiveResNodeRef->OwningTeam == TEAM_IND) - { - AICOMM_DeployStructure(pBot, STRUCTURE_MARINE_RESTOWER, HiveToSecure->HiveResNodeRef->Location); - return true; - } - - if (ExistingStructure.IsValid()) - { - if (ExistingStructure.StructureType == STRUCTURE_MARINE_PHASEGATE) - { - ExistingPG = ExistingStructure; - } - else - { - ExistingTF = ExistingStructure; - } - } - - if (AITAC_PhaseGatesAvailable(pBot->Player->GetTeam())) - { - if (!ExistingPG.IsValid()) - { - StructureFilter.DeployableTypes = STRUCTURE_MARINE_PHASEGATE; - - ExistingPG = AITAC_FindClosestDeployableToLocation(OutpostLocation, &StructureFilter); - - if (!ExistingPG.IsValid()) - { - Vector BuildLocation = UTIL_GetRandomPointOnNavmeshInRadius(GetBaseNavProfile(STRUCTURE_BASE_NAV_PROFILE), OutpostLocation, UTIL_MetresToGoldSrcUnits(5.0f)); - - if (!vIsZero(BuildLocation)) - { - AvHAIBuildableStructure* DeployedStructure = AICOMM_DeployStructure(pBot, STRUCTURE_MARINE_PHASEGATE, BuildLocation, STRUCTURE_PURPOSE_FORTIFY); - - if (DeployedStructure) { return true; } - } - - BuildLocation = UTIL_GetRandomPointOnNavmeshInRadiusIgnoreReachability(GetBaseNavProfile(STRUCTURE_BASE_NAV_PROFILE), OutpostLocation, UTIL_MetresToGoldSrcUnits(5.0f)); - - if (!vIsZero(BuildLocation)) - { - AvHAIBuildableStructure* DeployedStructure = AICOMM_DeployStructure(pBot, STRUCTURE_MARINE_PHASEGATE, BuildLocation, STRUCTURE_PURPOSE_FORTIFY); - - if (DeployedStructure) { return true; } - } - - BuildLocation = UTIL_GetRandomPointOnNavmeshInRadiusIgnoreReachability(GetBaseNavProfile(STRUCTURE_BASE_NAV_PROFILE), HiveToSecure->FloorLocation, UTIL_MetresToGoldSrcUnits(5.0f)); - - if (!vIsZero(BuildLocation)) - { - AvHAIBuildableStructure* DeployedStructure = AICOMM_DeployStructure(pBot, STRUCTURE_MARINE_PHASEGATE, BuildLocation, STRUCTURE_PURPOSE_FORTIFY); - - if (DeployedStructure) { return true; } - } - - return false; - } - } - } - - if (!ExistingTF.IsValid()) - { - StructureFilter.DeployableTypes = STRUCTURE_MARINE_TURRETFACTORY; - - ExistingTF = AITAC_FindClosestDeployableToLocation(OutpostLocation, &StructureFilter); - - if (!ExistingTF.IsValid()) - { - // First, try and put the TF near any existing phasegate (if it exists) - Vector BuildLocation = UTIL_GetRandomPointOnNavmeshInRadius(GetBaseNavProfile(STRUCTURE_BASE_NAV_PROFILE), OutpostLocation, UTIL_MetresToGoldSrcUnits(3.0f)); - - if (!vIsZero(BuildLocation)) - { - AvHAIBuildableStructure* DeployedStructure = AICOMM_DeployStructure(pBot, STRUCTURE_MARINE_TURRETFACTORY, BuildLocation, STRUCTURE_PURPOSE_FORTIFY); - - if (DeployedStructure) { return true; } - } - - // That failed, now try expanding the radius a bit and ignoring reachability - BuildLocation = UTIL_GetRandomPointOnNavmeshInRadiusIgnoreReachability(GetBaseNavProfile(STRUCTURE_BASE_NAV_PROFILE), OutpostLocation, UTIL_MetresToGoldSrcUnits(5.0f)); - - if (!vIsZero(BuildLocation)) - { - AvHAIBuildableStructure* DeployedStructure = AICOMM_DeployStructure(pBot, STRUCTURE_MARINE_TURRETFACTORY, BuildLocation, STRUCTURE_PURPOSE_FORTIFY); - - if (DeployedStructure) { return true; } - } - - // That failed too, try putting it anywhere near the hive location - BuildLocation = UTIL_GetRandomPointOnNavmeshInRadiusIgnoreReachability(GetBaseNavProfile(STRUCTURE_BASE_NAV_PROFILE), HiveToSecure->FloorLocation, UTIL_MetresToGoldSrcUnits(5.0f)); - - if (!vIsZero(BuildLocation)) - { - AvHAIBuildableStructure* DeployedStructure = AICOMM_DeployStructure(pBot, STRUCTURE_MARINE_TURRETFACTORY, BuildLocation, STRUCTURE_PURPOSE_FORTIFY); - - if (DeployedStructure) { return true; } - } - - return false; - } - } - - StructureFilter.DeployableTypes = STRUCTURE_MARINE_TURRET; - StructureFilter.MaxSearchRadius = UTIL_MetresToGoldSrcUnits(10.0f); - - int NumTurrets = AITAC_GetNumDeployablesNearLocation(ExistingTF.Location, &StructureFilter); - - if (NumTurrets < 5) - { - Vector BuildLocation = UTIL_GetRandomPointOnNavmeshInRadiusIgnoreReachability(GetBaseNavProfile(STRUCTURE_BASE_NAV_PROFILE), ExistingTF.Location, (BALANCE_VAR(kCommandStationBuildDistance) * 0.8f)); - - if (!vIsZero(BuildLocation)) - { - AvHAIBuildableStructure* DeployedStructure = AICOMM_DeployStructure(pBot, STRUCTURE_MARINE_TURRET, BuildLocation, STRUCTURE_PURPOSE_FORTIFY); - - if (DeployedStructure) { return true; } - } - - BuildLocation = UTIL_GetRandomPointOnNavmeshInRadius(GetBaseNavProfile(MARINE_BASE_NAV_PROFILE), ExistingTF.Location, (BALANCE_VAR(kCommandStationBuildDistance) * 0.8f)); - - if (!vIsZero(BuildLocation)) - { - AvHAIBuildableStructure* DeployedStructure = AICOMM_DeployStructure(pBot, STRUCTURE_MARINE_TURRET, BuildLocation, STRUCTURE_PURPOSE_FORTIFY); - - if (DeployedStructure) { return true; } - } - - return false; - } - - return false; -} - -bool AICOMM_BuildInfantryPortal(AvHAIPlayer* pBot, edict_t* CommChair) -{ - if (FNullEnt(CommChair) || !UTIL_StructureIsFullyBuilt(CommChair)) { return false; } - - Vector BuildLocation = AITAC_GetRandomBuildHintInLocation(STRUCTURE_MARINE_INFANTRYPORTAL, CommChair->v.origin, BALANCE_VAR(kCommandStationBuildDistance)); - - if (!vIsZero(BuildLocation)) - { - AvHAIBuildableStructure* DeployedStructure = AICOMM_DeployStructure(pBot, STRUCTURE_MARINE_INFANTRYPORTAL, BuildLocation, STRUCTURE_PURPOSE_BASE); - - if (DeployedStructure) { 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)) - { - AvHAIBuildableStructure* DeployedStructure = AICOMM_DeployStructure(pBot, STRUCTURE_MARINE_INFANTRYPORTAL, BuildLocation, STRUCTURE_PURPOSE_BASE); - - if (DeployedStructure) { 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)) - { - AvHAIBuildableStructure* DeployedStructure = AICOMM_DeployStructure(pBot, STRUCTURE_MARINE_INFANTRYPORTAL, BuildLocation, STRUCTURE_PURPOSE_BASE); - - if (DeployedStructure) { 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) != nullptr; -} - bool AICOMM_CheckForNextRecycleAction(AvHAIPlayer* pBot) { for (auto it = pBot->Bases.begin(); it != pBot->Bases.end(); it++) @@ -4188,7 +3784,7 @@ void AICOMM_DeployBases(AvHAIPlayer* pBot) { AvHAIMarineBase* ThisBase = &(*baseIt); - if (ThisBase->BaseType == MARINE_BASE_SIEGE && !ThisBase->bRecycleBase) + if (ThisBase->BaseType == MARINE_BASE_SIEGE) { if (vDist2DSq(ThisHive->Location, ThisBase->BaseLocation) < sqrf(BALANCE_VAR(kSiegeTurretRange))) { @@ -4838,119 +4434,6 @@ bool AICOMM_ShouldCommanderRelocate(AvHAIPlayer* pBot) return false; } -bool AICOMM_CheckForNextRelocationAction(AvHAIPlayer* pBot) -{ - AvHTeamNumber BotTeam = pBot->Player->GetTeam(); - AvHTeamNumber EnemyTeam = AIMGR_GetEnemyTeam(BotTeam); - - Vector RelocationPoint = pBot->RelocationSpot; - - if (vIsZero(RelocationPoint)) { return false; } - - edict_t* CurrentCommChair = AITAC_GetCommChair(BotTeam); - - if (FNullEnt(CurrentCommChair)) { return false; } - - DeployableSearchFilter OrigInfPortalFilter; - OrigInfPortalFilter.DeployableTeam = BotTeam; - OrigInfPortalFilter.DeployableTypes = STRUCTURE_MARINE_INFANTRYPORTAL; - OrigInfPortalFilter.MaxSearchRadius = UTIL_MetresToGoldSrcUnits(5.0f); - - // First ensure we have one infantry portal in our starting location, in case it goes horribly wrong - if (!AITAC_DeployableExistsAtLocation(CurrentCommChair->v.origin, &OrigInfPortalFilter)) - { - return AICOMM_BuildInfantryPortal(pBot, CurrentCommChair); - } - - // Don't do anything more if we don't have anyone at the relocation point yet, but we can drop RTs if needed - if (AITAC_GetNumPlayersOfTeamInArea(BotTeam, RelocationPoint, UTIL_MetresToGoldSrcUnits(10.0f), false, nullptr, AVH_USER3_COMMANDER_PLAYER) == 0) - { - const AvHAIResourceNode* CappableNode = AICOMM_GetNearestResourceNodeCapOpportunity(BotTeam, CurrentCommChair->v.origin); - - if (CappableNode) - { - AvHAIBuildableStructure* DeployedStructure = AICOMM_DeployStructure(pBot, STRUCTURE_MARINE_RESTOWER, CappableNode->Location); - - if (DeployedStructure || pBot->Player->GetResources() <= BALANCE_VAR(kResourceTowerCost) + 10) { return true; } - - } - - return false; - } - - DeployableSearchFilter NewBaseFilter; - NewBaseFilter.DeployableTeam = BotTeam; - NewBaseFilter.DeployableTypes = STRUCTURE_MARINE_COMMCHAIR; - NewBaseFilter.ExcludeStatusFlags = STRUCTURE_STATUS_RECYCLING; - NewBaseFilter.MaxSearchRadius = UTIL_MetresToGoldSrcUnits(10.0f); - - AvHAIBuildableStructure RelocationCommChair = AITAC_FindClosestDeployableToLocation(RelocationPoint, &NewBaseFilter); - - if (!RelocationCommChair.IsValid()) - { - Vector BuildPoint = AITAC_GetRandomBuildHintInLocation(STRUCTURE_MARINE_COMMCHAIR, pBot->RelocationSpot, UTIL_MetresToGoldSrcUnits(10.0f)); - - if (!vIsZero(BuildPoint)) - { - AvHAIBuildableStructure* DeployedStructure = AICOMM_DeployStructure(pBot, STRUCTURE_MARINE_COMMCHAIR, BuildPoint, STRUCTURE_PURPOSE_BASE); - - if (DeployedStructure) { return true; } - } - - BuildPoint = UTIL_GetRandomPointOnNavmeshInRadius(GetBaseNavProfile(STRUCTURE_BASE_NAV_PROFILE), pBot->RelocationSpot, UTIL_MetresToGoldSrcUnits(2.0f)); - - if (!vIsZero(BuildPoint)) - { - AvHAIBuildableStructure* DeployedStructure = AICOMM_DeployStructure(pBot, STRUCTURE_MARINE_COMMCHAIR, BuildPoint, STRUCTURE_PURPOSE_BASE); - - if (DeployedStructure) { return true; } - } - - BuildPoint = UTIL_GetRandomPointOnNavmeshInRadius(GetBaseNavProfile(STRUCTURE_BASE_NAV_PROFILE), pBot->RelocationSpot, UTIL_MetresToGoldSrcUnits(10.0f)); - - if (!vIsZero(BuildPoint)) - { - AvHAIBuildableStructure* DeployedStructure = AICOMM_DeployStructure(pBot, STRUCTURE_MARINE_COMMCHAIR, BuildPoint, STRUCTURE_PURPOSE_BASE); - - if (DeployedStructure) { return true; } - } - - return false; - } - - if (!(RelocationCommChair.StructureStatusFlags & STRUCTURE_STATUS_COMPLETED)) { return false; } - - NewBaseFilter.DeployableTypes = STRUCTURE_MARINE_INFANTRYPORTAL; - NewBaseFilter.MaxSearchRadius = UTIL_MetresToGoldSrcUnits(8.0f); - NewBaseFilter.IncludeStatusFlags = STRUCTURE_STATUS_NONE; - - int NumInfPortals = AITAC_GetNumDeployablesNearLocation(RelocationCommChair.Location, &NewBaseFilter); - - if (NumInfPortals < 2) - { - return AICOMM_BuildInfantryPortal(pBot, RelocationCommChair.edict); - } - - DeployableSearchFilter OldStuffFilter; - OldStuffFilter.DeployableTeam = BotTeam; - OldStuffFilter.ExcludeStatusFlags = STRUCTURE_STATUS_RECYCLING; - OldStuffFilter.DeployableTypes = SEARCH_ALL_STRUCTURES; - OldStuffFilter.MinSearchRadius = UTIL_MetresToGoldSrcUnits(20.0f); - OldStuffFilter.PurposeFlags = STRUCTURE_PURPOSE_BASE; - - vector OldBaseStructures = AITAC_FindAllDeployables(pBot->RelocationSpot, &OldStuffFilter); - - for (auto it = OldBaseStructures.begin(); it != OldBaseStructures.end(); it++) - { - if (it->edict != CurrentCommChair) - { - return AICOMM_RecycleStructure(pBot, &(*it)); - } - } - - return false; -} - bool AICOMM_BuildOutBase(AvHAIPlayer* pBot, AvHAIMarineBase* BaseToBuildOut) { if (!pBot || !BaseToBuildOut) { return false; } diff --git a/main/source/mod/AvHAICommander.h b/main/source/mod/AvHAICommander.h index 34aec671..706e0071 100644 --- a/main/source/mod/AvHAICommander.h +++ b/main/source/mod/AvHAICommander.h @@ -43,7 +43,6 @@ bool AICOMM_CheckForNextSupportAction(AvHAIPlayer* pBot); bool AICOMM_CheckForNextRecycleAction(AvHAIPlayer* pBot); bool AICOMM_CheckForNextResearchAction(AvHAIPlayer* pBot); bool AICOMM_CheckForNextSupplyAction(AvHAIPlayer* pBot); -bool AICOMM_CheckForNextRelocationAction(AvHAIPlayer* pBot); Vector AICOMM_GetNextScanLocation(AvHAIPlayer* pBot); @@ -51,10 +50,6 @@ void AICOMM_CommanderThink(AvHAIPlayer* pBot); const AvHAIHiveDefinition* AICOMM_GetEmptyHiveOpportunityNearestLocation(AvHAIPlayer* CommanderBot, const Vector SearchLocation); -bool AICOMM_BuildInfantryPortal(AvHAIPlayer* pBot, edict_t* CommChair); -bool AICOMM_PerformNextSiegeHiveAction(AvHAIPlayer* pBot, const AvHAIHiveDefinition* HiveToSiege); -bool AICOMM_PerformNextSecureHiveAction(AvHAIPlayer* pBot, const AvHAIHiveDefinition* HiveToSecure); - ai_commander_request* AICOMM_GetExistingRequestForPlayer(AvHAIPlayer* pBot, edict_t* Requestor); void AICOMM_CheckNewRequests(AvHAIPlayer* pBot); bool AICOMM_IsRequestValid(ai_commander_request* Request); diff --git a/main/source/mod/AvHAINavigation.cpp b/main/source/mod/AvHAINavigation.cpp index 8ddff7cb..094f0476 100644 --- a/main/source/mod/AvHAINavigation.cpp +++ b/main/source/mod/AvHAINavigation.cpp @@ -510,6 +510,11 @@ bool UTIL_UpdateTileCache() return bTileCacheUpToDate; } +bool UTIL_IsTileCacheUpToDate() +{ + return bTileCacheUpToDate; +} + Vector UTIL_AdjustPointAwayFromNavWall(const Vector Location, const float MaxDistanceFromWall) { @@ -6865,6 +6870,8 @@ bool MoveTo(AvHAIPlayer* pBot, const Vector Destination, const BotMoveStyle Move return true; } + if (!UTIL_IsTileCacheUpToDate()) { return true; } + nav_status* BotNavInfo = &pBot->BotNavInfo; pBot->BotNavInfo.MoveStyle = MoveStyle; @@ -7060,10 +7067,8 @@ bool MoveTo(AvHAIPlayer* pBot, const Vector Destination, const BotMoveStyle Move Vector FindClosestPointBackOnPath(AvHAIPlayer* pBot, Vector Destination) { - Vector GeneralMoveDir = UTIL_GetVectorNormal2D(Destination - pBot->Edict->v.origin); - Vector CheckDir = pBot->Edict->v.origin + (GeneralMoveDir * 16.0f); - Vector ValidNavmeshPoint = AdjustPointForPathfinding(CheckDir); + Vector ValidNavmeshPoint = AdjustPointForPathfinding(pBot->CollisionHullBottomLocation, pBot->BotNavInfo.NavProfile); if (vIsZero(ValidNavmeshPoint)) { diff --git a/main/source/mod/AvHAINavigation.h b/main/source/mod/AvHAINavigation.h index da9a7072..b771e761 100644 --- a/main/source/mod/AvHAINavigation.h +++ b/main/source/mod/AvHAINavigation.h @@ -495,6 +495,8 @@ nav_door* UTIL_GetNavDoorByEdict(const edict_t* DoorEdict); nav_door* UTIL_GetClosestLiftToPoints(const Vector StartPoint, const Vector EndPoint); AvHAIOffMeshConnection* UTIL_GetOffMeshConnectionForLift(nav_door* LiftRef); +bool UTIL_IsTileCacheUpToDate(); + Vector UTIL_AdjustPointAwayFromNavWall(const Vector Location, const float MaxDistanceFromWall); void UTIL_PopulateBaseNavProfiles(); diff --git a/main/source/mod/AvHAIPlayer.cpp b/main/source/mod/AvHAIPlayer.cpp index 0a1e8755..04ed05ba 100644 --- a/main/source/mod/AvHAIPlayer.cpp +++ b/main/source/mod/AvHAIPlayer.cpp @@ -1460,7 +1460,7 @@ void BotUpdateView(AvHAIPlayer* pBot) bool bHasLOS = !vIsZero(VisiblePoint); bool bIsPlayerInvisible = UTIL_IsCloakedPlayerInvisible(pBot->Edict, PlayerRef); - bool bIsTracked = PlayerRef->GetOpacity() > 0.1f && (!bHasLOS && (IsPlayerParasited(PlayerEdict) || (GetHasUpgrade(pBot->Edict->v.iuser4, MASK_UPGRADE_8) && IsPlayerMotionTracked(PlayerEdict)))); + bool bIsTracked = PlayerRef->GetOpacity() > 0.1f && (!bHasLOS && (IsPlayerParasited(PlayerEdict) || IsPlayerSOF(PlayerEdict) || (GetHasUpgrade(pBot->Edict->v.iuser4, MASK_UPGRADE_8) && IsPlayerMotionTracked(PlayerEdict)))); TrackingInfo->bHasLOS = bHasLOS; TrackingInfo->bEnemyHasLOS = bEnemyCanSee; @@ -1739,15 +1739,14 @@ void StartNewBotFrame(AvHAIPlayer* pBot) Vector ProjectPoint = (IsPlayerLerk(pBot->Edict)) ? pBot->CurrentFloorPosition : pBot->CollisionHullBottomLocation; - if (vDist3DSq(pBot->BotNavInfo.LastNavMeshCheckPosition, ProjectPoint) > sqrf(16.0f)) + if (UTIL_IsTileCacheUpToDate() && vDist3DSq(pBot->BotNavInfo.LastNavMeshCheckPosition, ProjectPoint) > sqrf(16.0f)) { if (UTIL_PointIsReachable(pBot->BotNavInfo.NavProfile, AITAC_GetTeamStartingLocation(pBot->Player->GetTeam()), ProjectPoint, 16.0f)) { Vector NavPoint = UTIL_ProjectPointToNavmesh(ProjectPoint); UTIL_AdjustPointAwayFromNavWall(NavPoint, 8.0f); - pBot->BotNavInfo.LastNavMeshPosition = NavPoint; - + pBot->BotNavInfo.LastNavMeshPosition = NavPoint; if (pBot->BotNavInfo.IsOnGround || IsPlayerLerk(pBot->Edict)) { @@ -3027,7 +3026,7 @@ void AIPlayerNSMarineThink(AvHAIPlayer* pBot) if (MarineCombatThink(pBot)) { return; } } - if (gpGlobals->time >= pBot->BotNextTaskEvaluationTime) + if (UTIL_IsTileCacheUpToDate() && gpGlobals->time >= pBot->BotNextTaskEvaluationTime) { pBot->BotNextTaskEvaluationTime = gpGlobals->time + frandrange(0.2f, 0.5f); @@ -7734,6 +7733,8 @@ bool SkulkCombatThink(AvHAIPlayer* pBot) float DistToEnemy = vDist2DSq(pBot->Edict->v.origin, TrackedEnemyRef->LastDetectedLocation); + bool bShouldBreakRetreat = false; + if (pBot->CurrentCombatStrategy == COMBAT_STRATEGY_RETREAT) { edict_t* NearestHealingSource = AITAC_AlienFindNearestHealingSource(pBot->Player->GetTeam(), pBot->Edict->v.origin, pBot->Edict, true); @@ -7777,7 +7778,7 @@ bool SkulkCombatThink(AvHAIPlayer* pBot) } - return false; + bShouldBreakRetreat = true; } bool bShouldBreakAmbush = false; @@ -7787,7 +7788,7 @@ bool SkulkCombatThink(AvHAIPlayer* pBot) bShouldBreakAmbush = DistToEnemy < ((TrackedEnemyRef->bHasLOS) ? sqrf(UTIL_MetresToGoldSrcUnits(5.0f)) : sqrf(UTIL_MetresToGoldSrcUnits(3.0f))); } - if (pBot->CurrentCombatStrategy == COMBAT_STRATEGY_ATTACK || (pBot->CurrentCombatStrategy == COMBAT_STRATEGY_AMBUSH && bShouldBreakAmbush)) + if (pBot->CurrentCombatStrategy == COMBAT_STRATEGY_ATTACK || bShouldBreakRetreat || (pBot->CurrentCombatStrategy == COMBAT_STRATEGY_AMBUSH && bShouldBreakAmbush)) { bool bIsCloaked = (UTIL_IsCloakedPlayerInvisible(CurrentEnemy, pBot->Player) || pBot->Player->GetOpacity() < 0.5f); @@ -8551,10 +8552,9 @@ bool FadeCombatThink(AvHAIPlayer* pBot) return true; } - - // If the enemy can see the healing source, then we must go on the attack as we're cornered - bShouldBreakRetreat = true; } + + bShouldBreakRetreat = true; } bool bShouldBreakAmbush = false; @@ -8769,10 +8769,10 @@ bool OnosCombatThink(AvHAIPlayer* pBot) MoveTo(pBot, UTIL_GetEntityGroundLocation(NearestHealingSource), MOVESTYLE_NORMAL, DesiredDistFromHealingSource); return true; } - - // If the enemy can see the healing source, then we must go on the attack - bShouldBreakRetreat = true; } + + // If the enemy can see the healing source, then we must go on the attack + bShouldBreakRetreat = true; } if (pBot->CurrentCombatStrategy == COMBAT_STRATEGY_ATTACK || bShouldBreakRetreat) diff --git a/main/source/mod/AvHAIPlayerUtil.cpp b/main/source/mod/AvHAIPlayerUtil.cpp index 6da57123..1eb7dfe2 100644 --- a/main/source/mod/AvHAIPlayerUtil.cpp +++ b/main/source/mod/AvHAIPlayerUtil.cpp @@ -170,6 +170,11 @@ bool IsPlayerMotionTracked(const edict_t* Player) return (Player->v.iuser4 & MASK_VIS_DETECTED); } +bool IsPlayerSOF(const edict_t* Player) +{ + return (Player->v.iuser4 & MASK_SENSORY_NEARBY); +} + float GetPlayerEnergy(const edict_t* Player) { return (Player->v.fuser3 * 0.001f); diff --git a/main/source/mod/AvHAIPlayerUtil.h b/main/source/mod/AvHAIPlayerUtil.h index 41b0c781..a333bc67 100644 --- a/main/source/mod/AvHAIPlayerUtil.h +++ b/main/source/mod/AvHAIPlayerUtil.h @@ -67,6 +67,8 @@ bool IsPlayerGestating(const edict_t* Player); bool IsPlayerParasited(const edict_t* Player); // Is the player being marked through walls to enemies through being sighted by an ally or affected by motion tracking? bool IsPlayerMotionTracked(const edict_t* Player); +// Is the player being marked through walls by a nearby sensory chamber or scent of fear? +bool IsPlayerSOF(const edict_t* Player); // Is the player currently on a ladder? Always false for Skulks and Lerks as they can't climb ladders bool IsPlayerOnLadder(const edict_t* Player); // Is the player an onos under the effect of charge? diff --git a/main/source/mod/AvHAITactical.cpp b/main/source/mod/AvHAITactical.cpp index 087d2e14..2b585a2f 100644 --- a/main/source/mod/AvHAITactical.cpp +++ b/main/source/mod/AvHAITactical.cpp @@ -5396,6 +5396,8 @@ edict_t* AITAC_AlienFindNearestHealingSource(AvHTeamNumber Team, Vector SearchLo edict_t* Result = nullptr; float MinDist = 0.0f; + AvHTeamNumber EnemyTeam = AIMGR_GetEnemyTeam(Team); + vector AllTeamHives = AITAC_GetAllTeamHives(Team, true); for (auto it = AllTeamHives.begin(); it != AllTeamHives.end(); it++) @@ -5403,6 +5405,8 @@ edict_t* AITAC_AlienFindNearestHealingSource(AvHTeamNumber Team, Vector SearchLo float ThisDist = vDist2DSq((*it)->Location, SearchLocation); // Factor healing radius into the distance checks, we don't have to be right at the hive to heal ThisDist -= BALANCE_VAR(kHiveHealRadius) * 0.75f; + + if (AITAC_AnyPlayerOnTeamHasLOSToLocation(EnemyTeam, (*it)->Location, UTIL_MetresToGoldSrcUnits(30.0f), nullptr)) { continue; } // We're already in healing distance of a hive, that's our healing source if (ThisDist <= 0.0f) { return (*it)->HiveEdict; } @@ -5429,6 +5433,8 @@ edict_t* AITAC_AlienFindNearestHealingSource(AvHTeamNumber Team, Vector SearchLo // Factor healing radius into the distance checks, we don't have to be sat on top of the DC to heal ThisDist -= BALANCE_VAR(kHiveHealRadius) * 0.75f; + if (AITAC_AnyPlayerOnTeamHasLOSToLocation(EnemyTeam, ThisDC.Location, UTIL_MetresToGoldSrcUnits(30.0f), nullptr)) { continue; } + // We're already in healing distance of a DC, that's our healing source if (ThisDist <= 0.0f) { return ThisDC.edict; } @@ -5445,6 +5451,11 @@ edict_t* AITAC_AlienFindNearestHealingSource(AvHTeamNumber Team, Vector SearchLo { float PlayerSearchDist = (!FNullEnt(Result)) ? MinDist : 0.0f; // As before, we only want players closer than our current "winner" FriendlyGorge = AITAC_GetNearestPlayerOfClassInArea(Team, SearchLocation, PlayerSearchDist, false, SearchingPlayer, AVH_USER3_ALIEN_PLAYER2); + + if (!FNullEnt(FriendlyGorge)) + { + if (AITAC_AnyPlayerOnTeamHasLOSToLocation(EnemyTeam, FriendlyGorge->v.origin, UTIL_MetresToGoldSrcUnits(30.0f), nullptr)) { FriendlyGorge = nullptr; } + } } return (!FNullEnt(FriendlyGorge) ? FriendlyGorge : Result); diff --git a/main/source/mod/AvHAITask.cpp b/main/source/mod/AvHAITask.cpp index f8cf85f1..299e16c0 100644 --- a/main/source/mod/AvHAITask.cpp +++ b/main/source/mod/AvHAITask.cpp @@ -2108,7 +2108,7 @@ void BotProgressEvolveTask(AvHAIPlayer* pBot, AvHAIPlayerTask* Task) { if (FNullEnt(Task->TaskTarget)) { - Task->TaskLocation = FindClosestNavigablePointToDestination(BaseNavProfiles[ONOS_BASE_NAV_PROFILE], AITAC_GetTeamStartingLocation(pBot->Player->GetTeam()), UTIL_GetEntityGroundLocation(Task->TaskTarget), UTIL_MetresToGoldSrcUnits(10.0f)); + Task->TaskLocation = FindClosestNavigablePointToDestination(BaseNavProfiles[ONOS_BASE_NAV_PROFILE], AITAC_GetTeamStartingLocation(pBot->Player->GetTeam()), pBot->CurrentFloorPosition, UTIL_MetresToGoldSrcUnits(10.0f)); if (vIsZero(Task->TaskLocation)) { @@ -2126,11 +2126,11 @@ void BotProgressEvolveTask(AvHAIPlayer* pBot, AvHAIPlayerTask* Task) } else { - Task->TaskLocation = FindClosestNavigablePointToDestination(BaseNavProfiles[ONOS_BASE_NAV_PROFILE], pBot->CurrentFloorPosition, UTIL_GetEntityGroundLocation(Task->TaskTarget), UTIL_MetresToGoldSrcUnits(10.0f)); + Task->TaskLocation = FindClosestNavigablePointToDestination(BaseNavProfiles[ONOS_BASE_NAV_PROFILE], AITAC_GetTeamStartingLocation(pBot->Player->GetTeam()), UTIL_GetEntityGroundLocation(Task->TaskTarget), UTIL_MetresToGoldSrcUnits(10.0f)); if (vIsZero(Task->TaskLocation)) { - Task->TaskLocation = UTIL_GetRandomPointOnNavmeshInRadius(BaseNavProfiles[STRUCTURE_BASE_NAV_PROFILE], Task->TaskLocation, UTIL_MetresToGoldSrcUnits(5.0f)); + Task->TaskLocation = UTIL_GetRandomPointOnNavmeshInRadius(BaseNavProfiles[STRUCTURE_BASE_NAV_PROFILE], UTIL_GetEntityGroundLocation(Task->TaskTarget), UTIL_MetresToGoldSrcUnits(10.0f)); } } }