diff --git a/main/source/detour/Include/DetourTileCache.h b/main/source/detour/Include/DetourTileCache.h index f7b42e98..f69dc2fd 100644 --- a/main/source/detour/Include/DetourTileCache.h +++ b/main/source/detour/Include/DetourTileCache.h @@ -95,6 +95,7 @@ struct dtTileCacheParams float walkableHeight; float walkableRadius; float walkableClimb; + float walkableSlope; float maxSimplificationError; int maxTiles; int maxObstacles; diff --git a/main/source/mod/AIPlayers/AvHAIConstants.h b/main/source/mod/AIPlayers/AvHAIConstants.h index a1b5d546..95b85a9f 100644 --- a/main/source/mod/AIPlayers/AvHAIConstants.h +++ b/main/source/mod/AIPlayers/AvHAIConstants.h @@ -289,6 +289,8 @@ typedef struct _BOT_GUARD_INFO Vector GuardLookLocation = g_vecZero; // Which area are we currently watching? float GuardStartLookTime = 0.0f; // When did we start watching the current area? float ThisGuardLookTime = 0.0f; // How long should we watch this area for? + float ThisGuardStandTime = 0.0f; // How long should we watch this area for? + float GuardStartStandTime = 0.0f; // How long should we watch this area for? } AvHAIGuardInfo; diff --git a/main/source/mod/AIPlayers/AvHAIPlayer.cpp b/main/source/mod/AIPlayers/AvHAIPlayer.cpp index 89362f9d..35465e65 100644 --- a/main/source/mod/AIPlayers/AvHAIPlayer.cpp +++ b/main/source/mod/AIPlayers/AvHAIPlayer.cpp @@ -2102,7 +2102,7 @@ void AIPlayerSetMarineAssaultPrimaryTask(AvHAIPlayer* pBot, AvHAIPlayerTask* Tas if (AITAC_PhaseGatesAvailable(pBot->Player->GetTeam())) { - const AvHAIHiveDefinition* ActiveHive = AITAC_GetActiveHiveNearestLocation(pBot->Edict->v.origin); + const AvHAIHiveDefinition* ActiveHive = AITAC_GetActiveHiveNearestLocation(AIMGR_GetEnemyTeam(pBot->Player->GetTeam()), pBot->Edict->v.origin); if (ActiveHive) { @@ -2471,11 +2471,11 @@ void AIPlayerSetAlienBuilderPrimaryTask(AvHAIPlayer* pBot, AvHAIPlayerTask* Task return; } - Vector ActualBuildLocation = UTIL_GetRandomPointOnNavmeshInRadiusIgnoreReachability(GetBaseNavProfile(STRUCTURE_BASE_NAV_PROFILE), BuildOrigin, UTIL_MetresToGoldSrcUnits(3.0f)); + Vector ActualBuildLocation = UTIL_GetRandomPointOnNavmeshInRadius(GetBaseNavProfile(STRUCTURE_BASE_NAV_PROFILE), BuildOrigin, UTIL_MetresToGoldSrcUnits(3.0f)); if (vIsZero(ActualBuildLocation)) { - ActualBuildLocation = UTIL_GetRandomPointOnNavmeshInRadius(GetBaseNavProfile(GORGE_BASE_NAV_PROFILE), BuildOrigin, UTIL_MetresToGoldSrcUnits(3.0f)); + ActualBuildLocation = UTIL_GetRandomPointOnNavmeshInRadiusIgnoreReachability(GetBaseNavProfile(GORGE_BASE_NAV_PROFILE), BuildOrigin, UTIL_MetresToGoldSrcUnits(3.0f)); } AITASK_SetBuildTask(pBot, Task, MissingStructure, ActualBuildLocation, false); @@ -2779,6 +2779,131 @@ void AIPlayerSetAlienAssaultPrimaryTask(AvHAIPlayer* pBot, AvHAIPlayerTask* Task void AIPlayerSetAlienHarasserPrimaryTask(AvHAIPlayer* pBot, AvHAIPlayerTask* Task) { + // If we aren't a lerk, go evolve into one. If we can't, then act like a regular assault alien until we can + if (!IsPlayerLerk(pBot->Edict)) + { + if (pBot->Player->GetResources() >= BALANCE_VAR(kLerkCost)) + { + if (Task->TaskType == TASK_EVOLVE && Task->Evolution == ALIEN_LIFEFORM_THREE) { return; } + + vector AllTeamHives = AITAC_GetAllTeamHives(pBot->Player->GetTeam()); + + AvHAIHiveDefinition* NearestHive = nullptr; + float MinDist = 0.0f; + + for (auto it = AllTeamHives.begin(); it != AllTeamHives.end(); it++) + { + float ThisDist = vDist2DSq(pBot->Edict->v.origin, (*it)->FloorLocation); + + if (!NearestHive || ThisDist < MinDist) + { + NearestHive = (*it); + MinDist = ThisDist; + } + } + + if (NearestHive) + { + AITASK_SetEvolveTask(pBot, Task, NearestHive->HiveEntity->edict(), ALIEN_LIFEFORM_THREE, true); + return; + } + else + { + AITASK_SetEvolveTask(pBot, Task, pBot->Edict->v.origin, ALIEN_LIFEFORM_THREE, true); + return; + } + } + + if (IsPlayerGorge(pBot->Edict)) + { + BotEvolveLifeform(pBot, pBot->Edict->v.origin, ALIEN_LIFEFORM_ONE); + return; + } + + AIPlayerSetAlienAssaultPrimaryTask(pBot, Task); + + return; + } + + AvHTeamNumber BotTeam = pBot->Player->GetTeam(); + AvHTeamNumber EnemyTeam = AIMGR_GetEnemyTeam(BotTeam); + + DeployableSearchFilter EnemyStructureFilter; + EnemyStructureFilter.DeployableTeam = EnemyTeam; + EnemyStructureFilter.ReachabilityTeam = BotTeam; + EnemyStructureFilter.ReachabilityFlags = pBot->BotNavInfo.NavProfile.ReachabilityFlag; + + Vector EnemyBaseLocation = AITAC_GetTeamStartingLocation(EnemyTeam); + + AvHAIBuildableStructure* EnemyStructureToAttack = nullptr; + + bool bEnemyIsMarines = (AIMGR_GetTeamType(EnemyTeam) == AVH_CLASS_TYPE_MARINE); + + if (bEnemyIsMarines) + { + EnemyStructureFilter.DeployableTypes = (STRUCTURE_MARINE_ARMSLAB | STRUCTURE_MARINE_OBSERVATORY | STRUCTURE_MARINE_INFANTRYPORTAL); + EnemyStructureToAttack = AITAC_FindFurthestDeployableFromLocation(EnemyBaseLocation, &EnemyStructureFilter); + } + else + { + EnemyStructureFilter.MaxSearchRadius = UTIL_MetresToGoldSrcUnits(20.0f); + EnemyStructureFilter.DeployableTypes = (STRUCTURE_ALIEN_RESTOWER | STRUCTURE_ALIEN_DEFENCECHAMBER | STRUCTURE_ALIEN_MOVEMENTCHAMBER | STRUCTURE_ALIEN_SENSORYCHAMBER); + EnemyStructureToAttack = AITAC_FindClosestDeployableToLocation(EnemyBaseLocation, &EnemyStructureFilter); + } + + if (EnemyStructureToAttack) + { + AITASK_SetAttackTask(pBot, Task, EnemyStructureToAttack->edict, false); + return; + } + + if (bEnemyIsMarines) + { + edict_t* CommChair = AITAC_GetCommChair(EnemyTeam); + + if (!FNullEnt(CommChair)) + { + AITASK_SetAttackTask(pBot, Task, CommChair, false); + return; + } + } + else + { + const AvHAIHiveDefinition* EnemyHive = AITAC_GetActiveHiveNearestLocation(EnemyTeam, pBot->Edict->v.origin); + + AITASK_SetAttackTask(pBot, Task, EnemyHive->HiveEntity->edict(), false); + return; + } + + vector AllEnemyPlayers = AIMGR_GetAllPlayersOnTeam(EnemyTeam); + edict_t* TargetPlayer = nullptr; + + float MinDist = 0.0f; + + for (auto it = AllEnemyPlayers.begin(); it != AllEnemyPlayers.end(); it++) + { + AvHPlayer* ThisPlayer = (*it); + + if (!ThisPlayer) { continue; } + + edict_t* PlayerEdict = ThisPlayer->edict(); + + if (!IsPlayerActiveInGame(PlayerEdict)) { continue; } + + float ThisDist = vDist2DSq(PlayerEdict->v.origin, pBot->Edict->v.origin); + + if (FNullEnt(TargetPlayer) || ThisDist < MinDist) + { + TargetPlayer = PlayerEdict; + MinDist = ThisDist; + } + } + + if (!FNullEnt(TargetPlayer)) + { + MoveTo(pBot, UTIL_GetFloorUnderEntity(TargetPlayer), MOVESTYLE_NORMAL); + } + } diff --git a/main/source/mod/AIPlayers/AvHAITactical.cpp b/main/source/mod/AIPlayers/AvHAITactical.cpp index 58775952..3e30fca7 100644 --- a/main/source/mod/AIPlayers/AvHAITactical.cpp +++ b/main/source/mod/AIPlayers/AvHAITactical.cpp @@ -18,6 +18,7 @@ #include "../AvHGamerules.h" #include "../AvHServerUtil.h" +#include "../AvHMarineEquipment.h" #include @@ -695,8 +696,28 @@ void AITAC_RefreshHiveData() it->TechStatus = theEntity->GetTechnology(); it->bIsUnderAttack = GetGameRules()->GetIsEntityUnderAttack(theEntity->entindex()); - it->OwningTeam = theEntity->GetTeamNumber(); - it->Status = (theEntity->GetIsActive() ? HIVE_STATUS_BUILT : (theEntity->GetIsSpawning() ? HIVE_STATUS_BUILDING : HIVE_STATUS_UNBUILT)); + + AvHTeamNumber CurrentOwningTeam = theEntity->GetTeamNumber(); + HiveStatusType CurrentStatus = (theEntity->GetIsActive() ? HIVE_STATUS_BUILT : (theEntity->GetIsSpawning() ? HIVE_STATUS_BUILDING : HIVE_STATUS_UNBUILT)); + + bool bHiveDestroyed = (CurrentOwningTeam != it->OwningTeam) || (it->Status == HIVE_STATUS_BUILT && CurrentStatus != it->Status); + + if (bHiveDestroyed) + { + if (it->OwningTeam == GetGameRules()->GetTeamANumber()) + { + TeamAStartingLocation = ZERO_VECTOR; + } + else + { + TeamBStartingLocation = ZERO_VECTOR; + } + + AITAC_GetTeamStartingLocation(it->OwningTeam); // Force refresh + } + + it->OwningTeam = CurrentOwningTeam; + it->Status = CurrentStatus; if (it->Status != HIVE_STATUS_UNBUILT && it->ObstacleRefs[REGULAR_NAV_MESH] == 0) { @@ -718,13 +739,15 @@ void AITAC_RefreshHiveData() NextRefresh++; } - } Vector AITAC_GetTeamStartingLocation(AvHTeamNumber Team) { if (vIsZero(TeamAStartingLocation) || vIsZero(TeamBStartingLocation)) { + AvHTeamNumber TeamANum = GetGameRules()->GetTeamANumber(); + AvHTeamNumber TeamBNum = GetGameRules()->GetTeamBNumber(); + AvHTeam* AvHTeamARef = GetGameRules()->GetTeamA(); AvHTeam* AvHTeamBRef = GetGameRules()->GetTeamB(); @@ -734,13 +757,29 @@ Vector AITAC_GetTeamStartingLocation(AvHTeamNumber Team) if (AvHTeamARef->GetTeamType() == AVH_CLASS_TYPE_MARINE) { - TeamAStartingLocation = TeamStartLocation; + DeployableSearchFilter IFFilter; + IFFilter.DeployableTeam = TeamANum; + IFFilter.DeployableTypes = STRUCTURE_MARINE_INFANTRYPORTAL; + IFFilter.IncludeStatusFlags = STRUCTURE_STATUS_COMPLETED; + IFFilter.ExcludeStatusFlags = STRUCTURE_STATUS_RECYCLING; + + AvHAIBuildableStructure* InfantryPortal = AITAC_FindClosestDeployableToLocation(ZERO_VECTOR, &IFFilter); + + if (InfantryPortal) + { + TeamAStartingLocation = InfantryPortal->Location; + } + else + { + Vector CommChairLocation = AITAC_GetCommChairLocation(TeamANum); + TeamAStartingLocation = (!vIsZero(CommChairLocation)) ? CommChairLocation : TeamStartLocation; + } } else { TeamAStartingLocation = TeamStartLocation; - const AvHAIHiveDefinition* Hive = AITAC_GetHiveNearestLocation(TeamStartLocation); + const AvHAIHiveDefinition* Hive = AITAC_GetActiveHiveNearestLocation(TeamANum, TeamStartLocation); if (Hive) { @@ -759,13 +798,29 @@ Vector AITAC_GetTeamStartingLocation(AvHTeamNumber Team) if (AvHTeamBRef->GetTeamType() == AVH_CLASS_TYPE_MARINE) { - TeamBStartingLocation = TeamStartLocation; + DeployableSearchFilter IFFilter; + IFFilter.DeployableTeam = TeamBNum; + IFFilter.DeployableTypes = STRUCTURE_MARINE_INFANTRYPORTAL; + IFFilter.IncludeStatusFlags = STRUCTURE_STATUS_COMPLETED; + IFFilter.ExcludeStatusFlags = STRUCTURE_STATUS_RECYCLING; + + AvHAIBuildableStructure* InfantryPortal = AITAC_FindClosestDeployableToLocation(ZERO_VECTOR, &IFFilter); + + if (InfantryPortal) + { + TeamAStartingLocation = InfantryPortal->Location; + } + else + { + Vector CommChairLocation = AITAC_GetCommChairLocation(TeamBNum); + TeamAStartingLocation = (!vIsZero(CommChairLocation)) ? CommChairLocation : TeamStartLocation; + } } else { TeamBStartingLocation = TeamStartLocation; - const AvHAIHiveDefinition* Hive = AITAC_GetActiveHiveNearestLocation(TeamStartLocation); + const AvHAIHiveDefinition* Hive = AITAC_GetActiveHiveNearestLocation(TeamBNum, TeamStartLocation); if (Hive) { @@ -777,6 +832,9 @@ Vector AITAC_GetTeamStartingLocation(AvHTeamNumber Team) } } } + + // Update reachabilities since team starting points have been modified + bNavMeshModified = true; } return (Team == GetGameRules()->GetTeamANumber()) ? TeamAStartingLocation : TeamBStartingLocation; @@ -794,18 +852,11 @@ Vector AITAC_GetCommChairLocation(AvHTeamNumber Team) } } - DeployableSearchFilter ChairFilter; - ChairFilter.DeployableTypes = STRUCTURE_MARINE_COMMCHAIR; - ChairFilter.DeployableTeam = Team; - ChairFilter.ReachabilityTeam = TEAM_IND; - ChairFilter.bConsiderPhaseDistance = false; - ChairFilter.IncludeStatusFlags = STRUCTURE_STATUS_COMPLETED; + edict_t* Chair = AITAC_GetCommChair(Team); - AvHAIBuildableStructure* ChairRef = AITAC_FindClosestDeployableToLocation(ZERO_VECTOR, &ChairFilter); - - if (ChairRef) + if (!FNullEnt(Chair)) { - return ChairRef->Location; + return Chair->v.origin; } return ZERO_VECTOR; @@ -1708,10 +1759,15 @@ AvHAIBuildableStructure* AITAC_UpdateBuildableStructure(CBaseEntity* Structure) unsigned int NewFlags = STRUCTURE_STATUS_NONE; + bool bJustCompleted = false; + bool bJustRecycled = false; + bool bJustDestroyed = false; + if (BaseBuildable->GetIsBuilt()) { - if (!(BuildingMap[EntIndex].StructureStatusFlags & STRUCTURE_STATUS_COMPLETED)) { - AITAC_OnStructureCompleted(&BuildingMap[EntIndex]); + if (!(BuildingMap[EntIndex].StructureStatusFlags & STRUCTURE_STATUS_COMPLETED)) + { + bJustCompleted = true; } NewFlags |= STRUCTURE_STATUS_COMPLETED; } @@ -1730,7 +1786,7 @@ AvHAIBuildableStructure* AITAC_UpdateBuildableStructure(CBaseEntity* Structure) { if (!(BuildingMap[EntIndex].StructureStatusFlags & STRUCTURE_STATUS_RECYCLING)) { - AITAC_OnStructureBeginRecycling(&BuildingMap[EntIndex]); + bJustRecycled = true; } NewFlags |= STRUCTURE_STATUS_RECYCLING; } @@ -1757,6 +1813,16 @@ AvHAIBuildableStructure* AITAC_UpdateBuildableStructure(CBaseEntity* Structure) BuildingMap[EntIndex].StructureStatusFlags = NewFlags; BuildingMap[EntIndex].LastSeen = StructureRefreshFrame; + if (bJustCompleted) + { + AITAC_OnStructureCompleted(&BuildingMap[EntIndex]); + } + + if (bJustRecycled) + { + AITAC_OnStructureBeginRecycling(&BuildingMap[EntIndex]); + } + return &BuildingMap[EntIndex]; } @@ -1819,6 +1885,22 @@ void AITAC_OnStructureCompleted(AvHAIBuildableStructure* NewStructure) } } + + if (NewStructure->StructureType == STRUCTURE_MARINE_INFANTRYPORTAL) + { + AvHTeamNumber Team = (AvHTeamNumber)NewStructure->edict->v.team; + + if (Team == GetGameRules()->GetTeamANumber()) + { + TeamAStartingLocation = ZERO_VECTOR; + } + else + { + TeamBStartingLocation = ZERO_VECTOR; + } + + AITAC_GetTeamStartingLocation(Team); // Force refresh of reachabilities and team starting locations + } } void AITAC_RemovePhaseGateConnections(AvHAIBuildableStructure* SourceGate, AvHAIBuildableStructure* TargetGate) @@ -1881,6 +1963,22 @@ void AITAC_OnStructureDestroyed(AvHAIBuildableStructure* DestroyedStructure) AITAC_RemovePhaseGateConnections(OtherPhaseGate, DestroyedStructure); } } + + if (DestroyedStructure->StructureType == STRUCTURE_MARINE_INFANTRYPORTAL) + { + AvHTeamNumber Team = (AvHTeamNumber)DestroyedStructure->edict->v.team; + + if (Team == GetGameRules()->GetTeamANumber()) + { + TeamAStartingLocation = ZERO_VECTOR; + } + else + { + TeamBStartingLocation = ZERO_VECTOR; + } + + AITAC_GetTeamStartingLocation(Team); // Force refresh of reachabilities and team starting locations + } } void AITAC_LinkAlienStructureToPlayer(AvHAIBuildableStructure* NewStructure) @@ -2329,14 +2427,14 @@ const AvHAIHiveDefinition* AITAC_GetHiveNearestLocation(const Vector SearchLocat return Result; } -const AvHAIHiveDefinition* AITAC_GetActiveHiveNearestLocation(const Vector SearchLocation) +const AvHAIHiveDefinition* AITAC_GetActiveHiveNearestLocation(AvHTeamNumber Team, const Vector SearchLocation) { AvHAIHiveDefinition* Result = nullptr; float MinDist = 0.0f; for (auto it = Hives.begin(); it != Hives.end(); it++) { - if (it->Status != HIVE_STATUS_BUILT) { continue; } + if (it->Status != HIVE_STATUS_BUILT || it->OwningTeam != Team) { continue; } float ThisDist = vDist3DSq(SearchLocation, it->Location); @@ -3133,23 +3231,30 @@ edict_t* AITAC_GetCommChair(AvHTeamNumber Team) ChairFilter.DeployableTeam = Team; ChairFilter.ReachabilityTeam = TEAM_IND; - AvHAIBuildableStructure* ChairStructure = AITAC_FindClosestDeployableToLocation(ZERO_VECTOR, &ChairFilter); + vector CommChairs = AITAC_FindAllDeployables(ZERO_VECTOR, &ChairFilter); - if (ChairStructure) + edict_t* MainCommChair = nullptr; + edict_t* BackupChair = nullptr; + + // If the team has more than one comm chair, pick the one in use + for (auto it = CommChairs.begin(); it != CommChairs.end(); it++) { - return ChairStructure->edict; + AvHCommandStation* ChairRef = dynamic_cast((*it)->EntityRef); + + // Idle animation will be 3 if the chair is in use (closed animation). See AvHCommandStation::GetIdleAnimation + if (ChairRef && ChairRef->GetIdleAnimation() == 3) + { + MainCommChair = ChairRef->edict(); + } + else + { + BackupChair = ChairRef->edict(); + } } - ChairFilter.DeployableTeam = TEAM_IND; + if (!FNullEnt(MainCommChair)) { return MainCommChair;} - ChairStructure = AITAC_FindClosestDeployableToLocation(AITAC_GetTeamStartingLocation(Team), &ChairFilter); - - if (ChairStructure) - { - return ChairStructure->edict; - } - - return nullptr; + return BackupChair; } edict_t* AITAC_GetNearestHumanAtLocation(const AvHTeamNumber Team, const Vector Location, const float MaxSearchRadius) @@ -3372,6 +3477,21 @@ const vector AITAC_GetAllHives() return Results; } +const vector AITAC_GetAllTeamHives(AvHTeamNumber Team) +{ + vector Results; + + for (auto it = Hives.begin(); it != Hives.end(); it++) + { + if (it->OwningTeam == Team) + { + Results.push_back(&(*it)); + } + } + + return Results; +} + bool AITAC_AnyPlayerOnTeamWithLOS(AvHTeamNumber Team, const Vector& Location, float SearchRadius) { float distSq = sqrf(SearchRadius); @@ -3521,17 +3641,16 @@ bool AITAC_IsAlienCapperNeeded(AvHAIPlayer* pBot) AvHTeamNumber BotTeam = pBot->Player->GetTeam(); AvHTeamNumber EnemyTeam = AIMGR_GetEnemyTeam(BotTeam); - float ResNodeOwnership = AITAC_GetTeamResNodeOwnership(BotTeam, false); - float EnemyNodeOwnership = AITAC_GetTeamResNodeOwnership(EnemyTeam, false); + float ResNodeOwnership = AITAC_GetTeamResNodeOwnership(BotTeam, true); + + if (ResNodeOwnership > 0.6f) { return false; } int NumTeamPlayers = AIMGR_GetNumPlayersOnTeam(BotTeam); - int MaxCappers = (int)ceilf((float)NumTeamPlayers * 0.5f); + int MaxCappers = (int)ceilf((float)NumTeamPlayers * 0.4f); int NumCurrentCappers = AIMGR_GetNumAIPlayersWithRoleOnTeam(BotTeam, BOT_ROLE_FIND_RESOURCES, pBot); - int DesiredCappers = 0; - - if (ResNodeOwnership > 0.6f) { return false; } + int DesiredCappers = 0; if (ResNodeOwnership < 0.25f) { @@ -3549,7 +3668,7 @@ bool AITAC_IsAlienCapperNeeded(AvHAIPlayer* pBot) // If we're lerk/fade/onos, only go capper if we have lots of resources and can replace them easily, otherwise we can't afford to waste resources going back to gorge if (!IsPlayerSkulk(pBot->Edict) && !IsPlayerGorge(pBot->Edict)) { - if (pBot->Player->GetResources() < 75 || ResNodeOwnership < 0.4f) { return false; } + if (pBot->Player->GetResources() < 75 || ResNodeOwnership >= 0.4f) { return false; } int NumSkulks = AITAC_GetNumPlayersOnTeamOfClass(BotTeam, AVH_USER3_ALIEN_PLAYER1, nullptr); int NumGorges = AITAC_GetNumPlayersOnTeamOfClass(BotTeam, AVH_USER3_ALIEN_PLAYER2, nullptr); diff --git a/main/source/mod/AIPlayers/AvHAITactical.h b/main/source/mod/AIPlayers/AvHAITactical.h index 36b8540f..4fc20b19 100644 --- a/main/source/mod/AIPlayers/AvHAITactical.h +++ b/main/source/mod/AIPlayers/AvHAITactical.h @@ -50,7 +50,7 @@ float AITAC_GetPhaseDistanceBetweenPoints(const Vector StartPoint, const Ve const AvHAIHiveDefinition* AITAC_GetHiveAtIndex(int Index); const AvHAIHiveDefinition* AITAC_GetHiveNearestLocation(const Vector SearchLocation); -const AvHAIHiveDefinition* AITAC_GetActiveHiveNearestLocation(const Vector SearchLocation); +const AvHAIHiveDefinition* AITAC_GetActiveHiveNearestLocation(AvHTeamNumber Team, const Vector SearchLocation); const AvHAIHiveDefinition* AITAC_GetNonEmptyHiveNearestLocation(const Vector SearchLocation); Vector AITAC_GetCommChairLocation(AvHTeamNumber Team); @@ -157,6 +157,7 @@ edict_t* AITAC_GetNearestHiddenPlayerInLocation(AvHTeamNumber Team, const Vector const vector AITAC_GetAllResourceNodes(); const vector AITAC_GetAllHives(); +const vector AITAC_GetAllTeamHives(AvHTeamNumber Team); bool AITAC_AnyPlayerOnTeamWithLOS(AvHTeamNumber Team, const Vector& Location, float SearchRadius); diff --git a/main/source/mod/AIPlayers/AvHAITask.cpp b/main/source/mod/AIPlayers/AvHAITask.cpp index 2f64dec1..46d6cf2b 100644 --- a/main/source/mod/AIPlayers/AvHAITask.cpp +++ b/main/source/mod/AIPlayers/AvHAITask.cpp @@ -1893,10 +1893,15 @@ void AlienProgressBuildTask(AvHAIPlayer* pBot, AvHAIPlayerTask* Task) return; } + if (!vIsZero(Task->TaskLocation)) + { + UTIL_DrawLine(INDEXENT(1), pBot->Edict->v.origin, Task->TaskLocation); + } + // We tried and failed to place the structure if (pBot->ActiveBuildInfo.BuildStatus == BUILD_ATTEMPT_FAILED) { - Task->TaskLocation = UTIL_GetRandomPointOnNavmeshInRadius(BaseNavProfiles[STRUCTURE_BASE_NAV_PROFILE], Task->TaskLocation, UTIL_MetresToGoldSrcUnits(2.0f)); + Task->TaskLocation = UTIL_GetRandomPointOnNavmeshInRadius(BaseNavProfiles[GORGE_BASE_NAV_PROFILE], Task->TaskLocation, UTIL_MetresToGoldSrcUnits(2.0f)); pBot->ActiveBuildInfo.BuildStatus = BUILD_ATTEMPT_NONE; } @@ -1909,6 +1914,29 @@ void AlienProgressBuildTask(AvHAIPlayer* pBot, AvHAIPlayerTask* Task) if (pBot->Player->GetResources() < ResRequired) { + + if (IsPlayerGorge(pBot->Edict)) + { + AvHTeamNumber BotTeam = pBot->Player->GetTeam(); + + DeployableSearchFilter UnfinishedFilter; + UnfinishedFilter.DeployableTeam = BotTeam; + UnfinishedFilter.DeployableTypes = SEARCH_ALL_STRUCTURES; + UnfinishedFilter.ReachabilityTeam = BotTeam; + UnfinishedFilter.ReachabilityFlags = pBot->BotNavInfo.NavProfile.ReachabilityFlag; + UnfinishedFilter.ExcludeStatusFlags = STRUCTURE_STATUS_COMPLETED; + UnfinishedFilter.MaxSearchRadius = UTIL_MetresToGoldSrcUnits(10.0f); + + AvHAIBuildableStructure* UnfinishedStructure = AITAC_FindClosestDeployableToLocation(Task->TaskLocation, &UnfinishedFilter); + + if (UnfinishedStructure) + { + AIPlayerBuildStructure(pBot, UnfinishedStructure->edict); + return; + } + } + + BotGuardLocation(pBot, Task->TaskLocation); return; } @@ -2578,17 +2606,21 @@ void BotGuardLocation(AvHAIPlayer* pBot, const Vector GuardLocation) if (DistFromGuardLocation > sqrf(UTIL_MetresToGoldSrcUnits(5.0f))) { pBot->GuardInfo.GuardLocation = g_vecZero; + pBot->GuardInfo.GuardStartLookTime = 0.0f; + pBot->GuardInfo.ThisGuardLookTime = 0.0f; + pBot->GuardInfo.GuardStartStandTime = 0.0f; + pBot->GuardInfo.ThisGuardStandTime = 0.0f; MoveTo(pBot, GuardLocation, MOVESTYLE_NORMAL); return; } - if (!pBot->GuardInfo.GuardLocation) + if (vIsZero(pBot->GuardInfo.GuardLocation)) { AITASK_GenerateGuardWatchPoints(pBot, GuardLocation); pBot->GuardInfo.GuardLocation = GuardLocation; } - if (gpGlobals->time - pBot->GuardInfo.GuardStartLookTime > pBot->GuardInfo.ThisGuardLookTime) + if (gpGlobals->time > pBot->GuardInfo.ThisGuardLookTime) { if (pBot->GuardInfo.NumGuardPoints > 0) { @@ -2603,36 +2635,28 @@ void BotGuardLocation(AvHAIPlayer* pBot, const Vector GuardLocation) pBot->GuardInfo.GuardLookLocation.z = pBot->CurrentEyePosition.z; } - Vector LookDir = UTIL_GetVectorNormal2D(pBot->GuardInfo.GuardLookLocation - GuardLocation); + pBot->GuardInfo.ThisGuardLookTime = gpGlobals->time + frandrange(2.0f, 5.0f); + } - Vector NewMoveCentre = GuardLocation - (LookDir * UTIL_MetresToGoldSrcUnits(2.0f)); + if (gpGlobals->time > pBot->GuardInfo.ThisGuardStandTime) + { + pBot->GuardInfo.GuardStandPosition = UTIL_GetRandomPointOnNavmeshInRadius(pBot->BotNavInfo.NavProfile, GuardLocation, UTIL_MetresToGoldSrcUnits(4.0f)); - Vector NewMoveLoc = UTIL_GetRandomPointOnNavmeshInRadius(BaseNavProfiles[MARINE_BASE_NAV_PROFILE], NewMoveCentre, UTIL_MetresToGoldSrcUnits(2.0f)); + pBot->GuardInfo.ThisGuardStandTime = gpGlobals->time + frandrange(5.0f, 10.0f); + } - if (NewMoveLoc != g_vecZero) + if (vDist2DSq(pBot->Edict->v.origin, pBot->GuardInfo.GuardStandPosition) > sqrf(32.0f)) + { + if (IsPlayerLerk(pBot->Edict)) { - pBot->GuardInfo.GuardStandPosition = NewMoveLoc; + MoveTo(pBot, pBot->GuardInfo.GuardStandPosition, MOVESTYLE_HIDE); } else { - pBot->GuardInfo.GuardStandPosition = GuardLocation; + MoveTo(pBot, pBot->GuardInfo.GuardStandPosition, MOVESTYLE_NORMAL); } - - pBot->GuardInfo.ThisGuardLookTime = frandrange(2.0f, 5.0f); - pBot->GuardInfo.GuardStartLookTime = gpGlobals->time; } - if (IsPlayerLerk(pBot->Edict)) - { - MoveTo(pBot, pBot->GuardInfo.GuardStandPosition, MOVESTYLE_HIDE); - } - else - { - MoveTo(pBot, pBot->GuardInfo.GuardStandPosition, MOVESTYLE_NORMAL); - } - - - BotLookAt(pBot, pBot->GuardInfo.GuardLookLocation); @@ -2659,15 +2683,15 @@ void AITASK_GenerateGuardWatchPoints(AvHAIPlayer* pBot, const Vector& GuardLocat path.clear(); - for (int i = 0; i < AITAC_GetNumHives(); i++) + vector AllHives = AITAC_GetAllHives(); + + for (auto it = AllHives.begin(); it != AllHives.end(); it++) { - const AvHAIHiveDefinition* Hive = AITAC_GetHiveAtIndex(i); + const AvHAIHiveDefinition* ThisHive = (*it); - if (!Hive) { continue; } + if (UTIL_QuickTrace(pEdict, GuardLocation + Vector(0.0f, 0.0f, 10.0f), ThisHive->Location) || vDist2DSq(GuardLocation, ThisHive->Location) < sqrf(UTIL_MetresToGoldSrcUnits(10.0f))) { continue; } - if (UTIL_QuickTrace(pEdict, GuardLocation + Vector(0.0f, 0.0f, 10.0f), Hive->Location) || vDist2DSq(GuardLocation, Hive->Location) < sqrf(UTIL_MetresToGoldSrcUnits(10.0f))) { continue; } - - dtStatus SearchResult = FindPathClosestToPoint(NavProfile, Hive->FloorLocation, GuardLocation, path, 500.0f); + dtStatus SearchResult = FindPathClosestToPoint(NavProfile, ThisHive->FloorLocation, GuardLocation, path, 500.0f); if (dtStatusSucceed(SearchResult)) { @@ -2680,21 +2704,10 @@ void AITASK_GenerateGuardWatchPoints(AvHAIPlayer* pBot, const Vector& GuardLocat } } - dtStatus SearchResult = FindPathClosestToPoint(NavProfile, AITAC_GetTeamStartingLocation(EnemyTeam), GuardLocation, path, 500.0f); - - if (dtStatusSucceed(SearchResult)) + if (AIMGR_GetEnemyTeamType(pBot->Player->GetTeam()) == AVH_CLASS_TYPE_MARINE) { - Vector FinalApproachDir = UTIL_GetVectorNormal2D(path.back().Location - prev(prev(path.end()))->Location); - Vector ProspectiveNewGuardLoc = GuardLocation - (FinalApproachDir * 300.0f); - ProspectiveNewGuardLoc.z = prev(prev(path.end()))->Location.z; - - pBot->GuardInfo.GuardPoints[pBot->GuardInfo.NumGuardPoints++] = ProspectiveNewGuardLoc; - } - - if (vDist2DSq(GuardLocation, AITAC_GetTeamStartingLocation(pBot->Player->GetTeam())) > sqrf(UTIL_MetresToGoldSrcUnits(15.0f))) - { - dtStatus SearchResult = FindPathClosestToPoint(NavProfile, AITAC_GetTeamStartingLocation(pBot->Player->GetTeam()), GuardLocation, path, 500.0f); + dtStatus SearchResult = FindPathClosestToPoint(NavProfile, AITAC_GetTeamStartingLocation(EnemyTeam), GuardLocation, path, 500.0f); if (dtStatusSucceed(SearchResult)) { @@ -2707,6 +2720,24 @@ void AITASK_GenerateGuardWatchPoints(AvHAIPlayer* pBot, const Vector& GuardLocat } } + if (AIMGR_GetTeamType(pBot->Player->GetTeam()) == AVH_CLASS_TYPE_MARINE) + { + if (vDist2DSq(GuardLocation, AITAC_GetTeamStartingLocation(pBot->Player->GetTeam())) > sqrf(UTIL_MetresToGoldSrcUnits(15.0f))) + { + dtStatus SearchResult = FindPathClosestToPoint(NavProfile, AITAC_GetTeamStartingLocation(pBot->Player->GetTeam()), GuardLocation, path, 500.0f); + + if (dtStatusSucceed(SearchResult)) + { + Vector FinalApproachDir = UTIL_GetVectorNormal2D(path.back().Location - prev(prev(path.end()))->Location); + Vector ProspectiveNewGuardLoc = GuardLocation - (FinalApproachDir * 300.0f); + + ProspectiveNewGuardLoc.z = prev(prev(path.end()))->Location.z; + + pBot->GuardInfo.GuardPoints[pBot->GuardInfo.NumGuardPoints++] = ProspectiveNewGuardLoc; + } + } + } + } bool BotWithBuildTaskExists(AvHTeamNumber Team, AvHAIDeployableStructureType StructureType) diff --git a/main/source/mod/AvHConsoleCommands.cpp b/main/source/mod/AvHConsoleCommands.cpp index 7d7c9f83..28605cac 100644 --- a/main/source/mod/AvHConsoleCommands.cpp +++ b/main/source/mod/AvHConsoleCommands.cpp @@ -1535,54 +1535,10 @@ BOOL AvHGamerules::ClientCommand( CBasePlayer *pPlayer, const char *pcmd ) theSuccess = true; } - else if (FStrEq(pcmd, "getaliencomp")) + else if (FStrEq(pcmd, "showteamstarts")) { - vector AlienPlayers = AIMGR_GetAIPlayersOnTeam(TEAM_TWO); - - int NumBuilders = 0; - int NumCappers = 0; - int NumHarassers = 0; - int NumAssault = 0; - - for (auto it = AlienPlayers.begin(); it != AlienPlayers.end(); it++) - { - AvHAIPlayer* NewCapper = (*it); - - if (NewCapper) - { - switch (NewCapper->BotRole) - { - case BOT_ROLE_BUILDER: - NumBuilders++; - break; - case BOT_ROLE_FIND_RESOURCES: - NumCappers++; - break; - case BOT_ROLE_HARASS: - NumHarassers++; - break; - case BOT_ROLE_ASSAULT: - NumAssault++; - break; - default: - break; - } - } - } - - char buf[32]; - - sprintf(buf, "Builders: %d\n", NumBuilders); - UTIL_SayText(buf, theAvHPlayer); - - sprintf(buf, "Cappers: %d\n", NumCappers); - UTIL_SayText(buf, theAvHPlayer); - - sprintf(buf, "Harassers: %d\n", NumHarassers); - UTIL_SayText(buf, theAvHPlayer); - - sprintf(buf, "Assault: %d\n", NumAssault); - UTIL_SayText(buf, theAvHPlayer); + UTIL_DrawLine(INDEXENT(1), INDEXENT(1)->v.origin, AITAC_GetTeamStartingLocation(TEAM_ONE), 20.0f, 0, 0, 255); + UTIL_DrawLine(INDEXENT(1), INDEXENT(1)->v.origin, AITAC_GetTeamStartingLocation(TEAM_TWO), 20.0f, 255, 255, 0); theSuccess = true; }