mirror of
https://github.com/ENSL/NS.git
synced 2024-11-10 07:11:38 +00:00
Improve bot vision, bug fixes
* Re-added the view frustum for bots * Hopefully stopped bots getting permanently stuck trying to evolve an upgrade in an invalid place * Bots will now leave the game after 2 hours if no humans playing (ignores human spectators)
This commit is contained in:
parent
75469430ad
commit
eba41379e3
10 changed files with 375 additions and 85 deletions
|
@ -8,6 +8,7 @@
|
|||
|
||||
#include "AvHHive.h"
|
||||
#include "AvHEntities.h"
|
||||
#include "AvHAIMath.h"
|
||||
|
||||
static const float commander_action_cooldown = 1.0f;
|
||||
static const float min_request_spam_time = 10.0f;
|
||||
|
@ -740,6 +741,7 @@ typedef struct AVH_AI_PLAYER
|
|||
AvHAIWeapon DesiredMoveWeapon = WEAPON_INVALID;
|
||||
AvHAIWeapon DesiredCombatWeapon = WEAPON_INVALID;
|
||||
|
||||
frustum_plane_t viewFrustum[6]; // Bot's view frustum. Essentially, their "screen" for determining visibility of stuff
|
||||
enemy_status TrackedEnemies[32];
|
||||
int CurrentEnemy = -1;
|
||||
AvHAICombatStrategy CurrentCombatStrategy = COMBAT_STRATEGY_ATTACK;
|
||||
|
|
|
@ -810,4 +810,47 @@ float UTIL_CalculateSlopeAngleBetweenPoints(const Vector StartPoint, const Vecto
|
|||
float Rise = fabsf(StartPoint.z - EndPoint.z);
|
||||
|
||||
return atanf(Rise / Run);
|
||||
}
|
||||
|
||||
// Function to check if a finite line intersects with an AABB
|
||||
bool vlineIntersectsAABB(Vector lineStart, Vector lineEnd, Vector BoxMinPosition, Vector BoxMaxPosition)
|
||||
{
|
||||
Vector RayDir = UTIL_GetVectorNormal(lineEnd - lineStart);
|
||||
float LineLength = vDist3D(lineStart, lineEnd);
|
||||
Vector dirfrac;
|
||||
|
||||
float t = FLT_MAX;
|
||||
|
||||
// r.dir is unit direction vector of ray
|
||||
dirfrac.x = 1.0f / RayDir.x;
|
||||
dirfrac.y = 1.0f / RayDir.y;
|
||||
dirfrac.z = 1.0f / RayDir.z;
|
||||
// lb is the corner of AABB with minimal coordinates - left bottom, rt is maximal corner
|
||||
// r.org is origin of ray
|
||||
float t1 = (BoxMinPosition.x - lineStart.x) * dirfrac.x;
|
||||
float t2 = (BoxMaxPosition.x - lineStart.x) * dirfrac.x;
|
||||
float t3 = (BoxMinPosition.y - lineStart.y) * dirfrac.y;
|
||||
float t4 = (BoxMaxPosition.y - lineStart.y) * dirfrac.y;
|
||||
float t5 = (BoxMinPosition.z - lineStart.z) * dirfrac.z;
|
||||
float t6 = (BoxMaxPosition.z - lineStart.z) * dirfrac.z;
|
||||
|
||||
float tmin = max(max(min(t1, t2), min(t3, t4)), min(t5, t6));
|
||||
float tmax = min(min(max(t1, t2), max(t3, t4)), max(t5, t6));
|
||||
|
||||
// if tmax < 0, ray (line) is intersecting AABB, but the whole AABB is behind us
|
||||
if (tmax < 0)
|
||||
{
|
||||
t = tmax;
|
||||
return false;
|
||||
}
|
||||
|
||||
// if tmin > tmax, ray doesn't intersect AABB
|
||||
if (tmin > tmax)
|
||||
{
|
||||
t = tmax;
|
||||
return false;
|
||||
}
|
||||
|
||||
t = tmin;
|
||||
return t <= LineLength;
|
||||
}
|
|
@ -205,4 +205,6 @@ unsigned int UTIL_CountSetBitsInInteger(unsigned int n);
|
|||
|
||||
float UTIL_CalculateSlopeAngleBetweenPoints(const Vector StartPoint, const Vector EndPoint);
|
||||
|
||||
bool vlineIntersectsAABB(Vector lineStart, Vector lineEnd, Vector BoxMinPosition, Vector BoxMaxPosition);
|
||||
|
||||
#endif
|
|
@ -2404,7 +2404,7 @@ bool HasBotCompletedJumpMove(const AvHAIPlayer* pBot, Vector MoveStart, Vector M
|
|||
|
||||
bool HasBotCompletedPhaseGateMove(const AvHAIPlayer* pBot, Vector MoveStart, Vector MoveEnd, Vector NextMoveDestination, SamplePolyFlags NextMoveFlag)
|
||||
{
|
||||
return vPointOverlaps3D(MoveEnd, pBot->Edict->v.absmin, pBot->Edict->v.absmax);
|
||||
return vPointOverlaps3D(MoveEnd, pBot->Edict->v.absmin, pBot->Edict->v.absmax) || vDist2DSq(pBot->Edict->v.origin, MoveEnd) < sqrf(32.0f);
|
||||
}
|
||||
|
||||
bool HasBotCompletedLiftMove(const AvHAIPlayer* pBot, Vector MoveStart, Vector MoveEnd, Vector NextMoveDestination, SamplePolyFlags NextMoveFlag)
|
||||
|
@ -4345,6 +4345,13 @@ bool IsBotOffWalkNode(const AvHAIPlayer* pBot, Vector MoveStart, Vector MoveEnd,
|
|||
|
||||
if (vDist2DSq(pBot->Edict->v.origin, NearestPointOnLine) > sqrf(GetPlayerRadius(pBot->Edict) * 3.0f)) { return true; }
|
||||
|
||||
if (!FNullEnt(pBot->Edict->v.groundentity))
|
||||
{
|
||||
nav_door* Door = UTIL_GetNavDoorByEdict(pBot->Edict->v.groundentity);
|
||||
|
||||
if (Door) { return false; }
|
||||
}
|
||||
|
||||
if (vEquals2D(NearestPointOnLine, MoveStart) && !UTIL_PointIsDirectlyReachable(pBot->CurrentFloorPosition, MoveStart)) { return true; }
|
||||
if (vEquals2D(NearestPointOnLine, MoveEnd) && !UTIL_PointIsDirectlyReachable(pBot->CurrentFloorPosition, MoveEnd)) { return true; }
|
||||
|
||||
|
@ -4358,6 +4365,15 @@ bool IsBotOffFallNode(const AvHAIPlayer* pBot, Vector MoveStart, Vector MoveEnd,
|
|||
|
||||
Vector NearestPointOnLine = vClosestPointOnLine2D(MoveStart, MoveEnd, pBot->Edict->v.origin);
|
||||
|
||||
if (vDist2DSq(pBot->Edict->v.origin, NearestPointOnLine) > sqrf(GetPlayerRadius(pBot->Edict) * 3.0f)) { return true; }
|
||||
|
||||
if (!FNullEnt(pBot->Edict->v.groundentity))
|
||||
{
|
||||
nav_door* Door = UTIL_GetNavDoorByEdict(pBot->Edict->v.groundentity);
|
||||
|
||||
if (Door) { return false; }
|
||||
}
|
||||
|
||||
if (!UTIL_PointIsDirectlyReachable(pBot->CurrentFloorPosition, MoveStart) && !UTIL_PointIsDirectlyReachable(pBot->CurrentFloorPosition, MoveEnd)) { return true; }
|
||||
|
||||
return false;
|
||||
|
@ -4391,7 +4407,7 @@ bool IsBotOffJumpNode(const AvHAIPlayer* pBot, Vector MoveStart, Vector MoveEnd,
|
|||
|
||||
bool IsBotOffPhaseGateNode(const AvHAIPlayer* pBot, Vector MoveStart, Vector MoveEnd, Vector NextMoveDestination, SamplePolyFlags NextMoveFlag)
|
||||
{
|
||||
if (vDist2DSq(pBot->Edict->v.origin, MoveStart) > sqrf(UTIL_MetresToGoldSrcUnits(3.0f)) && vDist2DSq(pBot->Edict->v.origin, MoveEnd) > sqrf(UTIL_MetresToGoldSrcUnits(3.0f))) { return true; }
|
||||
if (vDist2DSq(pBot->Edict->v.origin, MoveStart) > sqrf(UTIL_MetresToGoldSrcUnits(2.0f)) && vDist2DSq(pBot->Edict->v.origin, MoveEnd) > sqrf(UTIL_MetresToGoldSrcUnits(2.0f))) { return true; }
|
||||
|
||||
DeployableSearchFilter PGFilter;
|
||||
PGFilter.DeployableTeam = pBot->Player->GetTeam();
|
||||
|
@ -6579,6 +6595,7 @@ void BotFollowPath(AvHAIPlayer* pBot)
|
|||
|
||||
if (IsBotOffPath(pBot))
|
||||
{
|
||||
MoveToWithoutNav(pBot, CurrentNode.Location);
|
||||
pBot->BotNavInfo.StuckInfo.bPathFollowFailed = true;
|
||||
ClearBotPath(pBot);
|
||||
return;
|
||||
|
@ -7574,15 +7591,13 @@ void UTIL_PopulateAffectedConnectionsForDoor(nav_door* Door)
|
|||
{
|
||||
Vector DoorCentre = (*stopIt);
|
||||
|
||||
Vector NearestPointOnLine = vClosestPointOnLine(ConnStart, MidPoint, DoorCentre);
|
||||
if (vPointOverlaps3D(NearestPointOnLine, DoorCentre - HalfExtents, DoorCentre + HalfExtents))
|
||||
if (vlineIntersectsAABB(ConnStart, MidPoint, DoorCentre - HalfExtents, DoorCentre + HalfExtents))
|
||||
{
|
||||
Door->AffectedConnections.push_back(&(*it));
|
||||
break;
|
||||
}
|
||||
|
||||
NearestPointOnLine = vClosestPointOnLine(MidPoint, ConnEnd, DoorCentre);
|
||||
if (vPointOverlaps3D(NearestPointOnLine, DoorCentre - HalfExtents, DoorCentre + HalfExtents))
|
||||
if (vlineIntersectsAABB(MidPoint, ConnEnd, DoorCentre - HalfExtents, DoorCentre + HalfExtents))
|
||||
{
|
||||
Door->AffectedConnections.push_back(&(*it));
|
||||
break;
|
||||
|
@ -8752,7 +8767,6 @@ void NAV_ProgressMovementTask(AvHAIPlayer* pBot)
|
|||
AimLocation.z = EntityCentre.z;
|
||||
}
|
||||
|
||||
UTIL_DrawLine(INDEXENT(1), pBot->CurrentEyePosition, AimLocation);
|
||||
}
|
||||
|
||||
BotMoveLookAt(pBot, AimLocation);
|
||||
|
@ -8771,7 +8785,8 @@ void NAV_ProgressMovementTask(AvHAIPlayer* pBot)
|
|||
}
|
||||
}
|
||||
|
||||
MoveTo(pBot, MoveTask->TaskLocation, MOVESTYLE_NORMAL);
|
||||
bool bSuccess = MoveTo(pBot, MoveTask->TaskLocation, MOVESTYLE_NORMAL);
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -197,6 +197,14 @@ bool BotUseObject(AvHAIPlayer* pBot, edict_t* Target, bool bContinuous)
|
|||
{
|
||||
pBot->Button |= IN_USE;
|
||||
pBot->LastUseTime = gpGlobals->time;
|
||||
|
||||
CBaseEntity* UsedObject = CBaseEntity::Instance(Target);
|
||||
|
||||
if (UsedObject)
|
||||
{
|
||||
UsedObject->Use(pBot->Player, pBot->Player, USE_TOGGLE, 0);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -1323,6 +1331,8 @@ void BotUpdateView(AvHAIPlayer* pBot)
|
|||
|
||||
pBot->ViewForwardVector = UTIL_GetForwardVector(pBot->Edict->v.v_angle);
|
||||
|
||||
UpdateAIPlayerViewFrustum(pBot);
|
||||
|
||||
// Update list of currently visible players
|
||||
for (int i = 1; i <= gpGlobals->maxClients; i++)
|
||||
{
|
||||
|
@ -1534,13 +1544,55 @@ void BotClearEnemyTrackingInfo(enemy_status* TrackingInfo)
|
|||
TrackingInfo->LastHiddenPosition = ZERO_VECTOR;
|
||||
}
|
||||
|
||||
void UpdateAIPlayerViewFrustum(AvHAIPlayer* pBot)
|
||||
{
|
||||
MAKE_VECTORS(pBot->Edict->v.v_angle);
|
||||
Vector up = gpGlobals->v_up;
|
||||
Vector forward = gpGlobals->v_forward;
|
||||
Vector right = gpGlobals->v_right;
|
||||
|
||||
Vector fc = (pBot->Edict->v.origin + pBot->Edict->v.view_ofs) + (forward * BOT_MAX_VIEW);
|
||||
|
||||
Vector fbl = fc + (up * f_ffheight / 2.0f) - (right * f_ffwidth / 2.0f);
|
||||
Vector fbr = fc + (up * f_ffheight / 2.0f) + (right * f_ffwidth / 2.0f);
|
||||
Vector ftl = fc - (up * f_ffheight / 2.0f) - (right * f_ffwidth / 2.0f);
|
||||
Vector ftr = fc - (up * f_ffheight / 2.0f) + (right * f_ffwidth / 2.0f);
|
||||
|
||||
Vector nc = (pBot->Edict->v.origin + pBot->Edict->v.view_ofs) + (forward * BOT_MIN_VIEW);
|
||||
|
||||
Vector nbl = nc + (up * f_fnheight / 2.0f) - (right * f_fnwidth / 2.0f);
|
||||
Vector nbr = nc + (up * f_fnheight / 2.0f) + (right * f_fnwidth / 2.0f);
|
||||
Vector ntl = nc - (up * f_fnheight / 2.0f) - (right * f_fnwidth / 2.0f);
|
||||
Vector ntr = nc - (up * f_fnheight / 2.0f) + (right * f_fnwidth / 2.0f);
|
||||
|
||||
UTIL_SetFrustumPlane(&pBot->viewFrustum[FRUSTUM_PLANE_TOP], ftl, ntl, ntr);
|
||||
UTIL_SetFrustumPlane(&pBot->viewFrustum[FRUSTUM_PLANE_BOTTOM], fbr, nbr, nbl);
|
||||
UTIL_SetFrustumPlane(&pBot->viewFrustum[FRUSTUM_PLANE_LEFT], fbl, nbl, ntl);
|
||||
UTIL_SetFrustumPlane(&pBot->viewFrustum[FRUSTUM_PLANE_RIGHT], ftr, ntr, nbr);
|
||||
UTIL_SetFrustumPlane(&pBot->viewFrustum[FRUSTUM_PLANE_NEAR], nbr, ntr, ntl);
|
||||
UTIL_SetFrustumPlane(&pBot->viewFrustum[FRUSTUM_PLANE_FAR], fbl, ftl, ftr);
|
||||
}
|
||||
|
||||
bool IsPlayerInBotFOV(AvHAIPlayer* Observer, edict_t* TargetPlayer)
|
||||
{
|
||||
Vector TargetVector = (TargetPlayer->v.origin - Observer->CurrentEyePosition).Normalize();
|
||||
/*Vector TargetVector = (TargetPlayer->v.origin - Observer->CurrentEyePosition).Normalize();
|
||||
|
||||
float DotProduct = UTIL_GetDotProduct(Observer->ViewForwardVector, TargetVector);
|
||||
|
||||
return DotProduct > 0.65f;
|
||||
return DotProduct > 0.65f;*/
|
||||
|
||||
if (FNullEnt(TargetPlayer) || !IsPlayerActiveInGame(TargetPlayer)) { return false; }
|
||||
// To make things a little more accurate, we're going to treat players as cylinders rather than boxes
|
||||
for (int i = 0; i < 6; i++)
|
||||
{
|
||||
// Our cylinder must be inside all planes to be visible, otherwise return false
|
||||
if (!UTIL_CylinderInsidePlane(&Observer->viewFrustum[i], TargetPlayer->v.origin - Vector(0, 0, 5), 60.0f, 16.0f))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
|
@ -1742,7 +1794,7 @@ void StartNewBotFrame(AvHAIPlayer* pBot)
|
|||
else
|
||||
{
|
||||
// All other structures should appear near-instantly
|
||||
if ((gpGlobals->time - pBot->PrimaryBotTask.ActiveBuildInfo.BuildAttemptTime) > 0.5f)
|
||||
if ((gpGlobals->time - pBot->PrimaryBotTask.ActiveBuildInfo.BuildAttemptTime) > 1.0f)
|
||||
{
|
||||
pBot->PrimaryBotTask.ActiveBuildInfo.BuildStatus = BUILD_ATTEMPT_FAILED;
|
||||
}
|
||||
|
@ -1765,7 +1817,7 @@ void StartNewBotFrame(AvHAIPlayer* pBot)
|
|||
else
|
||||
{
|
||||
// All other structures should appear near-instantly
|
||||
if ((gpGlobals->time - pBot->SecondaryBotTask.ActiveBuildInfo.BuildAttemptTime) > 0.5f)
|
||||
if ((gpGlobals->time - pBot->SecondaryBotTask.ActiveBuildInfo.BuildAttemptTime) > 1.0f)
|
||||
{
|
||||
pBot->SecondaryBotTask.ActiveBuildInfo.BuildStatus = BUILD_ATTEMPT_FAILED;
|
||||
}
|
||||
|
@ -3201,6 +3253,7 @@ bool MarineCombatThink(AvHAIPlayer* pBot)
|
|||
|
||||
void AIPlayerSetPrimaryMarineTask(AvHAIPlayer* pBot, AvHAIPlayerTask* Task)
|
||||
{
|
||||
|
||||
switch (pBot->BotRole)
|
||||
{
|
||||
case BOT_ROLE_SWEEPER:
|
||||
|
@ -3890,6 +3943,15 @@ void AIPlayerSetSecondaryMarineTask(AvHAIPlayer* pBot, AvHAIPlayerTask* Task)
|
|||
}
|
||||
}
|
||||
|
||||
// If we're engaging an enemy turret then finish the job
|
||||
if (Task->TaskType == TASK_ATTACK && (GetStructureTypeFromEdict(Task->TaskTarget) & (STRUCTURE_ALIEN_OFFENCECHAMBER | STRUCTURE_MARINE_TURRET | STRUCTURE_MARINE_TURRETFACTORY | STRUCTURE_MARINE_TURRETFACTORY)))
|
||||
{
|
||||
if (vDist2DSq(pBot->Edict->v.origin, Task->TaskTarget->v.origin) < sqrf(UTIL_MetresToGoldSrcUnits(20.0f)))
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Find any nearby unbuilt structures
|
||||
DeployableSearchFilter UnbuiltFilter;
|
||||
UnbuiltFilter.DeployableTypes = STRUCTURE_MARINE_INFANTRYPORTAL;
|
||||
|
@ -4071,6 +4133,35 @@ void AIPlayerSetSecondaryMarineTask(AvHAIPlayer* pBot, AvHAIPlayerTask* Task)
|
|||
}
|
||||
}
|
||||
|
||||
// If we're engaging an enemy turret then finish the job
|
||||
if (Task->TaskType == TASK_ATTACK)
|
||||
{
|
||||
if (vDist2DSq(pBot->Edict->v.origin, Task->TaskTarget->v.origin) < sqrf(UTIL_MetresToGoldSrcUnits(20.0f)))
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
DeployableSearchFilter EnemyStructures;
|
||||
EnemyStructures.DeployableTypes = SEARCH_ALL_STRUCTURES;
|
||||
EnemyStructures.DeployableTeam = BotTeam;
|
||||
EnemyStructures.ReachabilityTeam = BotTeam;
|
||||
EnemyStructures.ReachabilityFlags = pBot->BotNavInfo.NavProfile.ReachabilityFlag;
|
||||
EnemyStructures.MaxSearchRadius = UTIL_MetresToGoldSrcUnits(10.0f);
|
||||
|
||||
vector<AvHAIBuildableStructure> NearbyEnemyStructures = AITAC_FindAllDeployables(pBot->Edict->v.origin, &EnemyStructures);
|
||||
|
||||
for (auto it = NearbyEnemyStructures.begin(); it != NearbyEnemyStructures.end(); it++)
|
||||
{
|
||||
if (UTIL_PlayerHasLOSToEntity(pBot->Edict, it->edict, UTIL_MetresToGoldSrcUnits(20.0f), false))
|
||||
{
|
||||
AITASK_SetAttackTask(pBot, Task, it->edict, false);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
bool AIPlayerMustFinishCurrentTask(AvHAIPlayer* pBot, AvHAIPlayerTask* Task)
|
||||
|
@ -4079,7 +4170,7 @@ bool AIPlayerMustFinishCurrentTask(AvHAIPlayer* pBot, AvHAIPlayerTask* Task)
|
|||
|
||||
if (!AITASK_IsTaskStillValid(pBot, Task)) { return false; }
|
||||
|
||||
if (IsPlayerGorge(pBot->Edict))
|
||||
if (GetPlayerActiveClass(pBot->Player) == AVH_USER3_ALIEN_PLAYER2)
|
||||
{
|
||||
AvHTeamNumber BotTeam = pBot->Player->GetTeam();
|
||||
|
||||
|
@ -4149,39 +4240,6 @@ void AIPlayerNSAlienThink(AvHAIPlayer* pBot)
|
|||
|
||||
pBot->CurrentTask = AIPlayerGetNextTask(pBot);
|
||||
|
||||
if (gpGlobals->time - pBot->LastCombatTime > 5.0f)
|
||||
{
|
||||
bool bInMiddleOfMove = false;
|
||||
|
||||
if (pBot->BotNavInfo.CurrentPath.size() > 0 && pBot->BotNavInfo.CurrentPathPoint < pBot->BotNavInfo.CurrentPath.size())
|
||||
{
|
||||
bot_path_node CurrentMove = pBot->BotNavInfo.CurrentPath[pBot->BotNavInfo.CurrentPathPoint];
|
||||
|
||||
bInMiddleOfMove = CurrentMove.flag != SAMPLE_POLYFLAGS_WALK;
|
||||
}
|
||||
|
||||
if (!bInMiddleOfMove)
|
||||
{
|
||||
if (!PlayerHasAlienUpgradeOfType(pBot->Edict, HIVE_TECH_DEFENCE) && AITAC_IsAlienUpgradeAvailableForTeam(pBot->Player->GetTeam(), HIVE_TECH_DEFENCE))
|
||||
{
|
||||
BotEvolveUpgrade(pBot, pBot->CurrentFloorPosition, AlienGetDesiredUpgrade(pBot, HIVE_TECH_DEFENCE));
|
||||
return;
|
||||
}
|
||||
|
||||
if (!PlayerHasAlienUpgradeOfType(pBot->Edict, HIVE_TECH_MOVEMENT) && AITAC_IsAlienUpgradeAvailableForTeam(pBot->Player->GetTeam(), HIVE_TECH_MOVEMENT))
|
||||
{
|
||||
BotEvolveUpgrade(pBot, pBot->CurrentFloorPosition, AlienGetDesiredUpgrade(pBot, HIVE_TECH_MOVEMENT));
|
||||
return;
|
||||
}
|
||||
|
||||
if (!PlayerHasAlienUpgradeOfType(pBot->Edict, HIVE_TECH_SENSORY) && AITAC_IsAlienUpgradeAvailableForTeam(pBot->Player->GetTeam(), HIVE_TECH_SENSORY))
|
||||
{
|
||||
BotEvolveUpgrade(pBot, pBot->CurrentFloorPosition, AlienGetDesiredUpgrade(pBot, HIVE_TECH_SENSORY));
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (pBot->CurrentTask && pBot->CurrentTask->TaskType != TASK_NONE)
|
||||
{
|
||||
BotProgressTask(pBot, pBot->CurrentTask);
|
||||
|
@ -5488,16 +5546,29 @@ void AIPlayerReceiveMoveOrder(AvHAIPlayer* pBot, Vector Destination)
|
|||
}
|
||||
|
||||
const AvHAIHiveDefinition* HiveRef = AITAC_GetHiveNearestLocation(Destination);
|
||||
|
||||
// Have we been asked to go to an empty hive? If so, then treat the order as a "help secure this hive" command
|
||||
if (HiveRef && HiveRef->Status == HIVE_STATUS_UNBUILT && vDist2DSq(HiveRef->Location, Destination) < sqrf(UTIL_MetresToGoldSrcUnits(15.0f)))
|
||||
if (HiveRef && vDist2DSq(HiveRef->Location, Destination) < sqrf(UTIL_MetresToGoldSrcUnits(15.0f)))
|
||||
{
|
||||
if (!AICOMM_IsHiveFullySecured(pBot, HiveRef, false))
|
||||
if (HiveRef->Status == HIVE_STATUS_UNBUILT)
|
||||
{
|
||||
AITASK_SetSecureHiveTask(pBot, &pBot->CommanderTask, HiveRef->HiveEdict, ActualMoveLocation, false);
|
||||
pBot->CommanderTask.bIssuedByCommander = true;
|
||||
return;
|
||||
if (!AICOMM_IsHiveFullySecured(pBot, HiveRef, false))
|
||||
{
|
||||
AITASK_SetSecureHiveTask(pBot, &pBot->CommanderTask, HiveRef->HiveEdict, ActualMoveLocation, false);
|
||||
pBot->CommanderTask.bIssuedByCommander = true;
|
||||
return;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (UTIL_QuickTrace(pBot->Edict, Destination + Vector(0.0f, 0.0f, 32.0f), HiveRef->Location))
|
||||
{
|
||||
AITASK_SetAttackTask(pBot, &pBot->CommanderTask, HiveRef->HiveEdict, false);
|
||||
pBot->CommanderTask.bIssuedByCommander = true;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
// Otherwise, treat as a normal move order. Go there and wait a bit to see what the commander wants to do next
|
||||
|
@ -5816,7 +5887,7 @@ void AIPlayerSetAlienCapperPrimaryTask(AvHAIPlayer* pBot, AvHAIPlayerTask* Task)
|
|||
|
||||
AvHAIResourceNode* NodeToCap = nullptr;
|
||||
|
||||
bool bCanAttackTowers = (!IsPlayerGorge(pBot->Edict) || PlayerHasWeapon(pBot->Player, WEAPON_GORGE_BILEBOMB));
|
||||
bool bCanAttackTowers = (GetPlayerActiveClass(pBot->Player) != AVH_USER3_ALIEN_PLAYER2 || PlayerHasWeapon(pBot->Player, WEAPON_GORGE_BILEBOMB));
|
||||
|
||||
// If we're already capping a node, are at the node and there is an unfinished tower on there, then finish the job and don't move on yet
|
||||
if (Task->TaskType == TASK_CAP_RESNODE)
|
||||
|
@ -5844,7 +5915,7 @@ void AIPlayerSetAlienCapperPrimaryTask(AvHAIPlayer* pBot, AvHAIPlayerTask* Task)
|
|||
|
||||
float ResourcesRequired = BALANCE_VAR(kResourceTowerCost);
|
||||
|
||||
if (!IsPlayerGorge(pBot->Edict))
|
||||
if (GetPlayerActiveClass(pBot->Player) != AVH_USER3_ALIEN_PLAYER2)
|
||||
{
|
||||
ResourcesRequired += BALANCE_VAR(kGorgeCost);
|
||||
}
|
||||
|
@ -6787,7 +6858,7 @@ void AIPlayerSetSecondaryAlienTask(AvHAIPlayer* pBot, AvHAIPlayerTask* Task)
|
|||
{
|
||||
AvHAIPlayer* ThisBot = (*BotIt);
|
||||
|
||||
if (ThisBot != pBot && IsPlayerActiveInGame(ThisBot->Edict) && !IsPlayerGorge(ThisBot->Edict) && vDist2DSq(ThisBot->Edict->v.origin, ThisHive->FloorLocation) > sqrf(UTIL_MetresToGoldSrcUnits(15.0f)))
|
||||
if (ThisBot != pBot && IsPlayerActiveInGame(ThisBot->Edict) && GetPlayerActiveClass(pBot->Player) != AVH_USER3_ALIEN_PLAYER2 && vDist2DSq(ThisBot->Edict->v.origin, ThisHive->FloorLocation) > sqrf(UTIL_MetresToGoldSrcUnits(15.0f)))
|
||||
{
|
||||
if (ThisBot->SecondaryBotTask.TaskType == TASK_DEFEND && ThisBot->SecondaryBotTask.TaskTarget == ThisHive->HiveEdict)
|
||||
{
|
||||
|
@ -6913,6 +6984,42 @@ void AIPlayerSetWantsAndNeedsAlienTask(AvHAIPlayer* pBot, AvHAIPlayerTask* Task)
|
|||
return;
|
||||
}
|
||||
|
||||
if (gpGlobals->time - pBot->LastCombatTime > 10.0f)
|
||||
{
|
||||
if (Task->TaskType == TASK_EVOLVE) { return; }
|
||||
|
||||
bool bInMiddleOfMove = false;
|
||||
|
||||
if (pBot->BotNavInfo.CurrentPath.size() > 0 && pBot->BotNavInfo.CurrentPathPoint < pBot->BotNavInfo.CurrentPath.size())
|
||||
{
|
||||
bot_path_node CurrentMove = pBot->BotNavInfo.CurrentPath[pBot->BotNavInfo.CurrentPathPoint];
|
||||
|
||||
bInMiddleOfMove = CurrentMove.flag != SAMPLE_POLYFLAGS_WALK;
|
||||
}
|
||||
|
||||
if (!bInMiddleOfMove)
|
||||
{
|
||||
if (!PlayerHasAlienUpgradeOfType(pBot->Edict, HIVE_TECH_DEFENCE) && AITAC_IsAlienUpgradeAvailableForTeam(pBot->Player->GetTeam(), HIVE_TECH_DEFENCE))
|
||||
{
|
||||
AITASK_SetEvolveTask(pBot, Task, pBot->CurrentFloorPosition, AlienGetDesiredUpgrade(pBot, HIVE_TECH_DEFENCE), true);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!PlayerHasAlienUpgradeOfType(pBot->Edict, HIVE_TECH_MOVEMENT) && AITAC_IsAlienUpgradeAvailableForTeam(pBot->Player->GetTeam(), HIVE_TECH_MOVEMENT))
|
||||
{
|
||||
AITASK_SetEvolveTask(pBot, Task, pBot->CurrentFloorPosition, AlienGetDesiredUpgrade(pBot, HIVE_TECH_MOVEMENT), true);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!PlayerHasAlienUpgradeOfType(pBot->Edict, HIVE_TECH_SENSORY) && AITAC_IsAlienUpgradeAvailableForTeam(pBot->Player->GetTeam(), HIVE_TECH_SENSORY))
|
||||
{
|
||||
AITASK_SetEvolveTask(pBot, Task, pBot->CurrentFloorPosition, AlienGetDesiredUpgrade(pBot, HIVE_TECH_SENSORY), true);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (CurrentHealth >= 1.0f) { return; }
|
||||
|
||||
bool bCanSelfHeal = (PlayerHasWeapon(pBot->Player, WEAPON_GORGE_HEALINGSPRAY) || PlayerHasWeapon(pBot->Player, WEAPON_FADE_METABOLIZE));
|
||||
|
|
|
@ -4,7 +4,24 @@
|
|||
#include "AvHPlayer.h"
|
||||
#include "AvHAIConstants.h"
|
||||
|
||||
// These define the bot's view frustum sides
|
||||
#define FRUSTUM_PLANE_TOP 0
|
||||
#define FRUSTUM_PLANE_BOTTOM 1
|
||||
#define FRUSTUM_PLANE_LEFT 2
|
||||
#define FRUSTUM_PLANE_RIGHT 3
|
||||
#define FRUSTUM_PLANE_NEAR 4
|
||||
#define FRUSTUM_PLANE_FAR 5
|
||||
|
||||
static const float BOT_FOV = 100.0f; // Bot's field of view;
|
||||
static const float BOT_MAX_VIEW = 9999.0f; // Bot's maximum view distance;
|
||||
static const float BOT_MIN_VIEW = 5.0f; // Bot's minimum view distance;
|
||||
static const float BOT_ASPECT_RATIO = 1.77778f; // Bot's view aspect ratio, 1.333333 for 4:3, 1.777778 for 16:9, 1.6 for 16:10;
|
||||
|
||||
static const float f_fnheight = 2.0f * tan((BOT_FOV * 0.0174532925f) * 0.5f) * BOT_MIN_VIEW;
|
||||
static const float f_fnwidth = f_fnheight * BOT_ASPECT_RATIO;
|
||||
|
||||
static const float f_ffheight = 2.0f * tan((BOT_FOV * 0.0174532925f) * 0.5f) * BOT_MAX_VIEW;
|
||||
static const float f_ffwidth = f_ffheight * BOT_ASPECT_RATIO;
|
||||
|
||||
|
||||
void BotJump(AvHAIPlayer* pBot);
|
||||
|
@ -47,6 +64,8 @@ void BotUpdateViewRotation(AvHAIPlayer* pBot, float DeltaTime);
|
|||
void BotUpdateView(AvHAIPlayer* pBot);
|
||||
void BotClearEnemyTrackingInfo(enemy_status* TrackingInfo);
|
||||
bool IsPlayerInBotFOV(AvHAIPlayer* Observer, edict_t* TargetPlayer);
|
||||
void UpdateAIPlayerViewFrustum(AvHAIPlayer* pBot);
|
||||
|
||||
|
||||
Vector GetVisiblePointOnPlayerFromObserver(edict_t* Observer, edict_t* TargetPlayer);
|
||||
|
||||
|
|
|
@ -12,6 +12,8 @@
|
|||
#include "../dlls/client.h"
|
||||
#include <time.h>
|
||||
|
||||
float MAX_MATCH_TIME = 7200.0f;
|
||||
|
||||
double last_think_time = 0.0;
|
||||
|
||||
vector<AvHAIPlayer> ActiveAIPlayers;
|
||||
|
@ -125,6 +127,21 @@ void AIMGR_UpdateAIPlayerCounts()
|
|||
// Don't add or remove bots too quickly, otherwise it can cause lag or even overflows
|
||||
if (gpGlobals->time - LastAIPlayerCountUpdate < 0.2f) { return; }
|
||||
|
||||
LastAIPlayerCountUpdate = gpGlobals->time;
|
||||
|
||||
bool bMatchExceededMaxLength = (gpGlobals->time - AIStartedTime) > MAX_MATCH_TIME;
|
||||
|
||||
// If bots are disabled, ensure we've removed all bots from the game
|
||||
if (!AIMGR_IsBotEnabled() || (bMatchExceededMaxLength && AIMGR_GetNumActiveHumanPlayers() == 0))
|
||||
{
|
||||
if (AIMGR_GetNumAIPlayers() > 0)
|
||||
{
|
||||
AIMGR_RemoveAIPlayerFromTeam(0);
|
||||
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (!AIMGR_ShouldStartPlayerBalancing()) { return; }
|
||||
|
||||
// If game has ended, kick bots that have dropped back to the ready room
|
||||
|
@ -134,18 +151,7 @@ void AIMGR_UpdateAIPlayerCounts()
|
|||
return;
|
||||
}
|
||||
|
||||
LastAIPlayerCountUpdate = gpGlobals->time;
|
||||
|
||||
// If bots are disabled, ensure we've removed all bots from the game
|
||||
if (!AIMGR_IsBotEnabled())
|
||||
{
|
||||
if (AIMGR_GetNumAIPlayers() > 0)
|
||||
{
|
||||
AIMGR_RemoveAIPlayerFromTeam(0);
|
||||
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
BotFillTiming CurrentFillTiming = CONFIG_GetBotFillTiming();
|
||||
|
||||
|
@ -810,6 +816,40 @@ int AIMGR_GetNumHumanPlayersOnTeam(AvHTeamNumber Team)
|
|||
return Result;
|
||||
}
|
||||
|
||||
int AIMGR_GetNumHumanPlayersOnServer()
|
||||
{
|
||||
int Result = 0;
|
||||
|
||||
for (int i = 1; i <= gpGlobals->maxClients; i++)
|
||||
{
|
||||
edict_t* PlayerEdict = INDEXENT(i);
|
||||
|
||||
if (!FNullEnt(PlayerEdict) && IsPlayerHuman(PlayerEdict))
|
||||
{
|
||||
Result++;
|
||||
}
|
||||
}
|
||||
|
||||
return Result;
|
||||
}
|
||||
|
||||
int AIMGR_GetNumActiveHumanPlayers()
|
||||
{
|
||||
int Result = 0;
|
||||
|
||||
for (int i = 1; i <= gpGlobals->maxClients; i++)
|
||||
{
|
||||
edict_t* PlayerEdict = INDEXENT(i);
|
||||
|
||||
if (!FNullEnt(PlayerEdict) && IsPlayerHuman(PlayerEdict) && PlayerEdict->v.team != TEAM_IND)
|
||||
{
|
||||
Result++;
|
||||
}
|
||||
}
|
||||
|
||||
return Result;
|
||||
}
|
||||
|
||||
int AIMGR_GetNumAIPlayersWithRoleOnTeam(AvHTeamNumber Team, AvHAIBotRole Role, AvHAIPlayer* IgnoreAIPlayer)
|
||||
{
|
||||
int Result = 0;
|
||||
|
|
|
@ -68,6 +68,8 @@ void AIDEBUG_TestPathFind();
|
|||
|
||||
int AIMGR_GetNumAIPlayersOnTeam(AvHTeamNumber Team);
|
||||
int AIMGR_GetNumHumanPlayersOnTeam(AvHTeamNumber Team);
|
||||
int AIMGR_GetNumHumanPlayersOnServer();
|
||||
int AIMGR_GetNumActiveHumanPlayers();
|
||||
|
||||
int AIMGR_GetNumAIPlayersWithRoleOnTeam(AvHTeamNumber Team, AvHAIBotRole Role, AvHAIPlayer* IgnoreAIPlayer);
|
||||
|
||||
|
|
|
@ -4638,7 +4638,7 @@ bool AITAC_ShouldBotBuildHive(AvHAIPlayer* pBot, AvHAIHiveDefinition** EligibleH
|
|||
|
||||
float HiveCost = BALANCE_VAR(kHiveCost);
|
||||
|
||||
if (!IsPlayerGorge(pBot->Edict))
|
||||
if (GetPlayerActiveClass(pBot->Player) != AVH_USER3_ALIEN_PLAYER2)
|
||||
{
|
||||
HiveCost += BALANCE_VAR(kGorgeCost);
|
||||
}
|
||||
|
@ -4655,7 +4655,7 @@ bool AITAC_ShouldBotBuildHive(AvHAIPlayer* pBot, AvHAIHiveDefinition** EligibleH
|
|||
|
||||
// If we're a higher lifeform, ensure we can't leave this to someone else before considering losing those resources
|
||||
// We will ignore humans and third party bots, because we don't know if they will drop the hive or not. Not everyone can be as team-spirited as us...
|
||||
if (!IsPlayerSkulk(pBot->Edict) && !IsPlayerGorge(pBot->Edict))
|
||||
if (!IsPlayerSkulk(pBot->Edict) && GetPlayerActiveClass(pBot->Player) != AVH_USER3_ALIEN_PLAYER2)
|
||||
{
|
||||
vector<AvHAIPlayer*> OtherAITeamMates = AIMGR_GetAIPlayersOnTeam(BotTeam);
|
||||
|
||||
|
@ -4813,7 +4813,7 @@ bool AITAC_IsAlienCapperNeeded(AvHAIPlayer* pBot)
|
|||
|
||||
float ResourcesNeeded = BALANCE_VAR(kResourceTowerCost);
|
||||
|
||||
if (!IsPlayerGorge(pBot->Edict))
|
||||
if (GetPlayerActiveClass(pBot->Player) != AVH_USER3_ALIEN_PLAYER2)
|
||||
{
|
||||
ResourcesNeeded += BALANCE_VAR(kGorgeCost);
|
||||
}
|
||||
|
@ -4823,8 +4823,8 @@ bool AITAC_IsAlienCapperNeeded(AvHAIPlayer* pBot)
|
|||
if (EnemyNodeOwnership < 0.35f) { return false; }
|
||||
}
|
||||
|
||||
bool bIsHigherLifeform = (!IsPlayerSkulk(pBot->Edict) && !IsPlayerGorge(pBot->Edict));
|
||||
bool bIsBuilder = (IsPlayerGorge(pBot->Edict) && pBot->BotRole == BOT_ROLE_BUILDER);
|
||||
bool bIsHigherLifeform = (!IsPlayerSkulk(pBot->Edict) && GetPlayerActiveClass(pBot->Player) != AVH_USER3_ALIEN_PLAYER2);
|
||||
bool bIsBuilder = (GetPlayerActiveClass(pBot->Player) == AVH_USER3_ALIEN_PLAYER2 && pBot->BotRole == BOT_ROLE_BUILDER);
|
||||
|
||||
if (bIsHigherLifeform || bIsBuilder)
|
||||
{
|
||||
|
@ -4919,7 +4919,7 @@ bool AITAC_IsAlienBuilderNeeded(AvHAIPlayer* pBot)
|
|||
}
|
||||
|
||||
// Don't build if we're a higher lifeform and there are others who could do the job instead
|
||||
if (!IsPlayerSkulk(pBot->Edict) && !IsPlayerGorge(pBot->Edict))
|
||||
if (!IsPlayerSkulk(pBot->Edict) && GetPlayerActiveClass(pBot->Player) != AVH_USER3_ALIEN_PLAYER2)
|
||||
{
|
||||
int NumSkulks = AITAC_GetNumPlayersOnTeamOfClass(BotTeam, AVH_USER3_ALIEN_PLAYER1, nullptr);
|
||||
int NumGorges = AITAC_GetNumPlayersOnTeamOfClass(BotTeam, AVH_USER3_ALIEN_PLAYER2, nullptr);
|
||||
|
|
|
@ -84,6 +84,55 @@ void AITASK_OnCompleteCommanderTask(AvHAIPlayer* pBot, AvHAIPlayerTask* Task)
|
|||
|
||||
if (OldTaskType == TASK_MOVE)
|
||||
{
|
||||
AvHTeamNumber BotTeam = pBot->Player->GetTeam();
|
||||
AvHTeamNumber EnemyTeam = AIMGR_GetEnemyTeam(BotTeam);
|
||||
|
||||
if (AIMGR_GetTeamType(EnemyTeam) == AVH_CLASS_TYPE_ALIEN)
|
||||
{
|
||||
const AvHAIHiveDefinition* NearestHive = AITAC_GetHiveNearestLocation(pBot->Edict->v.origin);
|
||||
|
||||
if (NearestHive && vDist2DSq(NearestHive->FloorLocation, pBot->Edict->v.origin) < sqrf(UTIL_MetresToGoldSrcUnits(15.0f)))
|
||||
{
|
||||
if (NearestHive->Status == HIVE_STATUS_UNBUILT)
|
||||
{
|
||||
AITASK_SetSecureHiveTask(pBot, Task, NearestHive->HiveEdict, NearestHive->FloorLocation, false);
|
||||
Task->bIssuedByCommander = true;
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (UTIL_PlayerHasLOSToEntity(pBot->Edict, NearestHive->HiveEdict, UTIL_MetresToGoldSrcUnits(15.0f), false))
|
||||
{
|
||||
AITASK_SetAttackTask(pBot, Task, NearestHive->HiveEdict, false);
|
||||
Task->bIssuedByCommander = true;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (vDist2DSq(pBot->Edict->v.origin, AITAC_GetTeamStartingLocation(EnemyTeam)) < sqrf(UTIL_MetresToGoldSrcUnits(10.0f)))
|
||||
{
|
||||
DeployableSearchFilter EnemyStuffFilter;
|
||||
EnemyStuffFilter.DeployableTypes = SEARCH_ALL_STRUCTURES;
|
||||
EnemyStuffFilter.DeployableTeam = EnemyTeam;
|
||||
EnemyStuffFilter.ReachabilityFlags = pBot->BotNavInfo.NavProfile.ReachabilityFlag;
|
||||
EnemyStuffFilter.ReachabilityTeam = (AvHTeamNumber)pBot->Edict->v.team;
|
||||
EnemyStuffFilter.MaxSearchRadius = UTIL_MetresToGoldSrcUnits(10.0f);
|
||||
|
||||
AvHAIBuildableStructure NearbyEnemyStructure = AITAC_FindClosestDeployableToLocation(AITAC_GetTeamStartingLocation(EnemyTeam), &EnemyStuffFilter);
|
||||
|
||||
if (NearbyEnemyStructure.IsValid())
|
||||
{
|
||||
AITASK_SetAttackTask(pBot, Task, NearbyEnemyStructure.edict, false);
|
||||
Task->bIssuedByCommander = true;
|
||||
return;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
DeployableSearchFilter EnemyResTowerFilter;
|
||||
EnemyResTowerFilter.DeployableTypes = SEARCH_ANY_RES_TOWER;
|
||||
EnemyResTowerFilter.DeployableTeam = (AIMGR_GetEnemyTeam(pBot->Player->GetTeam()));
|
||||
|
@ -972,6 +1021,18 @@ bool AITASK_IsEvolveTaskStillValid(AvHAIPlayer* pBot, AvHAIPlayerTask* Task)
|
|||
return !IsPlayerFade(pBot->Edict) && pBot->Player->GetResources() >= BALANCE_VAR(kFadeCost);
|
||||
case ALIEN_LIFEFORM_FIVE:
|
||||
return !IsPlayerOnos(pBot->Edict) && pBot->Player->GetResources() >= BALANCE_VAR(kOnosCost) && (AITAC_GetNumPlayersOnTeamOfClass(pBot->Player->GetTeam(), AVH_USER3_ALIEN_PLAYER5, nullptr) < 2);
|
||||
case ALIEN_EVOLUTION_ONE:
|
||||
case ALIEN_EVOLUTION_TWO:
|
||||
case ALIEN_EVOLUTION_THREE:
|
||||
return (!PlayerHasAlienUpgradeOfType(pBot->Edict, HIVE_TECH_DEFENCE) && AITAC_IsAlienUpgradeAvailableForTeam(pBot->Player->GetTeam(), HIVE_TECH_DEFENCE));
|
||||
case ALIEN_EVOLUTION_SEVEN:
|
||||
case ALIEN_EVOLUTION_EIGHT:
|
||||
case ALIEN_EVOLUTION_NINE:
|
||||
return (!PlayerHasAlienUpgradeOfType(pBot->Edict, HIVE_TECH_MOVEMENT) && AITAC_IsAlienUpgradeAvailableForTeam(pBot->Player->GetTeam(), HIVE_TECH_MOVEMENT));
|
||||
case ALIEN_EVOLUTION_TEN:
|
||||
case ALIEN_EVOLUTION_ELEVEN:
|
||||
case ALIEN_EVOLUTION_TWELVE:
|
||||
return (!PlayerHasAlienUpgradeOfType(pBot->Edict, HIVE_TECH_SENSORY) && AITAC_IsAlienUpgradeAvailableForTeam(pBot->Player->GetTeam(), HIVE_TECH_SENSORY));
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
|
@ -1003,7 +1064,7 @@ bool AITASK_IsAlienHealTaskStillValid(AvHAIPlayer* pBot, AvHAIPlayerTask* Task)
|
|||
{
|
||||
if (!Task->TaskTarget || FNullEnt(Task->TaskTarget) || (Task->TaskTarget->v.effects & EF_NODRAW) || Task->TaskTarget->v.deadflag != DEAD_NO) { return false; }
|
||||
|
||||
if (!IsPlayerGorge(pBot->Edict)) { return false; }
|
||||
if (GetPlayerActiveClass(pBot->Player) != AVH_USER3_ALIEN_PLAYER2) { return false; }
|
||||
|
||||
if (GetPlayerOverallHealthPercent(Task->TaskTarget) >= 0.99f) { return false; }
|
||||
|
||||
|
@ -1331,7 +1392,7 @@ void BotProgressReinforceStructureTask(AvHAIPlayer* pBot, AvHAIPlayerTask* Task)
|
|||
if (!vIsZero(Task->TaskLocation))
|
||||
{
|
||||
float ResourceCost = UTIL_GetCostOfStructureType(NextStructure);
|
||||
if (!IsPlayerGorge(pBot->Edict))
|
||||
if (GetPlayerActiveClass(pBot->Player) != AVH_USER3_ALIEN_PLAYER2)
|
||||
{
|
||||
ResourceCost += BALANCE_VAR(kGorgeCost);
|
||||
}
|
||||
|
@ -1345,7 +1406,7 @@ void BotProgressReinforceStructureTask(AvHAIPlayer* pBot, AvHAIPlayerTask* Task)
|
|||
}
|
||||
|
||||
// We have nothing to build, or we don't have enough resources yet, see if there's any unfinished structures we can finish off
|
||||
if (IsPlayerGorge(pBot->Edict))
|
||||
if (GetPlayerActiveClass(pBot->Player) == AVH_USER3_ALIEN_PLAYER2)
|
||||
{
|
||||
DeployableSearchFilter UnfinishedFilter;
|
||||
UnfinishedFilter.DeployableTeam = BotTeam;
|
||||
|
@ -1965,7 +2026,7 @@ void AlienProgressBuildHiveTask(AvHAIPlayer* pBot, AvHAIPlayerTask* Task)
|
|||
|
||||
int ResRequired = UTIL_GetCostOfStructureType(Task->StructureType);
|
||||
|
||||
if (!IsPlayerGorge(pBot->Edict))
|
||||
if (GetPlayerActiveClass(pBot->Player) != AVH_USER3_ALIEN_PLAYER2)
|
||||
{
|
||||
ResRequired += BALANCE_VAR(kGorgeCost);
|
||||
}
|
||||
|
@ -2023,7 +2084,7 @@ void AlienProgressBuildTask(AvHAIPlayer* pBot, AvHAIPlayerTask* Task)
|
|||
|
||||
int ResRequired = UTIL_GetCostOfStructureType(Task->StructureType);
|
||||
|
||||
if (!IsPlayerGorge(pBot->Edict))
|
||||
if (GetPlayerActiveClass(pBot->Player) != AVH_USER3_ALIEN_PLAYER2)
|
||||
{
|
||||
ResRequired += BALANCE_VAR(kGorgeCost);
|
||||
}
|
||||
|
@ -2064,7 +2125,6 @@ void BotAlienPlaceChamber(AvHAIPlayer* pBot, AvHAIPlayerTask* Task, AvHAIDeploya
|
|||
{
|
||||
if (vIsZero(Task->TaskLocation) || DesiredStructure == STRUCTURE_NONE) { return; }
|
||||
|
||||
|
||||
if (Task->ActiveBuildInfo.BuildStatus == BUILD_ATTEMPT_PENDING) { return; }
|
||||
|
||||
float DistFromBuildLocation = vDist2DSq(pBot->Edict->v.origin, Task->TaskLocation);
|
||||
|
@ -2092,7 +2152,7 @@ void BotAlienPlaceChamber(AvHAIPlayer* pBot, AvHAIPlayerTask* Task, AvHAIDeploya
|
|||
|
||||
int ResRequired = UTIL_GetCostOfStructureType(DesiredStructure);
|
||||
|
||||
if (!IsPlayerGorge(pBot->Edict))
|
||||
if (GetPlayerActiveClass(pBot->Player) != AVH_USER3_ALIEN_PLAYER2)
|
||||
{
|
||||
ResRequired += BALANCE_VAR(kGorgeCost);
|
||||
}
|
||||
|
@ -2102,7 +2162,7 @@ void BotAlienPlaceChamber(AvHAIPlayer* pBot, AvHAIPlayerTask* Task, AvHAIDeploya
|
|||
return;
|
||||
}
|
||||
|
||||
if (!IsPlayerGorge(pBot->Edict))
|
||||
if (GetPlayerActiveClass(pBot->Player) != AVH_USER3_ALIEN_PLAYER2)
|
||||
{
|
||||
BotEvolveLifeform(pBot, pBot->CurrentFloorPosition, ALIEN_LIFEFORM_TWO);
|
||||
return;
|
||||
|
@ -2145,7 +2205,7 @@ void BotAlienBuildResTower(AvHAIPlayer* pBot, AvHAIPlayerTask* Task, const AvHAI
|
|||
|
||||
int ResRequired = UTIL_GetCostOfStructureType(STRUCTURE_ALIEN_RESTOWER);
|
||||
|
||||
if (!IsPlayerGorge(pBot->Edict))
|
||||
if (GetPlayerActiveClass(pBot->Player) != AVH_USER3_ALIEN_PLAYER2)
|
||||
{
|
||||
ResRequired += BALANCE_VAR(kGorgeCost);
|
||||
}
|
||||
|
@ -2157,7 +2217,7 @@ void BotAlienBuildResTower(AvHAIPlayer* pBot, AvHAIPlayerTask* Task, const AvHAI
|
|||
return;
|
||||
}
|
||||
|
||||
if (!IsPlayerGorge(pBot->Edict))
|
||||
if (GetPlayerActiveClass(pBot->Player) != AVH_USER3_ALIEN_PLAYER2)
|
||||
{
|
||||
BotEvolveLifeform(pBot, pBot->CurrentFloorPosition, ALIEN_LIFEFORM_TWO);
|
||||
return;
|
||||
|
@ -2200,7 +2260,7 @@ void BotAlienBuildHive(AvHAIPlayer* pBot, AvHAIPlayerTask* Task, const AvHAIHive
|
|||
{
|
||||
int ResRequired = UTIL_GetCostOfStructureType(STRUCTURE_ALIEN_HIVE);
|
||||
|
||||
if (!IsPlayerGorge(pBot->Edict))
|
||||
if (GetPlayerActiveClass(pBot->Player) != AVH_USER3_ALIEN_PLAYER2)
|
||||
{
|
||||
ResRequired += BALANCE_VAR(kGorgeCost);
|
||||
}
|
||||
|
@ -2210,7 +2270,7 @@ void BotAlienBuildHive(AvHAIPlayer* pBot, AvHAIPlayerTask* Task, const AvHAIHive
|
|||
return;
|
||||
}
|
||||
|
||||
if (!IsPlayerGorge(pBot->Edict))
|
||||
if (GetPlayerActiveClass(pBot->Player) != AVH_USER3_ALIEN_PLAYER2)
|
||||
{
|
||||
BotEvolveLifeform(pBot, pBot->CurrentFloorPosition, ALIEN_LIFEFORM_TWO);
|
||||
return;
|
||||
|
@ -2325,7 +2385,7 @@ void AlienProgressCapResNodeTask(AvHAIPlayer* pBot, AvHAIPlayerTask* Task)
|
|||
{
|
||||
// Node is empty and not capped by either side
|
||||
|
||||
int NumResourcesRequired = (IsPlayerGorge(pBot->Edict) ? BALANCE_VAR(kResourceTowerCost) : (BALANCE_VAR(kResourceTowerCost) + BALANCE_VAR(kGorgeCost)));
|
||||
int NumResourcesRequired = (GetPlayerActiveClass(pBot->Player) == AVH_USER3_ALIEN_PLAYER2) ? BALANCE_VAR(kResourceTowerCost) : (BALANCE_VAR(kResourceTowerCost) + BALANCE_VAR(kGorgeCost));
|
||||
|
||||
// We have enough resources to place the tower (includes cost of evolving to gorge if necessary)
|
||||
if (pBot->Player->GetResources() >= NumResourcesRequired)
|
||||
|
|
Loading…
Reference in a new issue