diff --git a/main/source/mod/AvHAICommander.cpp b/main/source/mod/AvHAICommander.cpp index dabcf8d4..67d6b10b 100644 --- a/main/source/mod/AvHAICommander.cpp +++ b/main/source/mod/AvHAICommander.cpp @@ -2978,12 +2978,15 @@ bool AICOMM_CheckForNextSupportAction(AvHAIPlayer* pBot) case BUILD_TURRET_FACTORY: RequiredRes = BALANCE_VAR(kTurretFactoryCost); StructureToDeploy = STRUCTURE_MARINE_TURRETFACTORY; + break; case BUILD_TURRET: RequiredRes = BALANCE_VAR(kSentryCost); StructureToDeploy = STRUCTURE_MARINE_TURRET; + break; case BUILD_PHASEGATE: RequiredRes = BALANCE_VAR(kPhaseGateCost); StructureToDeploy = STRUCTURE_MARINE_PHASEGATE; + break; default: break; } diff --git a/main/source/mod/AvHAIConfig.cpp b/main/source/mod/AvHAIConfig.cpp index 5ab6d921..cf39cbd4 100644 --- a/main/source/mod/AvHAIConfig.cpp +++ b/main/source/mod/AvHAIConfig.cpp @@ -16,7 +16,7 @@ std::unordered_map TeamSizeMap; bot_skill BotSkillLevels[4]; -AvHMessageID ChamberSequence[3] = { ALIEN_BUILD_DEFENSE_CHAMBER, ALIEN_BUILD_MOVEMENT_CHAMBER, ALIEN_BUILD_SENSORY_CHAMBER }; +std::vector ChamberSequence; string DefaultBotNames[MAX_PLAYERS] = { "MrRobot", "Wall-E", @@ -173,6 +173,7 @@ void CONFIG_PopulateBotNames() if (BotNames.size() > 2) { auto rng = std::default_random_engine{}; + rng.seed(time(0)); std::shuffle(begin(BotNames), end(BotNames), rng); } @@ -187,6 +188,7 @@ void CONFIG_PopulateBotNames() if (DefaultNames.size() > 2) { auto rng = std::default_random_engine{}; + rng.seed(time(0)); std::shuffle(begin(DefaultNames), end(DefaultNames), rng); } @@ -255,6 +257,15 @@ void CONFIG_ParseConfigFile() BotSkillLevels[3].alien_bot_motion_tracking_skill = 1.0f; BotSkillLevels[3].alien_bot_view_speed = 2.0f; + ChamberSequence.clear(); + ChamberSequence.push_back(ALIEN_BUILD_DEFENSE_CHAMBER); + ChamberSequence.push_back(ALIEN_BUILD_MOVEMENT_CHAMBER); + ChamberSequence.push_back(ALIEN_BUILD_SENSORY_CHAMBER); + + std::srand(time(0)); + auto rng = std::default_random_engine{}; + rng.seed(time(0)); + std::shuffle(std::begin(ChamberSequence), std::end(ChamberSequence), rng); string BotConfigFile = string(getModDirectory()) + "/nsbots.ini"; @@ -503,12 +514,6 @@ void CONFIG_ParseConfigFile() if (!stricmp(keyChar, "ChamberSequence")) { - AvHMessageID HiveOneTech = MESSAGE_NULL; - AvHMessageID HiveTwoTech = MESSAGE_NULL; - AvHMessageID HiveThreeTech = MESSAGE_NULL; - - std::vector AvailableTechs = { ALIEN_BUILD_DEFENSE_CHAMBER, ALIEN_BUILD_MOVEMENT_CHAMBER, ALIEN_BUILD_SENSORY_CHAMBER }; - auto firstTechDelimiter = value.find("/"); if (firstTechDelimiter == std::string::npos) @@ -533,104 +538,64 @@ void CONFIG_ParseConfigFile() const char* SecondTechChar = SecondTech.c_str(); const char* ThirdTechChar = ThirdTech.c_str(); - if (!stricmp(FirstTechChar, "movement")) + if (!stricmp(FirstTechChar, "defense")) { - HiveOneTech = ALIEN_BUILD_MOVEMENT_CHAMBER; - - AvailableTechs.erase(std::remove(AvailableTechs.begin(), AvailableTechs.end(), ALIEN_BUILD_MOVEMENT_CHAMBER), AvailableTechs.end()); - + auto Element = std::find(ChamberSequence.begin(), ChamberSequence.end(), ALIEN_BUILD_DEFENSE_CHAMBER); + int Index = Element - ChamberSequence.begin(); + std::swap(ChamberSequence[0], ChamberSequence[Index]); } - else if (!stricmp(FirstTechChar, "defense")) + else if (!stricmp(FirstTechChar, "movement")) { - HiveOneTech = ALIEN_BUILD_DEFENSE_CHAMBER; - - AvailableTechs.erase(std::remove(AvailableTechs.begin(), AvailableTechs.end(), ALIEN_BUILD_DEFENSE_CHAMBER), AvailableTechs.end()); + auto Element = std::find(ChamberSequence.begin(), ChamberSequence.end(), ALIEN_BUILD_MOVEMENT_CHAMBER); + int Index = Element - ChamberSequence.begin(); + std::swap(ChamberSequence[0], ChamberSequence[Index]); } else if (!stricmp(FirstTechChar, "sensory")) { - HiveOneTech = ALIEN_BUILD_SENSORY_CHAMBER; - - AvailableTechs.erase(std::remove(AvailableTechs.begin(), AvailableTechs.end(), ALIEN_BUILD_SENSORY_CHAMBER), AvailableTechs.end()); + auto Element = std::find(ChamberSequence.begin(), ChamberSequence.end(), ALIEN_BUILD_SENSORY_CHAMBER); + int Index = Element - ChamberSequence.begin(); + std::swap(ChamberSequence[0], ChamberSequence[Index]); } - if (!stricmp(SecondTechChar, "movement")) + + if (!stricmp(SecondTechChar, "defense")) { - if (std::find(AvailableTechs.begin(), AvailableTechs.end(), ALIEN_BUILD_MOVEMENT_CHAMBER) != AvailableTechs.end()) - { - HiveTwoTech = ALIEN_BUILD_MOVEMENT_CHAMBER; - AvailableTechs.erase(std::remove(AvailableTechs.begin(), AvailableTechs.end(), ALIEN_BUILD_MOVEMENT_CHAMBER), AvailableTechs.end()); - } + auto Element = std::find(ChamberSequence.begin(), ChamberSequence.end(), ALIEN_BUILD_DEFENSE_CHAMBER); + int Index = Element - ChamberSequence.begin(); + std::swap(ChamberSequence[1], ChamberSequence[Index]); } - else if (!stricmp(SecondTechChar, "defense")) + else if (!stricmp(SecondTechChar, "movement")) { - if (std::find(AvailableTechs.begin(), AvailableTechs.end(), ALIEN_BUILD_DEFENSE_CHAMBER) != AvailableTechs.end()) - { - HiveTwoTech = ALIEN_BUILD_DEFENSE_CHAMBER; - AvailableTechs.erase(std::remove(AvailableTechs.begin(), AvailableTechs.end(), ALIEN_BUILD_DEFENSE_CHAMBER), AvailableTechs.end()); - } + auto Element = std::find(ChamberSequence.begin(), ChamberSequence.end(), ALIEN_BUILD_MOVEMENT_CHAMBER); + int Index = Element - ChamberSequence.begin(); + std::swap(ChamberSequence[1], ChamberSequence[Index]); } else if (!stricmp(SecondTechChar, "sensory")) { - if (std::find(AvailableTechs.begin(), AvailableTechs.end(), ALIEN_BUILD_SENSORY_CHAMBER) != AvailableTechs.end()) - { - HiveTwoTech = ALIEN_BUILD_SENSORY_CHAMBER; - AvailableTechs.erase(std::remove(AvailableTechs.begin(), AvailableTechs.end(), ALIEN_BUILD_SENSORY_CHAMBER), AvailableTechs.end()); - } + auto Element = std::find(ChamberSequence.begin(), ChamberSequence.end(), ALIEN_BUILD_SENSORY_CHAMBER); + int Index = Element - ChamberSequence.begin(); + std::swap(ChamberSequence[1], ChamberSequence[Index]); } - if (!stricmp(ThirdTechChar, "movement")) + if (!stricmp(ThirdTechChar, "defense")) { - if (std::find(AvailableTechs.begin(), AvailableTechs.end(), ALIEN_BUILD_MOVEMENT_CHAMBER) != AvailableTechs.end()) - { - HiveThreeTech = ALIEN_BUILD_MOVEMENT_CHAMBER; - AvailableTechs.erase(std::remove(AvailableTechs.begin(), AvailableTechs.end(), ALIEN_BUILD_MOVEMENT_CHAMBER), AvailableTechs.end()); - } + auto Element = std::find(ChamberSequence.begin(), ChamberSequence.end(), ALIEN_BUILD_DEFENSE_CHAMBER); + int Index = Element - ChamberSequence.begin(); + std::swap(ChamberSequence[2], ChamberSequence[Index]); } - else if (!stricmp(ThirdTechChar, "defense")) + else if (!stricmp(ThirdTechChar, "movement")) { - if (std::find(AvailableTechs.begin(), AvailableTechs.end(), ALIEN_BUILD_DEFENSE_CHAMBER) != AvailableTechs.end()) - { - HiveThreeTech = ALIEN_BUILD_DEFENSE_CHAMBER; - AvailableTechs.erase(std::remove(AvailableTechs.begin(), AvailableTechs.end(), ALIEN_BUILD_DEFENSE_CHAMBER), AvailableTechs.end()); - } + auto Element = std::find(ChamberSequence.begin(), ChamberSequence.end(), ALIEN_BUILD_MOVEMENT_CHAMBER); + int Index = Element - ChamberSequence.begin(); + std::swap(ChamberSequence[2], ChamberSequence[Index]); } else if (!stricmp(ThirdTechChar, "sensory")) { - if (std::find(AvailableTechs.begin(), AvailableTechs.end(), ALIEN_BUILD_SENSORY_CHAMBER) != AvailableTechs.end()) - { - HiveThreeTech = ALIEN_BUILD_SENSORY_CHAMBER; - AvailableTechs.erase(std::remove(AvailableTechs.begin(), AvailableTechs.end(), ALIEN_BUILD_SENSORY_CHAMBER), AvailableTechs.end()); - } + auto Element = std::find(ChamberSequence.begin(), ChamberSequence.end(), ALIEN_BUILD_SENSORY_CHAMBER); + int Index = Element - ChamberSequence.begin(); + std::swap(ChamberSequence[2], ChamberSequence[Index]); } - if (HiveOneTech == MESSAGE_NULL) - { - int random = rand() % AvailableTechs.size(); - HiveOneTech = AvailableTechs[random]; - - AvailableTechs.erase(std::remove(AvailableTechs.begin(), AvailableTechs.end(), HiveOneTech), AvailableTechs.end()); - } - - if (HiveTwoTech == MESSAGE_NULL) - { - int random = rand() % AvailableTechs.size(); - HiveTwoTech = AvailableTechs[random]; - - AvailableTechs.erase(std::remove(AvailableTechs.begin(), AvailableTechs.end(), HiveTwoTech), AvailableTechs.end()); - } - - if (HiveThreeTech == MESSAGE_NULL) - { - int random = rand() % AvailableTechs.size(); - HiveThreeTech = AvailableTechs[random]; - - AvailableTechs.erase(std::remove(AvailableTechs.begin(), AvailableTechs.end(), HiveTwoTech), AvailableTechs.end()); - } - - ChamberSequence[0] = HiveOneTech; - ChamberSequence[1] = HiveTwoTech; - ChamberSequence[2] = HiveThreeTech; - continue; } } diff --git a/main/source/mod/AvHAIConstants.h b/main/source/mod/AvHAIConstants.h index 26055e27..5eec3bf8 100644 --- a/main/source/mod/AvHAIConstants.h +++ b/main/source/mod/AvHAIConstants.h @@ -322,7 +322,7 @@ typedef struct _BOT_GUARD_INFO { Vector GuardLocation = g_vecZero; // What position are we guarding? Vector GuardStandPosition = g_vecZero; // Where the bot should stand to guard position (moves around a bit) - Vector GuardPoints[8]; // All potential areas to watch that an enemy could approach from + std::vector GuardPoints; // All potential areas to watch that an enemy could approach from int NumGuardPoints = 0; // How many watch areas there are for the current location Vector GuardLookLocation = g_vecZero; // Which area are we currently watching? float GuardStartLookTime = 0.0f; // When did we start watching the current area? diff --git a/main/source/mod/AvHAITactical.cpp b/main/source/mod/AvHAITactical.cpp index 9dc96c3a..7e35c356 100644 --- a/main/source/mod/AvHAITactical.cpp +++ b/main/source/mod/AvHAITactical.cpp @@ -4711,23 +4711,25 @@ bool AITAC_ShouldBotBuildHive(AvHAIPlayer* pBot, AvHAIHiveDefinition** EligibleH // Must be an empty hive DeployableSearchFilter EnemyFortificationsFilter; - EnemyFortificationsFilter.DeployableTeam = EnemyTeam; - EnemyFortificationsFilter.MaxSearchRadius = UTIL_MetresToGoldSrcUnits(10.0f); + EnemyFortificationsFilter.DeployableTeam = EnemyTeam; if (AIMGR_GetTeamType(EnemyTeam) == AVH_CLASS_TYPE_MARINE) { - EnemyFortificationsFilter.DeployableTypes = (STRUCTURE_MARINE_PHASEGATE | STRUCTURE_MARINE_TURRETFACTORY | STRUCTURE_MARINE_ADVTURRETFACTORY); + EnemyFortificationsFilter.MaxSearchRadius = UTIL_MetresToGoldSrcUnits(20.0f); + EnemyFortificationsFilter.DeployableTypes = (STRUCTURE_MARINE_PHASEGATE | STRUCTURE_MARINE_TURRETFACTORY | STRUCTURE_MARINE_ADVTURRETFACTORY | STRUCTURE_MARINE_SIEGETURRET); EnemyFortificationsFilter.ExcludeStatusFlags = STRUCTURE_STATUS_RECYCLING; EnemyFortificationsFilter.IncludeStatusFlags = STRUCTURE_STATUS_COMPLETED; // This is important to prevent exploiting the AI. Those structures have to be built first! } else { + EnemyFortificationsFilter.MaxSearchRadius = UTIL_MetresToGoldSrcUnits(10.0f); EnemyFortificationsFilter.DeployableTypes = (STRUCTURE_ALIEN_OFFENCECHAMBER); } // Enemy have built some stuff, wait until it's clear before building if (AITAC_DeployableExistsAtLocation(ThisHive->FloorLocation, &EnemyFortificationsFilter)) { continue; } + // Should be clear to drop dat hive! float ThisDist = vDist2DSq(pBot->Edict->v.origin, ThisHive->FloorLocation); diff --git a/main/source/mod/AvHAITask.cpp b/main/source/mod/AvHAITask.cpp index 3fbe5c70..0d17f17d 100644 --- a/main/source/mod/AvHAITask.cpp +++ b/main/source/mod/AvHAITask.cpp @@ -1192,7 +1192,7 @@ void BotProgressPickupTask(AvHAIPlayer* pBot, AvHAIPlayerTask* Task) { AvHAIWeapon CurrentPrimaryWeapon = UTIL_GetPlayerPrimaryWeapon(pBot->Player); - if (CurrentPrimaryWeapon != WEAPON_NONE && CurrentPrimaryWeapon != UTIL_GetWeaponTypeFromEdict(Task->TaskTarget)) + if (CurrentPrimaryWeapon != WEAPON_INVALID && CurrentPrimaryWeapon != UTIL_GetWeaponTypeFromEdict(Task->TaskTarget)) { if (GetPlayerCurrentWeapon(pBot->Player) != CurrentPrimaryWeapon) { @@ -2821,9 +2821,9 @@ void BotGuardLocation(AvHAIPlayer* pBot, const Vector GuardLocation) { float DistFromGuardLocation = vDist2DSq(pBot->Edict->v.origin, GuardLocation); - if (DistFromGuardLocation > sqrf(UTIL_MetresToGoldSrcUnits(10.0f))) + if (DistFromGuardLocation > sqrf(UTIL_MetresToGoldSrcUnits(5.0f))) { - memset(&pBot->GuardInfo, 0, sizeof(AvHAIGuardInfo)); + UTIL_ClearGuardInfo(pBot); MoveTo(pBot, GuardLocation, MOVESTYLE_NORMAL, UTIL_MetresToGoldSrcUnits(10.0f)); return; } @@ -2836,15 +2836,38 @@ void BotGuardLocation(AvHAIPlayer* pBot, const Vector GuardLocation) if (gpGlobals->time > pBot->GuardInfo.ThisGuardLookTime) { - if (pBot->GuardInfo.NumGuardPoints > 0) + if (pBot->GuardInfo.GuardPoints.size() > 0) { - int NewGuardLookIndex = irandrange(0, (pBot->GuardInfo.NumGuardPoints - 1)); + if (pBot->GuardInfo.GuardPoints.size() == 1) + { + pBot->GuardInfo.GuardLookLocation = (*pBot->GuardInfo.GuardPoints.begin()); + } + else + { + Vector NewLookPoint = pBot->GuardInfo.GuardLookLocation; + + int HighestScore = 0.0f; + + for (auto it = pBot->GuardInfo.GuardPoints.begin(); it != pBot->GuardInfo.GuardPoints.end(); it++) + { + if (vEquals((*it), pBot->GuardInfo.GuardLookLocation)) { continue; } + + float thisScore = frandrange(0.01f, 1.0f); + + if (thisScore > HighestScore) + { + NewLookPoint = (*it); + HighestScore = thisScore; + } + } + + pBot->GuardInfo.GuardLookLocation = NewLookPoint; + } - pBot->GuardInfo.GuardLookLocation = pBot->GuardInfo.GuardPoints[NewGuardLookIndex]; } else { - pBot->GuardInfo.GuardLookLocation = UTIL_GetRandomPointOnNavmeshInRadius(BaseNavProfiles[SKULK_BASE_NAV_PROFILE], pBot->Edict->v.origin, UTIL_MetresToGoldSrcUnits(5.0f)); + pBot->GuardInfo.GuardLookLocation = UTIL_GetRandomPointOnNavmeshInRadius(BaseNavProfiles[SKULK_BASE_NAV_PROFILE], pBot->Edict->v.origin, UTIL_MetresToGoldSrcUnits(3.0f)); pBot->GuardInfo.GuardLookLocation.z = pBot->CurrentEyePosition.z; } @@ -2854,7 +2877,7 @@ void BotGuardLocation(AvHAIPlayer* pBot, const Vector GuardLocation) if (gpGlobals->time > pBot->GuardInfo.ThisGuardStandTime) { - pBot->GuardInfo.GuardStandPosition = UTIL_GetRandomPointOnNavmeshInRadius(pBot->BotNavInfo.NavProfile, GuardLocation, UTIL_MetresToGoldSrcUnits(5.0f)); + pBot->GuardInfo.GuardStandPosition = UTIL_GetRandomPointOnNavmeshInRadius(pBot->BotNavInfo.NavProfile, GuardLocation, UTIL_MetresToGoldSrcUnits(3.0f)); pBot->GuardInfo.ThisGuardStandTime = gpGlobals->time + frandrange(5.0f, 10.0f); } @@ -2878,7 +2901,14 @@ void BotGuardLocation(AvHAIPlayer* pBot, const Vector GuardLocation) void UTIL_ClearGuardInfo(AvHAIPlayer* pBot) { - memset(&pBot->GuardInfo, 0, sizeof(AvHAIGuardInfo)); + pBot->GuardInfo.GuardLocation = ZERO_VECTOR; + pBot->GuardInfo.GuardLookLocation = ZERO_VECTOR; + pBot->GuardInfo.GuardPoints.clear(); + pBot->GuardInfo.GuardStandPosition = ZERO_VECTOR; + pBot->GuardInfo.GuardStartLookTime = 0.0f; + pBot->GuardInfo.GuardStartStandTime = 0.0f; + pBot->GuardInfo.ThisGuardLookTime = 0.0f; + pBot->GuardInfo.ThisGuardStandTime = 0.0f; } void AITASK_GenerateGuardWatchPoints(AvHAIPlayer* pBot, const Vector& GuardLocation) @@ -2903,51 +2933,107 @@ void AITASK_GenerateGuardWatchPoints(AvHAIPlayer* pBot, const Vector& GuardLocat { const AvHAIHiveDefinition* ThisHive = (*it); + if (UTIL_QuickTrace(pEdict, GuardLocation, ThisHive->Location)) { 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; } - dtStatus SearchResult = FindPathClosestToPoint(NavProfile, ThisHive->FloorLocation, GuardLocation, path, 500.0f); + dtStatus SearchResult = FindPathClosestToPoint(NavProfile, GuardLocation, ThisHive->FloorLocation, path, 500.0f); if (dtStatusSucceed(SearchResult) && path.size() > 0) { - Vector FinalApproachDir = UTIL_GetVectorNormal2D(path.back().Location - prev(prev(path.end()))->Location); - Vector ProspectiveNewGuardLoc = GuardLocation - (FinalApproachDir * 300.0f); + Vector FurthestPoint = UTIL_GetFurthestVisiblePointOnPath(GuardLocation + Vector(0.0f, 0.0f, 64.0f), path, true); + FurthestPoint.z += 64.0f; - ProspectiveNewGuardLoc.z = prev(prev(path.end()))->Location.z; + Vector LookDir = UTIL_GetVectorNormal(FurthestPoint - GuardLocation); - pBot->GuardInfo.GuardPoints[pBot->GuardInfo.NumGuardPoints++] = ProspectiveNewGuardLoc; + bool bShouldAdd = true; + + for (auto it = pBot->GuardInfo.GuardPoints.begin(); it != pBot->GuardInfo.GuardPoints.end(); it++) + { + Vector ThisLookDir = UTIL_GetVectorNormal((*it) - GuardLocation); + + if (UTIL_GetDotProduct(ThisLookDir, LookDir) > 0.8f) + { + bShouldAdd = false; + break; + } + } + + if (bShouldAdd) + { + pBot->GuardInfo.GuardPoints.push_back(FurthestPoint); + } } } if (AIMGR_GetEnemyTeamType(pBot->Player->GetTeam()) == AVH_CLASS_TYPE_MARINE) { - - dtStatus SearchResult = FindPathClosestToPoint(NavProfile, AITAC_GetTeamStartingLocation(EnemyTeam), GuardLocation, path, 500.0f); - - if (dtStatusSucceed(SearchResult) && path.size() > 0) + if (!UTIL_QuickTrace(nullptr, GuardLocation, AITAC_GetTeamStartingLocation(EnemyTeam))) { - Vector FinalApproachDir = UTIL_GetVectorNormal2D(path.back().Location - prev(prev(path.end()))->Location); - Vector ProspectiveNewGuardLoc = GuardLocation - (FinalApproachDir * 300.0f); + dtStatus SearchResult = FindPathClosestToPoint(NavProfile, GuardLocation, AITAC_GetTeamStartingLocation(EnemyTeam), path, 500.0f); - ProspectiveNewGuardLoc.z = prev(prev(path.end()))->Location.z; + if (dtStatusSucceed(SearchResult) && path.size() > 0) + { + Vector FurthestPoint = UTIL_GetFurthestVisiblePointOnPath(GuardLocation + Vector(0.0f, 0.0f, 64.0f), path, true); + FurthestPoint.z += 64.0f; - pBot->GuardInfo.GuardPoints[pBot->GuardInfo.NumGuardPoints++] = ProspectiveNewGuardLoc; + Vector LookDir = UTIL_GetVectorNormal(FurthestPoint - GuardLocation); + + bool bShouldAdd = true; + + for (auto it = pBot->GuardInfo.GuardPoints.begin(); it != pBot->GuardInfo.GuardPoints.end(); it++) + { + Vector ThisLookDir = UTIL_GetVectorNormal((*it) - GuardLocation); + + if (UTIL_GetDotProduct(ThisLookDir, LookDir) > 0.8f) + { + bShouldAdd = false; + break; + } + } + + if (bShouldAdd) + { + pBot->GuardInfo.GuardPoints.push_back(FurthestPoint); + } + } } } if (AIMGR_GetTeamType(pBot->Player->GetTeam()) == AVH_CLASS_TYPE_MARINE) { - if (vDist2DSq(GuardLocation, AITAC_GetTeamStartingLocation(pBot->Player->GetTeam())) > sqrf(UTIL_MetresToGoldSrcUnits(15.0f))) + if (!UTIL_QuickTrace(pEdict, GuardLocation, AITAC_GetTeamStartingLocation(pBot->Player->GetTeam()))) { - dtStatus SearchResult = FindPathClosestToPoint(NavProfile, AITAC_GetTeamStartingLocation(pBot->Player->GetTeam()), GuardLocation, path, 500.0f); - if (dtStatusSucceed(SearchResult) && path.size() > 0) + if (vDist2DSq(GuardLocation, AITAC_GetTeamStartingLocation(pBot->Player->GetTeam())) > sqrf(UTIL_MetresToGoldSrcUnits(15.0f))) { - Vector FinalApproachDir = UTIL_GetVectorNormal2D(path.back().Location - prev(prev(path.end()))->Location); - Vector ProspectiveNewGuardLoc = GuardLocation - (FinalApproachDir * 300.0f); + dtStatus SearchResult = FindPathClosestToPoint(NavProfile, GuardLocation, AITAC_GetTeamStartingLocation(pBot->Player->GetTeam()), path, 500.0f); - ProspectiveNewGuardLoc.z = prev(prev(path.end()))->Location.z; + if (dtStatusSucceed(SearchResult) && path.size() > 0) + { + Vector FurthestPoint = UTIL_GetFurthestVisiblePointOnPath(GuardLocation + Vector(0.0f, 0.0f, 64.0f), path, true); + FurthestPoint.z += 64.0f; - pBot->GuardInfo.GuardPoints[pBot->GuardInfo.NumGuardPoints++] = ProspectiveNewGuardLoc; + Vector LookDir = UTIL_GetVectorNormal(FurthestPoint - GuardLocation); + + bool bShouldAdd = true; + + for (auto it = pBot->GuardInfo.GuardPoints.begin(); it != pBot->GuardInfo.GuardPoints.end(); it++) + { + Vector ThisLookDir = UTIL_GetVectorNormal((*it) - GuardLocation); + + if (UTIL_GetDotProduct(ThisLookDir, LookDir) > 0.8f) + { + bShouldAdd = false; + break; + } + } + + if (bShouldAdd) + { + pBot->GuardInfo.GuardPoints.push_back(FurthestPoint); + } + } } } } diff --git a/main/source/mod/AvHAITask.h b/main/source/mod/AvHAITask.h index afb8297b..674bd49a 100644 --- a/main/source/mod/AvHAITask.h +++ b/main/source/mod/AvHAITask.h @@ -118,4 +118,5 @@ void BotAlienHealTarget(AvHAIPlayer* pBot, edict_t* HealTarget); void RegisterBotAlienBuildAttempt(AvHAIPlayer* pBot, AvHAIPlayerTask* Task, Vector PlacementLocation, AvHAIDeployableStructureType DesiredStructure); + #endif \ No newline at end of file