General improvements

* AI Commander will now attempt to place turret factories close to any existing turrets to prevent inactive turrets being left behind
* Aliens will not try to pursue enemies who have teleported away (unless they teleported close by)
* Fixed a bug where bots would not target the nearest sentry/OC to engage
* Improved how marines attack OCs, particularly how they take cover to reload
This commit is contained in:
RGreenlees 2024-06-28 12:06:36 +01:00 committed by pierow
parent a01d8a6708
commit 290ad067eb
7 changed files with 241 additions and 23 deletions

View file

@ -4215,7 +4215,7 @@ void AICOMM_DeployBases(AvHAIPlayer* pBot)
{ {
// Make sure that our siege guy is somewhere we can build // Make sure that our siege guy is somewhere we can build
Vector ProjectedPoint = UTIL_ProjectPointToNavmesh(ThisPlayer->pev->origin, Vector(100.0f, 100.0f, 100.0f), GetBaseNavProfile(STRUCTURE_BASE_NAV_PROFILE)); Vector ProjectedPoint = UTIL_ProjectPointToNavmesh(ThisPlayer->pev->origin, Vector(100.0f, 100.0f, 100.0f), GetBaseNavProfile(STRUCTURE_BASE_NAV_PROFILE));
if (!vIsZero(ProjectedPoint)) if (!vIsZero(ProjectedPoint) && vDist2DSq(ProjectedPoint, ThisHive->Location) < sqrf(BALANCE_VAR(kSiegeTurretRange)))
{ {
AICOMM_AddNewBase(pBot, ProjectedPoint, MARINE_BASE_SIEGE); AICOMM_AddNewBase(pBot, ProjectedPoint, MARINE_BASE_SIEGE);
} }
@ -4982,6 +4982,8 @@ bool AICOMM_BuildOutMainBase(AvHAIPlayer* pBot, AvHAIMarineBase* BaseToBuildOut)
int NumTurrets = 0; int NumTurrets = 0;
int NumIncomplete = 0; int NumIncomplete = 0;
vector<Vector> TurretLocations;
int DesiredInfPortals = (int)ceilf((float)AIMGR_GetNumPlayersOnTeam(BotTeam) / 4.0f); int DesiredInfPortals = (int)ceilf((float)AIMGR_GetNumPlayersOnTeam(BotTeam) / 4.0f);
for (auto it = BaseToBuildOut->PlacedStructures.begin(); it != BaseToBuildOut->PlacedStructures.end(); it++) for (auto it = BaseToBuildOut->PlacedStructures.begin(); it != BaseToBuildOut->PlacedStructures.end(); it++)
@ -5056,6 +5058,7 @@ bool AICOMM_BuildOutMainBase(AvHAIPlayer* pBot, AvHAIMarineBase* BaseToBuildOut)
break; break;
case STRUCTURE_MARINE_TURRET: case STRUCTURE_MARINE_TURRET:
NumTurrets++; NumTurrets++;
TurretLocations.push_back(StructureRef.Location);
break; break;
default: default:
break; break;
@ -5209,6 +5212,30 @@ bool AICOMM_BuildOutMainBase(AvHAIPlayer* pBot, AvHAIMarineBase* BaseToBuildOut)
if (bSuccess) { return true; } if (bSuccess) { return true; }
} }
if (NumTurrets > 0)
{
Vector Centroid = ZERO_VECTOR;
for (auto tLocs = TurretLocations.begin(); tLocs != TurretLocations.end(); tLocs++)
{
Centroid = Centroid + *tLocs;
}
Centroid = Centroid / TurretLocations.size();
if (!vIsZero(Centroid))
{
Vector CentroidBuildLocation = UTIL_ProjectPointToNavmesh(Centroid, GetBaseNavProfile(STRUCTURE_BASE_NAV_PROFILE));
if (!vIsZero(CentroidBuildLocation))
{
bool bSuccess = AICOMM_AddStructureToBase(pBot, STRUCTURE_MARINE_TURRETFACTORY, CentroidBuildLocation, BaseToBuildOut);
if (bSuccess) { return true; }
}
}
}
int NumAttempts = 0; int NumAttempts = 0;
while (NumAttempts < 5) while (NumAttempts < 5)
@ -5475,6 +5502,8 @@ bool AICOMM_BuildOutOutpost(AvHAIPlayer* pBot, AvHAIMarineBase* BaseToBuildOut)
int NumTurrets = 0; int NumTurrets = 0;
int NumIncomplete = 0; int NumIncomplete = 0;
vector<Vector> TurretLocations;
for (auto it = BaseToBuildOut->PlacedStructures.begin(); it != BaseToBuildOut->PlacedStructures.end(); it++) for (auto it = BaseToBuildOut->PlacedStructures.begin(); it != BaseToBuildOut->PlacedStructures.end(); it++)
{ {
AvHAIBuildableStructure StructureRef = AITAC_GetDeployableStructureByEntIndex(BaseToBuildOut->BaseTeam, *it); AvHAIBuildableStructure StructureRef = AITAC_GetDeployableStructureByEntIndex(BaseToBuildOut->BaseTeam, *it);
@ -5499,6 +5528,7 @@ bool AICOMM_BuildOutOutpost(AvHAIPlayer* pBot, AvHAIMarineBase* BaseToBuildOut)
break; break;
case STRUCTURE_MARINE_TURRET: case STRUCTURE_MARINE_TURRET:
NumTurrets++; NumTurrets++;
TurretLocations.push_back(StructureRef.Location);
break; break;
default: default:
break; break;
@ -5584,6 +5614,33 @@ bool AICOMM_BuildOutOutpost(AvHAIPlayer* pBot, AvHAIMarineBase* BaseToBuildOut)
if (bSuccess) { return true; } if (bSuccess) { return true; }
} }
if (StructureToDeploy == STRUCTURE_MARINE_TURRETFACTORY)
{
if (NumTurrets > 0)
{
Vector Centroid = ZERO_VECTOR;
for (auto tLocs = TurretLocations.begin(); tLocs != TurretLocations.end(); tLocs++)
{
Centroid = Centroid + *tLocs;
}
Centroid = Centroid / TurretLocations.size();
if (!vIsZero(Centroid))
{
Vector CentroidBuildLocation = UTIL_ProjectPointToNavmesh(Centroid, GetBaseNavProfile(STRUCTURE_BASE_NAV_PROFILE));
if (!vIsZero(CentroidBuildLocation))
{
bool bSuccess = AICOMM_AddStructureToBase(pBot, StructureToDeploy, CentroidBuildLocation, BaseToBuildOut);
if (bSuccess) { return true; }
}
}
}
}
int NumAttempts = 0; int NumAttempts = 0;
while (NumAttempts < 5) while (NumAttempts < 5)
@ -5624,6 +5681,8 @@ bool AICOMM_BuildOutSiege(AvHAIPlayer* pBot, AvHAIMarineBase* BaseToBuildOut)
int NumTurrets = 0; int NumTurrets = 0;
int NumIncomplete = 0; int NumIncomplete = 0;
vector<Vector> TurretLocations;
for (auto it = BaseToBuildOut->PlacedStructures.begin(); it != BaseToBuildOut->PlacedStructures.end(); it++) for (auto it = BaseToBuildOut->PlacedStructures.begin(); it != BaseToBuildOut->PlacedStructures.end(); it++)
{ {
AvHAIBuildableStructure StructureRef = AITAC_GetDeployableStructureByEntIndex(BaseToBuildOut->BaseTeam, *it); AvHAIBuildableStructure StructureRef = AITAC_GetDeployableStructureByEntIndex(BaseToBuildOut->BaseTeam, *it);
@ -5651,6 +5710,7 @@ bool AICOMM_BuildOutSiege(AvHAIPlayer* pBot, AvHAIMarineBase* BaseToBuildOut)
break; break;
case STRUCTURE_MARINE_SIEGETURRET: case STRUCTURE_MARINE_SIEGETURRET:
NumTurrets++; NumTurrets++;
TurretLocations.push_back(StructureRef.Location);
break; break;
default: default:
break; break;
@ -5710,6 +5770,30 @@ bool AICOMM_BuildOutSiege(AvHAIPlayer* pBot, AvHAIMarineBase* BaseToBuildOut)
int NumAttempts = 0; int NumAttempts = 0;
if (NumTurrets > 0)
{
Vector Centroid = ZERO_VECTOR;
for (auto tLocs = TurretLocations.begin(); tLocs != TurretLocations.end(); tLocs++)
{
Centroid = Centroid + *tLocs;
}
Centroid = Centroid / TurretLocations.size();
if (!vIsZero(Centroid))
{
Vector BuildLocation = UTIL_ProjectPointToNavmesh(Centroid, GetBaseNavProfile(STRUCTURE_BASE_NAV_PROFILE));
if (!vIsZero(BuildLocation))
{
bool bSuccess = AICOMM_AddStructureToBase(pBot, StructureToDeploy, BuildLocation, BaseToBuildOut);
if (bSuccess) { return true; }
}
}
}
while (NumAttempts < 5) while (NumAttempts < 5)
{ {
Vector BuildLocation = UTIL_GetRandomPointOnNavmeshInRadiusIgnoreReachability(GetBaseNavProfile(STRUCTURE_BASE_NAV_PROFILE), BaseToBuildOut->BaseLocation, UTIL_MetresToGoldSrcUnits(2.0f + NumAttempts)); Vector BuildLocation = UTIL_GetRandomPointOnNavmeshInRadiusIgnoreReachability(GetBaseNavProfile(STRUCTURE_BASE_NAV_PROFILE), BaseToBuildOut->BaseLocation, UTIL_MetresToGoldSrcUnits(2.0f + NumAttempts));
@ -5820,6 +5904,8 @@ bool AICOMM_BuildOutGuardPost(AvHAIPlayer* pBot, AvHAIMarineBase* BaseToBuildOut
int NumTurrets = 0; int NumTurrets = 0;
int NumIncomplete = 0; int NumIncomplete = 0;
vector<Vector> TurretLocations;
for (auto it = BaseToBuildOut->PlacedStructures.begin(); it != BaseToBuildOut->PlacedStructures.end(); it++) for (auto it = BaseToBuildOut->PlacedStructures.begin(); it != BaseToBuildOut->PlacedStructures.end(); it++)
{ {
AvHAIBuildableStructure StructureRef = AITAC_GetDeployableStructureByEntIndex(BaseToBuildOut->BaseTeam, *it); AvHAIBuildableStructure StructureRef = AITAC_GetDeployableStructureByEntIndex(BaseToBuildOut->BaseTeam, *it);
@ -5839,6 +5925,7 @@ bool AICOMM_BuildOutGuardPost(AvHAIPlayer* pBot, AvHAIMarineBase* BaseToBuildOut
else if (StructureRef.StructureType == STRUCTURE_MARINE_TURRET) else if (StructureRef.StructureType == STRUCTURE_MARINE_TURRET)
{ {
NumTurrets++; NumTurrets++;
TurretLocations.push_back(StructureRef.Location);
} }
else if (StructureRef.StructureType == STRUCTURE_MARINE_OBSERVATORY) else if (StructureRef.StructureType == STRUCTURE_MARINE_OBSERVATORY)
{ {
@ -5919,6 +6006,33 @@ bool AICOMM_BuildOutGuardPost(AvHAIPlayer* pBot, AvHAIMarineBase* BaseToBuildOut
if (bSuccess) { return true; } if (bSuccess) { return true; }
} }
if (StructureToDeploy == STRUCTURE_MARINE_TURRETFACTORY)
{
if (NumTurrets > 0)
{
Vector Centroid = ZERO_VECTOR;
for (auto tLocs = TurretLocations.begin(); tLocs != TurretLocations.end(); tLocs++)
{
Centroid = Centroid + *tLocs;
}
Centroid = Centroid / TurretLocations.size();
if (!vIsZero(Centroid))
{
Vector CentroidBuildLocation = UTIL_ProjectPointToNavmesh(Centroid, GetBaseNavProfile(STRUCTURE_BASE_NAV_PROFILE));
if (!vIsZero(CentroidBuildLocation))
{
bool bSuccess = AICOMM_AddStructureToBase(pBot, StructureToDeploy, CentroidBuildLocation, BaseToBuildOut);
if (bSuccess) { return true; }
}
}
}
}
int NumAttempts = 0; int NumAttempts = 0;
while (NumAttempts < 5) while (NumAttempts < 5)
@ -5953,7 +6067,7 @@ AvHAIMarineBase* AICOMM_AddNewBase(AvHAIPlayer* pBot, Vector NewBaseLocation, Ma
bool AICOMM_AddStructureToBase(AvHAIPlayer* pBot, AvHAIDeployableStructureType StructureToDeploy, Vector BuildLocation, AvHAIMarineBase* BaseToAdd) bool AICOMM_AddStructureToBase(AvHAIPlayer* pBot, AvHAIDeployableStructureType StructureToDeploy, Vector BuildLocation, AvHAIMarineBase* BaseToAdd)
{ {
if (vIsZero(BuildLocation)) { return false; } if (!BaseToAdd || vIsZero(BuildLocation)) { return false; }
AvHAIBuildableStructure* DeployedStructure = AICOMM_DeployStructure(pBot, StructureToDeploy, BuildLocation); AvHAIBuildableStructure* DeployedStructure = AICOMM_DeployStructure(pBot, StructureToDeploy, BuildLocation);
@ -5961,6 +6075,18 @@ bool AICOMM_AddStructureToBase(AvHAIPlayer* pBot, AvHAIDeployableStructureType S
{ {
BaseToAdd->PlacedStructures.push_back(DeployedStructure->EntIndex); BaseToAdd->PlacedStructures.push_back(DeployedStructure->EntIndex);
BaseToAdd->bBaseInitialised = true; BaseToAdd->bBaseInitialised = true;
if (BaseToAdd->BaseType == MARINE_BASE_MAINBASE)
{
DeployedStructure->Purpose = STRUCTURE_PURPOSE_BASE;
}
else if (BaseToAdd->BaseType == MARINE_BASE_SIEGE)
{
DeployedStructure->Purpose = STRUCTURE_PURPOSE_SIEGE;
}
else
{
DeployedStructure->Purpose = STRUCTURE_PURPOSE_FORTIFY;
}
return true; return true;
} }

View file

@ -768,6 +768,8 @@ typedef struct AVH_AI_PLAYER
float LastRequestTime = 0.0f; // When bot last used a voice line to request something. Prevents spam float LastRequestTime = 0.0f; // When bot last used a voice line to request something. Prevents spam
float LastTeleportTime = 0.0f; // Last time the bot teleported somewhere
Vector DesiredLookDirection = g_vecZero; // What view angle is the bot currently turning towards Vector DesiredLookDirection = g_vecZero; // What view angle is the bot currently turning towards
Vector InterpolatedLookDirection = g_vecZero; // Used to smoothly interpolate the bot's view rather than snap instantly like an aimbot Vector InterpolatedLookDirection = g_vecZero; // Used to smoothly interpolate the bot's view rather than snap instantly like an aimbot
edict_t* LookTarget = nullptr; // Used to work out what view angle is needed to look at the desired entity edict_t* LookTarget = nullptr; // Used to work out what view angle is needed to look at the desired entity

View file

@ -3772,7 +3772,16 @@ void BlockedMove(AvHAIPlayer* pBot, const Vector StartPoint, const Vector EndPoi
if (vIsZero(vForward)) if (vIsZero(vForward))
{ {
vForward = UTIL_GetForwardVector2D(pBot->Edict->v.angles); if (pBot->BotNavInfo.CurrentPathPoint < pBot->BotNavInfo.CurrentPath.size() - 1)
{
bot_path_node NextPathNode = pBot->BotNavInfo.CurrentPath[pBot->BotNavInfo.CurrentPathPoint + 1];
vForward = UTIL_GetVectorNormal2D(NextPathNode.Location - pBot->Edict->v.origin);
}
else
{
vForward = UTIL_GetForwardVector2D(pBot->Edict->v.angles);
}
} }
} }
@ -6831,6 +6840,7 @@ bool MoveTo(AvHAIPlayer* pBot, const Vector Destination, const BotMoveStyle Move
if (!bSucceeded) if (!bSucceeded)
{ {
const char* botName = STRING(pBot->Edict->v.netname);
pBot->BotNavInfo.StuckInfo.bPathFollowFailed = true; pBot->BotNavInfo.StuckInfo.bPathFollowFailed = true;
if (!UTIL_PointIsOnNavmesh(pBot->CollisionHullBottomLocation, pBot->BotNavInfo.NavProfile)) if (!UTIL_PointIsOnNavmesh(pBot->CollisionHullBottomLocation, pBot->BotNavInfo.NavProfile))
@ -6839,7 +6849,7 @@ bool MoveTo(AvHAIPlayer* pBot, const Vector Destination, const BotMoveStyle Move
{ {
MoveDirectlyTo(pBot, BotNavInfo->LastNavMeshPosition); MoveDirectlyTo(pBot, BotNavInfo->LastNavMeshPosition);
if (vDist2DSq(pBot->CurrentFloorPosition, BotNavInfo->LastNavMeshPosition) < sqrf(8.0f)) if (vDist2DSq(pBot->CurrentFloorPosition, BotNavInfo->LastNavMeshPosition) < 1.0f)
{ {
BotNavInfo->LastNavMeshPosition = g_vecZero; BotNavInfo->LastNavMeshPosition = g_vecZero;
} }
@ -6848,7 +6858,7 @@ bool MoveTo(AvHAIPlayer* pBot, const Vector Destination, const BotMoveStyle Move
} }
else else
{ {
if (!vIsZero(BotNavInfo->UnstuckMoveLocation) && vDist2DSq(pBot->CurrentFloorPosition, BotNavInfo->UnstuckMoveLocation) < sqrf(8.0f)) if (!vIsZero(BotNavInfo->UnstuckMoveLocation) && vDist2DSq(pBot->CurrentFloorPosition, BotNavInfo->UnstuckMoveLocation) < 1.0f)
{ {
BotNavInfo->UnstuckMoveLocation = ZERO_VECTOR; BotNavInfo->UnstuckMoveLocation = ZERO_VECTOR;
} }
@ -6867,7 +6877,27 @@ bool MoveTo(AvHAIPlayer* pBot, const Vector Destination, const BotMoveStyle Move
} }
else else
{ {
MoveDirectlyTo(pBot, Destination); if (!vIsZero(BotNavInfo->UnstuckMoveLocation) && vDist2DSq(pBot->CurrentFloorPosition, BotNavInfo->UnstuckMoveLocation) < 1.0f)
{
BotNavInfo->UnstuckMoveLocation = ZERO_VECTOR;
}
if (vIsZero(BotNavInfo->UnstuckMoveLocation))
{
BotNavInfo->UnstuckMoveLocation = FindClosestPointBackOnPath(pBot, Destination);
}
if (!vIsZero(BotNavInfo->UnstuckMoveLocation))
{
MoveDirectlyTo(pBot, BotNavInfo->UnstuckMoveLocation);
return false;
}
else
{
MoveDirectlyTo(pBot, Destination);
}
return false; return false;
} }

View file

@ -1433,6 +1433,20 @@ void BotUpdateView(AvHAIPlayer* pBot)
} }
} }
// Detect if a player has teleported away. Basically, if the player has moved significantly far away from where they were last detected in a very short space of time
// then they've teleported and we should clear their tracking info. This should work for phase gates, but also any trigger_teleport in the map (e.g. co_daimos phase gates)
if (!vIsZero(TrackingInfo->LastDetectedLocation) && gpGlobals->time - TrackingInfo->LastDetectedTime < 1.0f)
{
if (vDist2DSq(PlayerEdict->v.origin, TrackingInfo->LastDetectedLocation) > sqrf(UTIL_MetresToGoldSrcUnits(5.0f)))
{
if (!UTIL_PlayerHasLOSToEntity(pBot->Edict, PlayerEdict, UTIL_MetresToGoldSrcUnits(20.0f), false))
{
BotClearEnemyTrackingInfo(TrackingInfo);
continue;
}
}
}
Vector VisiblePoint = GetVisiblePointOnPlayerFromObserver(pBot->Edict, PlayerEdict); Vector VisiblePoint = GetVisiblePointOnPlayerFromObserver(pBot->Edict, PlayerEdict);
TrackingInfo->VisiblePointOnPlayer = VisiblePoint; TrackingInfo->VisiblePointOnPlayer = VisiblePoint;
@ -1518,7 +1532,7 @@ void BotUpdateView(AvHAIPlayer* pBot)
AvHAIBuildableStructure ThisTurret = (*it); AvHAIBuildableStructure ThisTurret = (*it);
AvHTurret* TurretRef = dynamic_cast<AvHTurret*>(ThisTurret.EntityRef); AvHTurret* TurretRef = dynamic_cast<AvHTurret*>(ThisTurret.EntityRef);
if (TurretRef && TurretRef->GetIsValidTarget(pBot->Player)) if (TurretRef && TurretRef->GetIsValidTarget(pBot->Player) && !vIsZero(GetVisiblePointOnPlayerFromObserver(ThisTurret.edict, pBot->Edict)))
{ {
bIsInRangeOfEnemyTurret = true; bIsInRangeOfEnemyTurret = true;
pBot->DangerTurrets.push_back(ThisTurret); pBot->DangerTurrets.push_back(ThisTurret);
@ -1723,11 +1737,17 @@ void StartNewBotFrame(AvHAIPlayer* pBot)
pBot->CurrentFloorPosition = NewFloorPosition; pBot->CurrentFloorPosition = NewFloorPosition;
if (vDist3DSq(pBot->BotNavInfo.LastNavMeshCheckPosition, pBot->CurrentFloorPosition) > sqrf(16.0f)) Vector ProjectPoint = (IsPlayerLerk(pBot->Edict)) ? pBot->CurrentFloorPosition : pBot->CollisionHullBottomLocation;
if (vDist3DSq(pBot->BotNavInfo.LastNavMeshCheckPosition, ProjectPoint) > sqrf(16.0f))
{ {
if (UTIL_PointIsReachable(pBot->BotNavInfo.NavProfile, AITAC_GetTeamStartingLocation(pBot->Player->GetTeam()), pBot->CurrentFloorPosition, 16.0f)) if (UTIL_PointIsReachable(pBot->BotNavInfo.NavProfile, AITAC_GetTeamStartingLocation(pBot->Player->GetTeam()), ProjectPoint, 16.0f))
{ {
pBot->BotNavInfo.LastNavMeshPosition = pBot->CurrentFloorPosition; Vector NavPoint = UTIL_ProjectPointToNavmesh(ProjectPoint);
UTIL_AdjustPointAwayFromNavWall(NavPoint, 8.0f);
pBot->BotNavInfo.LastNavMeshPosition = NavPoint;
if (pBot->BotNavInfo.IsOnGround || IsPlayerLerk(pBot->Edict)) if (pBot->BotNavInfo.IsOnGround || IsPlayerLerk(pBot->Edict))
{ {
@ -1894,7 +1914,24 @@ void EndBotFrame(AvHAIPlayer* pBot)
void CustomThink(AvHAIPlayer* pBot) void CustomThink(AvHAIPlayer* pBot)
{ {
MoveTo(pBot, UTIL_GetFloorUnderEntity(INDEXENT(1)), MOVESTYLE_NORMAL); pBot->CurrentTask = &pBot->PrimaryBotTask;
AITASK_BotUpdateAndClearTasks(pBot);
if (pBot->CurrentTask->TaskType != TASK_ATTACK)
{
DeployableSearchFilter EnemyOCFilter;
EnemyOCFilter.DeployableTypes = STRUCTURE_ALIEN_OFFENCECHAMBER;
AvHAIBuildableStructure NearestOC = AITAC_FindClosestDeployableToLocation(pBot->Edict->v.origin, &EnemyOCFilter);
if (NearestOC.IsValid())
{
AITASK_SetAttackTask(pBot, pBot->CurrentTask, NearestOC.edict, false);
}
}
BotProgressTask(pBot, pBot->CurrentTask);
} }
@ -4305,6 +4342,7 @@ void AIPlayerSetSecondaryMarineTask(AvHAIPlayer* pBot, AvHAIPlayerTask* Task)
if (FNullEnt(NearestDangerTurret.edict) || ThisDist < MinDist) if (FNullEnt(NearestDangerTurret.edict) || ThisDist < MinDist)
{ {
NearestDangerTurret = (*it); NearestDangerTurret = (*it);
MinDist = ThisDist;
} }
} }
@ -4615,6 +4653,9 @@ void AIPlayerNSAlienThink(AvHAIPlayer* pBot)
if (AlienCombatThink(pBot)) { return; } if (AlienCombatThink(pBot)) { return; }
} }
// We've JUST tried placing a structure. Wait until we get confirmation of the structure being placed before doing anything else
if (pBot->CurrentTask && pBot->CurrentTask->ActiveBuildInfo.BuildStatus == BUILD_ATTEMPT_PENDING) { return; }
bool bPlayerMustFinishPrimaryTask = AIPlayerMustFinishCurrentTask(pBot, &pBot->PrimaryBotTask); bool bPlayerMustFinishPrimaryTask = AIPlayerMustFinishCurrentTask(pBot, &pBot->PrimaryBotTask);
if (!bPlayerMustFinishPrimaryTask) if (!bPlayerMustFinishPrimaryTask)
@ -7124,6 +7165,7 @@ void AIPlayerSetSecondaryAlienTask(AvHAIPlayer* pBot, AvHAIPlayerTask* Task)
if (FNullEnt(NearestDangerTurret.edict) || ThisDist < MinDist) if (FNullEnt(NearestDangerTurret.edict) || ThisDist < MinDist)
{ {
NearestDangerTurret = (*it); NearestDangerTurret = (*it);
MinDist = ThisDist;
} }
} }
@ -7521,7 +7563,10 @@ void AIPlayerSetWantsAndNeedsAlienTask(AvHAIPlayer* pBot, AvHAIPlayerTask* Task)
bInMiddleOfMove = CurrentMove.flag != SAMPLE_POLYFLAGS_WALK; bInMiddleOfMove = CurrentMove.flag != SAMPLE_POLYFLAGS_WALK;
} }
if (!bInMiddleOfMove) // Don't get upgrades if we're not in our regular desired life form, e.g. we've temporarily gone gorge to drop a res tower
bool bTempEvolved = (pBot->BotRole == BOT_ROLE_BUILDER && !IsPlayerGorge(pBot->Edict)) || (pBot->BotRole != BOT_ROLE_BUILDER && IsPlayerGorge(pBot->Edict));
if (!bInMiddleOfMove && !bTempEvolved)
{ {
if (!PlayerHasAlienUpgradeOfType(pBot->Edict, HIVE_TECH_DEFENCE) && AITAC_IsAlienUpgradeAvailableForTeam(pBot->Player->GetTeam(), HIVE_TECH_DEFENCE)) if (!PlayerHasAlienUpgradeOfType(pBot->Edict, HIVE_TECH_DEFENCE) && AITAC_IsAlienUpgradeAvailableForTeam(pBot->Player->GetTeam(), HIVE_TECH_DEFENCE))
{ {
@ -8894,4 +8939,5 @@ void OnBotTeleport(AvHAIPlayer* pBot)
ClearBotStuck(pBot); ClearBotStuck(pBot);
ClearBotStuckMovement(pBot); ClearBotStuckMovement(pBot);
pBot->BotNavInfo.LastOpenLocation = ZERO_VECTOR; pBot->BotNavInfo.LastOpenLocation = ZERO_VECTOR;
pBot->LastTeleportTime = gpGlobals->time;
} }

View file

@ -644,6 +644,10 @@ void AIMGR_UpdateAIPlayers()
BotUpdateViewRotation(bot, FrameDelta); BotUpdateViewRotation(bot, FrameDelta);
// Need to reset this since impulses generally should only be called once at a time, so this
// prevents it from being called on consecutive frames if this bot isn't running its think routine every frame
bot->Impulse = 0;
if (bHasRoundStarted) if (bHasRoundStarted)
{ {
if (IsPlayerCommander(bot->Edict)) if (IsPlayerCommander(bot->Edict))

View file

@ -1146,6 +1146,11 @@ void AITAC_PopulateHiveData()
void AITAC_RefreshHiveData() void AITAC_RefreshHiveData()
{ {
if (ResourceNodes.size() == 0)
{
AITAC_PopulateResourceNodes();
}
if (Hives.size() == 0) if (Hives.size() == 0)
{ {
AITAC_PopulateHiveData(); AITAC_PopulateHiveData();
@ -4827,7 +4832,7 @@ bool AITAC_ShouldBotBuildHive(AvHAIPlayer* pBot, AvHAIHiveDefinition** EligibleH
HiveCost += BALANCE_VAR(kGorgeCost); HiveCost += BALANCE_VAR(kGorgeCost);
} }
if (pBot->Player->GetResources() < HiveCost) { return false; } if (pBot->Player->GetResources() < HiveCost - 10) { return false; }
AvHTeamNumber BotTeam = pBot->Player->GetTeam(); AvHTeamNumber BotTeam = pBot->Player->GetTeam();
AvHTeamNumber EnemyTeam = AIMGR_GetEnemyTeam(BotTeam); AvHTeamNumber EnemyTeam = AIMGR_GetEnemyTeam(BotTeam);

View file

@ -1007,8 +1007,6 @@ bool AITASK_IsMarineSecureHiveTaskStillValid(AvHAIPlayer* pBot, AvHAIPlayerTask*
if (!HiveToSecure || HiveToSecure->Status != HIVE_STATUS_UNBUILT) { return false; } if (!HiveToSecure || HiveToSecure->Status != HIVE_STATUS_UNBUILT) { return false; }
// A marine bot will consider their "secure hive" task completed if the following structures have been fully built: // A marine bot will consider their "secure hive" task completed if the following structures have been fully built:
// Phase gate (only if tech available) // Phase gate (only if tech available)
// Turret factory (regular or advanced) // Turret factory (regular or advanced)
@ -1380,6 +1378,7 @@ void BotProgressReinforceStructureTask(AvHAIPlayer* pBot, AvHAIPlayerTask* Task)
// We had a go, whether it succeeded or not we should try a new location // 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) if (Task->ActiveBuildInfo.BuildStatus == BUILD_ATTEMPT_FAILED || Task->ActiveBuildInfo.BuildStatus == BUILD_ATTEMPT_SUCCESS)
{ {
pBot->Impulse = 0;
Task->TaskStartedTime = gpGlobals->time; Task->TaskStartedTime = gpGlobals->time;
Task->TaskLocation = ZERO_VECTOR; Task->TaskLocation = ZERO_VECTOR;
Task->ActiveBuildInfo.BuildStatus = BUILD_ATTEMPT_NONE; Task->ActiveBuildInfo.BuildStatus = BUILD_ATTEMPT_NONE;
@ -1817,7 +1816,7 @@ void BotProgressAttackTask(AvHAIPlayer* pBot, AvHAIPlayerTask* Task)
AvHTurret* TurretRef = dynamic_cast<AvHTurret*>(CBaseEntity::Instance(Task->TaskTarget)); AvHTurret* TurretRef = dynamic_cast<AvHTurret*>(CBaseEntity::Instance(Task->TaskTarget));
if (TurretRef && TurretRef->GetIsValidTarget(pBot->Player)) if (TurretRef && TurretRef->GetIsValidTarget(pBot->Player) && !vIsZero(GetVisiblePointOnPlayerFromObserver(Task->TaskTarget, pBot->Edict)))
{ {
if (vIsZero(pBot->LastSafeLocation)) if (vIsZero(pBot->LastSafeLocation))
{ {
@ -1825,6 +1824,7 @@ void BotProgressAttackTask(AvHAIPlayer* pBot, AvHAIPlayerTask* Task)
} }
MoveTo(pBot, pBot->LastSafeLocation, MOVESTYLE_NORMAL); MoveTo(pBot, pBot->LastSafeLocation, MOVESTYLE_NORMAL);
BotLookAt(pBot, Task->TaskTarget);
} }
return; return;
@ -2908,7 +2908,6 @@ void MarineProgressSecureHiveTask(AvHAIPlayer* pBot, AvHAIPlayerTask* Task)
StructureFilter.ReachabilityTeam = BotTeam; StructureFilter.ReachabilityTeam = BotTeam;
StructureFilter.ReachabilityFlags = pBot->BotNavInfo.NavProfile.ReachabilityFlag; StructureFilter.ReachabilityFlags = pBot->BotNavInfo.NavProfile.ReachabilityFlag;
StructureFilter.ExcludeStatusFlags = STRUCTURE_STATUS_RECYCLING; StructureFilter.ExcludeStatusFlags = STRUCTURE_STATUS_RECYCLING;
StructureFilter.PurposeFlags = STRUCTURE_PURPOSE_FORTIFY;
vector<AvHAIBuildableStructure> BuildableStructures = AITAC_FindAllDeployables(Hive->FloorLocation, &StructureFilter); vector<AvHAIBuildableStructure> BuildableStructures = AITAC_FindAllDeployables(Hive->FloorLocation, &StructureFilter);
@ -2988,10 +2987,10 @@ void MarineProgressSecureHiveTask(AvHAIPlayer* pBot, AvHAIPlayerTask* Task)
{ {
DeployableSearchFilter EnemyStructures; DeployableSearchFilter EnemyStructures;
EnemyStructures.DeployableTypes = SEARCH_ALL_STRUCTURES; EnemyStructures.DeployableTypes = SEARCH_ALL_STRUCTURES;
EnemyStructures.MaxSearchRadius = UTIL_MetresToGoldSrcUnits(15.0f);
EnemyStructures.DeployableTeam = EnemyTeam; EnemyStructures.DeployableTeam = EnemyTeam;
EnemyStructures.ReachabilityTeam = BotTeam; EnemyStructures.ReachabilityTeam = BotTeam;
EnemyStructures.ReachabilityFlags = pBot->BotNavInfo.NavProfile.ReachabilityFlag; EnemyStructures.ReachabilityFlags = pBot->BotNavInfo.NavProfile.ReachabilityFlag;
EnemyStructures.MaxSearchRadius = UTIL_MetresToGoldSrcUnits(15.0f);
AvHAIBuildableStructure EnemyStructure = AITAC_FindClosestDeployableToLocation(Hive->FloorLocation, &EnemyStructures); AvHAIBuildableStructure EnemyStructure = AITAC_FindClosestDeployableToLocation(Hive->FloorLocation, &EnemyStructures);
@ -3113,8 +3112,6 @@ void MarineProgressCapResNodeTask(AvHAIPlayer* pBot, AvHAIPlayerTask* Task)
BotGuardLocation(pBot, Task->TaskLocation); BotGuardLocation(pBot, Task->TaskLocation);
} }
} }
void BotProgressAssaultMarineBaseTask(AvHAIPlayer* pBot, AvHAIPlayerTask* Task) void BotProgressAssaultMarineBaseTask(AvHAIPlayer* pBot, AvHAIPlayerTask* Task)
@ -3809,7 +3806,13 @@ void AITASK_SetMoveTask(AvHAIPlayer* pBot, AvHAIPlayerTask* Task, const Vector L
void AITASK_SetBuildTask(AvHAIPlayer* pBot, AvHAIPlayerTask* Task, const AvHAIDeployableStructureType StructureType, const Vector Location, const bool bIsUrgent) void AITASK_SetBuildTask(AvHAIPlayer* pBot, AvHAIPlayerTask* Task, const AvHAIDeployableStructureType StructureType, const Vector Location, const bool bIsUrgent)
{ {
if (Task->TaskType == TASK_BUILD && Task->StructureType == StructureType && vDist2DSq(Task->TaskLocation, Location) < sqrf(UTIL_MetresToGoldSrcUnits(5.0f))) { return; } if (Task->TaskType == TASK_BUILD && Task->StructureType == StructureType && vDist2DSq(Task->TaskLocation, Location) < sqrf(UTIL_MetresToGoldSrcUnits(1.0f)))
{
Task->bTaskIsUrgent = bIsUrgent;
return;
}
if (Task->ActiveBuildInfo.BuildStatus == BUILD_ATTEMPT_PENDING) { return; }
AITASK_ClearBotTask(pBot, Task); AITASK_ClearBotTask(pBot, Task);
@ -4028,6 +4031,8 @@ void AITASK_SetReinforceStructureTask(AvHAIPlayer* pBot, AvHAIPlayerTask* Task,
return; return;
} }
if (Task->ActiveBuildInfo.BuildStatus == BUILD_ATTEMPT_PENDING) { return; }
AITASK_ClearBotTask(pBot, Task); AITASK_ClearBotTask(pBot, Task);
if (FNullEnt(Target) || Target->v.deadflag != DEAD_NO) { return; } if (FNullEnt(Target) || Target->v.deadflag != DEAD_NO) { return; }