Ladder fix + relocation fixes

* Improved ladder climbing, especially for skulks
* Fixed issues with bots getting confused when switching commanders during a relocation
This commit is contained in:
RGreenlees 2024-05-28 22:58:37 +01:00 committed by pierow
parent 9a4a6b3660
commit 36318cd1d4
8 changed files with 359 additions and 108 deletions

View file

@ -3239,7 +3239,7 @@ bool AICOMM_CheckForNextSupportAction(AvHAIPlayer* pBot)
} }
} }
bool bSuccess = AICOMM_DeployStructure(pBot, StructureToDeploy, ProjectedDeployLocation, STRUCTURE_PURPOSE_NONE); bool bSuccess = AICOMM_DeployStructure(pBot, StructureToDeploy, ProjectedDeployLocation, STRUCTURE_PURPOSE_GENERAL);
if (bSuccess) if (bSuccess)
{ {
@ -3252,7 +3252,7 @@ bool AICOMM_CheckForNextSupportAction(AvHAIPlayer* pBot)
if (!vIsZero(DeployLocation)) if (!vIsZero(DeployLocation))
{ {
bool bSuccess = AICOMM_DeployStructure(pBot, StructureToDeploy, DeployLocation, STRUCTURE_PURPOSE_NONE); bool bSuccess = AICOMM_DeployStructure(pBot, StructureToDeploy, DeployLocation, STRUCTURE_PURPOSE_GENERAL);
if (bSuccess) if (bSuccess)
{ {
@ -3265,7 +3265,7 @@ bool AICOMM_CheckForNextSupportAction(AvHAIPlayer* pBot)
if (!vIsZero(DeployLocation)) if (!vIsZero(DeployLocation))
{ {
bool bSuccess = AICOMM_DeployStructure(pBot, StructureToDeploy, DeployLocation, STRUCTURE_PURPOSE_NONE); bool bSuccess = AICOMM_DeployStructure(pBot, StructureToDeploy, DeployLocation, STRUCTURE_PURPOSE_GENERAL);
if (bSuccess) if (bSuccess)
{ {
@ -3399,6 +3399,13 @@ void AICOMM_CommanderThink(AvHAIPlayer* pBot)
if (!vIsZero(pBot->RelocationSpot)) if (!vIsZero(pBot->RelocationSpot))
{ {
vector<AvHAIPlayer*> AllMarineBots = AIMGR_GetAIPlayersOnTeam(pBot->Player->GetTeam());
for (auto it = AllMarineBots.begin(); it != AllMarineBots.end(); it++)
{
(*it)->RelocationSpot = pBot->RelocationSpot;
}
const AvHAIHiveDefinition* RelocationHive = AITAC_GetHiveNearestLocation(pBot->RelocationSpot); const AvHAIHiveDefinition* RelocationHive = AITAC_GetHiveNearestLocation(pBot->RelocationSpot);
if (RelocationHive) if (RelocationHive)
@ -4026,19 +4033,29 @@ bool AICOMM_CheckForNextRelocationAction(AvHAIPlayer* pBot)
{ {
Vector BuildPoint = AITAC_GetRandomBuildHintInLocation(STRUCTURE_MARINE_COMMCHAIR, pBot->RelocationSpot, UTIL_MetresToGoldSrcUnits(10.0f)); Vector BuildPoint = AITAC_GetRandomBuildHintInLocation(STRUCTURE_MARINE_COMMCHAIR, pBot->RelocationSpot, UTIL_MetresToGoldSrcUnits(10.0f));
if (vIsZero(BuildPoint)) if (!vIsZero(BuildPoint))
{ {
BuildPoint = UTIL_GetRandomPointOnNavmeshInRadius(GetBaseNavProfile(STRUCTURE_BASE_NAV_PROFILE), RelocationPoint, UTIL_MetresToGoldSrcUnits(2.0f)); bool bSuccess = AICOMM_DeployStructure(pBot, STRUCTURE_MARINE_COMMCHAIR, BuildPoint, STRUCTURE_PURPOSE_BASE);
if (bSuccess) { return true; }
} }
if (vIsZero(BuildPoint)) BuildPoint = UTIL_GetRandomPointOnNavmeshInRadius(GetBaseNavProfile(STRUCTURE_BASE_NAV_PROFILE), pBot->RelocationSpot, UTIL_MetresToGoldSrcUnits(2.0f));
{
BuildPoint = UTIL_ProjectPointToNavmesh(RelocationPoint, Vector(500.0f, 500.0f, 500.0f), GetBaseNavProfile(STRUCTURE_BASE_NAV_PROFILE));
}
if (!vIsZero(BuildPoint)) if (!vIsZero(BuildPoint))
{ {
return AICOMM_DeployStructure(pBot, STRUCTURE_MARINE_COMMCHAIR, BuildPoint, STRUCTURE_PURPOSE_BASE); bool bSuccess = AICOMM_DeployStructure(pBot, STRUCTURE_MARINE_COMMCHAIR, BuildPoint, STRUCTURE_PURPOSE_BASE);
if (bSuccess) { return true; }
}
BuildPoint = UTIL_GetRandomPointOnNavmeshInRadius(GetBaseNavProfile(STRUCTURE_BASE_NAV_PROFILE), pBot->RelocationSpot, UTIL_MetresToGoldSrcUnits(10.0f));
if (!vIsZero(BuildPoint))
{
bool bSuccess = AICOMM_DeployStructure(pBot, STRUCTURE_MARINE_COMMCHAIR, BuildPoint, STRUCTURE_PURPOSE_BASE);
if (bSuccess) { return true; }
} }
return false; return false;

View file

@ -3848,7 +3848,34 @@ void JumpMove(AvHAIPlayer* pBot, const Vector StartPoint, const Vector EndPoint)
} }
} }
void LadderMove(AvHAIPlayer* pBot, const Vector StartPoint, const Vector EndPoint, float RequiredClimbHeight, unsigned char NextArea) void MountLadderMove(AvHAIPlayer* pBot, edict_t* LadderToMount)
{
Vector LadderNormal = UTIL_GetLadderNormal(pBot->Edict->v.origin, LadderToMount);
LadderNormal = UTIL_GetVectorNormal2D(LadderNormal);
Vector NearestPointOnLadder = UTIL_GetClosestPointOnEntityToLocation(pBot->Edict->v.origin, LadderToMount);
Vector OrientationToLadder = UTIL_GetVectorNormal2D(pBot->Edict->v.origin - NearestPointOnLadder);
if (UTIL_GetDotProduct2D(LadderNormal, OrientationToLadder) < 0.8f)
{
Vector MovePoint = NearestPointOnLadder + (LadderNormal * 32.0f);
pBot->desiredMovementDir = UTIL_GetVectorNormal2D(MovePoint - pBot->Edict->v.origin);
}
else
{
Vector nearestLadderPoint = UTIL_GetCentreOfEntity(LadderToMount);
nearestLadderPoint.z = pBot->Edict->v.origin.z;
pBot->desiredMovementDir = UTIL_GetVectorNormal2D(NearestPointOnLadder - pBot->Edict->v.origin);
}
Vector LookPoint = NearestPointOnLadder;
BotLookAt(pBot, LookPoint, true);
}
void SkulkLadderMove(AvHAIPlayer* pBot, const Vector StartPoint, const Vector EndPoint, float RequiredClimbHeight, unsigned char NextArea)
{ {
edict_t* pEdict = pBot->Edict; edict_t* pEdict = pBot->Edict;
AvHPlayer* AIPlayer = pBot->Player; AvHPlayer* AIPlayer = pBot->Player;
@ -3857,11 +3884,6 @@ void LadderMove(AvHAIPlayer* pBot, const Vector StartPoint, const Vector EndPoin
bool bIsGoingUpLadder = (EndPoint.z > StartPoint.z); bool bIsGoingUpLadder = (EndPoint.z > StartPoint.z);
// Stop holding crouch if we're a skulk so we can climb up/down
if (IsPlayerSkulk(pBot->Edict))
{
pBot->Button &= ~IN_DUCK;
edict_t* Ladder = UTIL_GetNearestLadderAtPoint(StartPoint); edict_t* Ladder = UTIL_GetNearestLadderAtPoint(StartPoint);
if (!FNullEnt(Ladder)) if (!FNullEnt(Ladder))
@ -3870,7 +3892,7 @@ void LadderMove(AvHAIPlayer* pBot, const Vector StartPoint, const Vector EndPoin
Vector LadderEnd = Ladder->v.absmax; Vector LadderEnd = Ladder->v.absmax;
LadderEnd.z = LadderStart.z; LadderEnd.z = LadderStart.z;
// Basically, if we're directly climbing up or down the ladder, treat it like a wall. The below test will be false if the ladder is to one side // The below test will be false if the ladder is to one side, hence do not try to climb it like a wall
if (vIntersects2D(StartPoint, EndPoint, LadderStart, LadderEnd)) if (vIntersects2D(StartPoint, EndPoint, LadderStart, LadderEnd))
{ {
if (bIsGoingUpLadder) if (bIsGoingUpLadder)
@ -3884,20 +3906,150 @@ void LadderMove(AvHAIPlayer* pBot, const Vector StartPoint, const Vector EndPoin
return; return;
} }
} }
// Stop holding crouch so we can wall-climb
pBot->Button &= ~IN_DUCK;
if (pBot->Edict->v.origin.z > RequiredClimbHeight)
{
if (UTIL_QuickHullTrace(pBot->Edict, pBot->Edict->v.origin, EndPoint + Vector(0.0f, 0.0f, 16.0f)))
{
pBot->desiredMovementDir = vForward;
BotLookAt(pBot, EndPoint + Vector(0.0f, 0.0f, 50.0f));
return;
} }
}
if (pBot->Edict->v.origin.z > Ladder->v.absmax.z)
{
WallClimbMove(pBot, StartPoint, EndPoint, RequiredClimbHeight);
return;
}
if (!IsPlayerOnLadder(pBot->Edict))
{
MountLadderMove(pBot, Ladder);
return;
}
pBot->Button |= IN_WALK;
Vector CurrentLadderNormal = UTIL_GetNearestSurfaceNormal(pBot->Edict->v.origin);
Vector LadderRightNormal = UTIL_GetVectorNormal(UTIL_GetCrossProduct(CurrentLadderNormal, UP_VECTOR));
Vector ClimbRightNormal = LadderRightNormal;
if (bIsGoingUpLadder)
{
ClimbRightNormal = -LadderRightNormal;
}
if (IsPlayerClimbingWall(pBot->Edict))
{
Vector StartLeftTrace = pBot->CollisionHullTopLocation - (ClimbRightNormal * GetPlayerRadius(pBot->Player));
Vector StartRightTrace = pBot->CollisionHullTopLocation + (ClimbRightNormal * GetPlayerRadius(pBot->Player));
Vector EndLeftTrace = (bIsGoingUpLadder) ? StartLeftTrace + Vector(0.0f, 0.0f, 32.0f) : StartLeftTrace - Vector(0.0f, 0.0f, 32.0f);
Vector EndRightTrace = (bIsGoingUpLadder) ? StartRightTrace + Vector(0.0f, 0.0f, 32.0f) : StartRightTrace - Vector(0.0f, 0.0f, 32.0f);
bool bBlockedLeft = !UTIL_QuickHullTrace(pEdict, StartLeftTrace, EndLeftTrace, head_hull);
bool bBlockedRight = !UTIL_QuickHullTrace(pEdict, StartRightTrace, EndRightTrace, head_hull);
if (bBlockedLeft && bBlockedRight)
{
Vector LadderCentre = UTIL_GetCentreOfEntity(Ladder);
int Side = vPointOnLine(LadderCentre, LadderCentre + CurrentLadderNormal, pBot->Edict->v.origin);
if (Side > 0)
{
pBot->desiredMovementDir = -LadderRightNormal;
}
else
{
pBot->desiredMovementDir = LadderRightNormal;
}
Vector LookLocation = pBot->Edict->v.origin - (CurrentLadderNormal * 50.0f);
LookLocation.z = RequiredClimbHeight + 100.0f;
BotMoveLookAt(pBot, LookLocation, true);
return;
}
// If we are blocked going up the ladder, face the ladder and slide left/right to avoid blockage
if (bBlockedLeft)
{
Vector LookLocation = pBot->Edict->v.origin - (CurrentLadderNormal * 50.0f);
LookLocation.z = RequiredClimbHeight + 100.0f;
BotMoveLookAt(pBot, LookLocation, true);
pBot->desiredMovementDir = ClimbRightNormal;
return;
}
if (bBlockedRight)
{
Vector LookLocation = pBot->Edict->v.origin - (CurrentLadderNormal * 50.0f);
LookLocation.z = RequiredClimbHeight + 100.0f;
BotMoveLookAt(pBot, LookLocation, true);
pBot->desiredMovementDir = -ClimbRightNormal;
return;
}
}
Vector LookLocation = pBot->Edict->v.origin - (CurrentLadderNormal * 50.0f);
LookLocation.z = (bIsGoingUpLadder) ? RequiredClimbHeight + 100.0f : Ladder->v.absmin.z;
BotMoveLookAt(pBot, LookLocation, true);
pBot->desiredMovementDir = -CurrentLadderNormal;
Vector CurrentVelocity = UTIL_GetVectorNormal2D(pBot->Edict->v.velocity);
if (UTIL_GetDotProduct2D(pBot->desiredMovementDir, CurrentVelocity) < 0.5f)
{
float ZVelocity = pBot->Edict->v.velocity.z;
float SpeedXY = pBot->Edict->v.velocity.Length2D();
pBot->Edict->v.velocity = pBot->desiredMovementDir * SpeedXY;
pBot->Edict->v.velocity.z = ZVelocity;
}
}
void LadderMove(AvHAIPlayer* pBot, const Vector StartPoint, const Vector EndPoint, float RequiredClimbHeight, unsigned char NextArea)
{
// Basically, if we're a skulk and are directly climbing up or down the ladder, treat it like a basic wall climb
if (IsPlayerSkulk(pBot->Edict))
{
SkulkLadderMove(pBot, StartPoint, EndPoint, RequiredClimbHeight, NextArea);
return;
}
edict_t* Ladder = UTIL_GetNearestLadderAtPoint(pBot->Edict->v.origin);
if (FNullEnt(Ladder)) { return; }
edict_t* pEdict = pBot->Edict;
AvHPlayer* AIPlayer = pBot->Player;
const Vector vForward = UTIL_GetVectorNormal2D(EndPoint - StartPoint);
bool bIsGoingUpLadder = (EndPoint.z > StartPoint.z);
if (IsPlayerOnLadder(pBot->Edict)) if (IsPlayerOnLadder(pBot->Edict))
{ {
// We're on the ladder and actively climbing // We're on the ladder and actively climbing
Vector CurrentLadderNormal; Vector CurrentLadderNormal;
if (IsPlayerSkulk(pBot->Edict)) if (pBot->Edict->v.origin.z > UTIL_GetNearestLadderTopPoint(pEdict).z)
{ {
CurrentLadderNormal = UTIL_GetNearestSurfaceNormal(pBot->Edict->v.origin); CurrentLadderNormal = UTIL_GetNearestLadderNormal(pBot->CollisionHullBottomLocation + Vector(0.0f, 0.0f, 5.0f));
} }
else else
{ {
CurrentLadderNormal = UTIL_GetNearestLadderNormal(pBot->CollisionHullBottomLocation + Vector(0.0f, 0.0f, 5.0f)); CurrentLadderNormal = UTIL_GetNearestLadderNormal(pBot->Edict->v.origin);
} }
CurrentLadderNormal = UTIL_GetVectorNormal2D(CurrentLadderNormal); CurrentLadderNormal = UTIL_GetVectorNormal2D(CurrentLadderNormal);
@ -3948,7 +4100,7 @@ void LadderMove(AvHAIPlayer* pBot, const Vector StartPoint, const Vector EndPoin
Vector LookLocation = EndPoint; Vector LookLocation = EndPoint;
LookLocation.z = pBot->CurrentEyePosition.z + 64.0f; LookLocation.z = pBot->CurrentEyePosition.z + 64.0f;
BotMoveLookAt(pBot, LookLocation); BotMoveLookAt(pBot, LookLocation, true);
// If the get-off point is opposite the ladder, then jump to get to it // If the get-off point is opposite the ladder, then jump to get to it
if (UTIL_GetDotProduct(CurrentLadderNormal, vForward) > 0.75f) if (UTIL_GetDotProduct(CurrentLadderNormal, vForward) > 0.75f)
@ -3956,18 +4108,15 @@ void LadderMove(AvHAIPlayer* pBot, const Vector StartPoint, const Vector EndPoin
BotJump(pBot); BotJump(pBot);
} }
if (!IsPlayerGorge(pEdict) && !IsPlayerLerk(pEdict) && !IsPlayerSkulk(pEdict)) if (!IsPlayerGorge(pEdict) && !IsPlayerLerk(pEdict))
{ {
Vector HeadTraceLocation = GetPlayerTopOfCollisionHull(pEdict, false); Vector HeadTraceLocation = GetPlayerTopOfCollisionHull(pEdict, false);
bool bHittingHead = !UTIL_QuickTrace(pBot->Edict, HeadTraceLocation, HeadTraceLocation + Vector(0.0f, 0.0f, 10.0f)); bool bHittingHead = !UTIL_QuickTrace(pBot->Edict, HeadTraceLocation, HeadTraceLocation + Vector(0.0f, 0.0f, 10.0f));
bool bClimbIntoVent = (NextArea == SAMPLE_POLYAREA_CROUCH); bool bClimbIntoVent = (NextArea == SAMPLE_POLYAREA_CROUCH);
if (!IsPlayerSkulk(pBot->Edict) && (bHittingHead || bClimbIntoVent))
{
pBot->Button |= IN_DUCK; pBot->Button |= IN_DUCK;
} }
}
return; return;
} }
@ -3978,7 +4127,7 @@ void LadderMove(AvHAIPlayer* pBot, const Vector StartPoint, const Vector EndPoin
{ {
pBot->desiredMovementDir = vForward; pBot->desiredMovementDir = vForward;
// We look up really far to get maximum launch // We look up really far to get maximum launch
BotMoveLookAt(pBot, EndPoint + Vector(0.0f, 0.0f, 100.0f)); BotMoveLookAt(pBot, EndPoint + Vector(0.0f, 0.0f, 100.0f), true);
return; return;
} }
@ -3987,36 +4136,79 @@ void LadderMove(AvHAIPlayer* pBot, const Vector StartPoint, const Vector EndPoin
Vector StartLeftTrace = pBot->CollisionHullTopLocation - (ClimbRightNormal * GetPlayerRadius(pBot->Player)); Vector StartLeftTrace = pBot->CollisionHullTopLocation - (ClimbRightNormal * GetPlayerRadius(pBot->Player));
Vector StartRightTrace = pBot->CollisionHullTopLocation + (ClimbRightNormal * GetPlayerRadius(pBot->Player)); Vector StartRightTrace = pBot->CollisionHullTopLocation + (ClimbRightNormal * GetPlayerRadius(pBot->Player));
bool bBlockedLeft = !UTIL_QuickTrace(pEdict, StartLeftTrace, StartLeftTrace + Vector(0.0f, 0.0f, 32.0f)); Vector EndLeftTrace = (bIsGoingUpLadder) ? StartLeftTrace + Vector(0.0f, 0.0f, 32.0f) : StartLeftTrace - Vector(0.0f, 0.0f, 32.0f);
bool bBlockedRight = !UTIL_QuickTrace(pEdict, StartRightTrace, StartRightTrace + Vector(0.0f, 0.0f, 32.0f)); Vector EndRightTrace = (bIsGoingUpLadder) ? StartRightTrace + Vector(0.0f, 0.0f, 32.0f) : StartRightTrace - Vector(0.0f, 0.0f, 32.0f);
// Look up at the top of the ladder bool bBlockedLeft = !UTIL_QuickTrace(pEdict, StartLeftTrace, EndLeftTrace);
bool bBlockedRight = !UTIL_QuickTrace(pEdict, StartRightTrace, EndRightTrace);
if (bBlockedLeft && bBlockedRight)
{
Vector LadderCentre = UTIL_GetCentreOfEntity(Ladder);
int Side = vPointOnLine(LadderCentre, LadderCentre + CurrentLadderNormal, pBot->Edict->v.origin);
if (Side > 0)
{
pBot->desiredMovementDir = -LadderRightNormal;
}
else
{
pBot->desiredMovementDir = LadderRightNormal;
}
Vector LookLocation = pBot->Edict->v.origin - (CurrentLadderNormal * 50.0f);
LookLocation.z = RequiredClimbHeight + 100.0f;
BotMoveLookAt(pBot, LookLocation, true);
return;
}
// If we are blocked going up the ladder, face the ladder and slide left/right to avoid blockage // If we are blocked going up the ladder, face the ladder and slide left/right to avoid blockage
if (bBlockedLeft && !bBlockedRight) if (bBlockedLeft)
{ {
Vector LookLocation = pBot->Edict->v.origin - (CurrentLadderNormal * 50.0f); Vector LookLocation = pBot->Edict->v.origin - (CurrentLadderNormal * 50.0f);
LookLocation.z = RequiredClimbHeight + 100.0f; LookLocation.z = RequiredClimbHeight + 100.0f;
BotMoveLookAt(pBot, LookLocation); BotMoveLookAt(pBot, LookLocation, true);
pBot->desiredMovementDir = ClimbRightNormal; pBot->desiredMovementDir = ClimbRightNormal;
return; return;
} }
if (bBlockedRight && !bBlockedLeft) if (bBlockedRight)
{ {
Vector LookLocation = pBot->Edict->v.origin - (CurrentLadderNormal * 50.0f); Vector LookLocation = pBot->Edict->v.origin - (CurrentLadderNormal * 50.0f);
LookLocation.z = RequiredClimbHeight + 100.0f; LookLocation.z = RequiredClimbHeight + 100.0f;
BotMoveLookAt(pBot, LookLocation); BotMoveLookAt(pBot, LookLocation, true);
pBot->desiredMovementDir = -ClimbRightNormal; pBot->desiredMovementDir = -ClimbRightNormal;
return; return;
} }
if (!UTIL_QuickHullTrace(pBot->Edict, pBot->CurrentEyePosition, pBot->CurrentEyePosition + Vector(0.0f, 0.0f, 32.0f)))
{
Vector LadderCentre = UTIL_GetCentreOfEntity(Ladder);
int Side = vPointOnLine(LadderCentre, LadderCentre + CurrentLadderNormal, pBot->Edict->v.origin);
if (Side > 0)
{
pBot->desiredMovementDir = -LadderRightNormal;
}
else
{
pBot->desiredMovementDir = LadderRightNormal;
}
Vector LookLocation = pBot->Edict->v.origin - (CurrentLadderNormal * 50.0f);
LookLocation.z = RequiredClimbHeight + 100.0f;
BotMoveLookAt(pBot, LookLocation, true);
return;
}
// Crouch if we're hitting our head on a ceiling // Crouch if we're hitting our head on a ceiling
if (!IsPlayerGorge(pEdict) && !IsPlayerLerk(pEdict) && !IsPlayerSkulk(pEdict)) if (!IsPlayerGorge(pEdict) && !IsPlayerLerk(pEdict))
{ {
Vector HeadTraceLocation = GetPlayerTopOfCollisionHull(pEdict, false); Vector HeadTraceLocation = GetPlayerTopOfCollisionHull(pEdict, false);
@ -4034,8 +4226,6 @@ void LadderMove(AvHAIPlayer* pBot, const Vector StartPoint, const Vector EndPoin
Vector LookLocation = EndPoint; Vector LookLocation = EndPoint;
if (!IsPlayerSkulk(pBot->Edict))
{
float dot = UTIL_GetDotProduct2D(vForward, LadderRightNormal); float dot = UTIL_GetDotProduct2D(vForward, LadderRightNormal);
// Get-off point is to the side of the ladder rather than right at the top // Get-off point is to the side of the ladder rather than right at the top
@ -4058,15 +4248,8 @@ void LadderMove(AvHAIPlayer* pBot, const Vector StartPoint, const Vector EndPoin
} }
LookLocation.z += 100.0f; LookLocation.z += 100.0f;
}
else
{
// Get-off point is at the top of the ladder, so face the ladder
LookLocation = UTIL_GetNearestLadderTopPoint(pBot->Edict->v.origin) - (CurrentLadderNormal * 50.0f);
LookLocation.z += 100.0f;
}
BotMoveLookAt(pBot, LookLocation); BotMoveLookAt(pBot, LookLocation, true);
if (RequiredClimbHeight > pBot->Edict->v.origin.z || IsPlayerSkulk(pBot->Edict)) if (RequiredClimbHeight > pBot->Edict->v.origin.z || IsPlayerSkulk(pBot->Edict))
{ {
@ -4116,8 +4299,6 @@ void LadderMove(AvHAIPlayer* pBot, const Vector StartPoint, const Vector EndPoin
Vector LookLocation = EndPoint; Vector LookLocation = EndPoint;
if (!IsPlayerSkulk(pBot->Edict))
{
Vector FurthestView = UTIL_GetFurthestVisiblePointOnPath(pBot); Vector FurthestView = UTIL_GetFurthestVisiblePointOnPath(pBot);
if (vIsZero(FurthestView)) if (vIsZero(FurthestView))
@ -4130,14 +4311,8 @@ void LadderMove(AvHAIPlayer* pBot, const Vector StartPoint, const Vector EndPoin
{ {
BotJump(pBot); BotJump(pBot);
} }
}
else
{
LookLocation = pBot->CurrentEyePosition - (CurrentLadderNormal * 50.0f);
LookLocation.z -= 100.0f;
}
BotMoveLookAt(pBot, LookLocation); BotMoveLookAt(pBot, LookLocation, true);
} }
return; return;
@ -4154,7 +4329,7 @@ void LadderMove(AvHAIPlayer* pBot, const Vector StartPoint, const Vector EndPoin
pBot->desiredMovementDir = UTIL_GetVectorNormal2D(TargetPoint - pBot->Edict->v.origin); pBot->desiredMovementDir = UTIL_GetVectorNormal2D(TargetPoint - pBot->Edict->v.origin);
Vector LookPoint = TargetPoint + Vector(0.0f, 0.0f, 100.0f); Vector LookPoint = TargetPoint + Vector(0.0f, 0.0f, 100.0f);
BotMoveLookAt(pBot, LookPoint); BotMoveLookAt(pBot, LookPoint, true);
return; return;
} }
@ -4169,7 +4344,7 @@ void LadderMove(AvHAIPlayer* pBot, const Vector StartPoint, const Vector EndPoin
} }
// If we're going down the ladder and are approaching it, just keep moving towards it // If we're going down the ladder and are approaching it, just keep moving towards it
if ((pBot->BotNavInfo.IsOnGround || IsPlayerSkulk(pBot->Edict)) && !bIsGoingUpLadder) if (pBot->BotNavInfo.IsOnGround && !bIsGoingUpLadder)
{ {
if (vDist2DSq(pEdict->v.origin, StartPoint) < sqrf(32.0f)) if (vDist2DSq(pEdict->v.origin, StartPoint) < sqrf(32.0f))
{ {
@ -4220,13 +4395,30 @@ void LadderMove(AvHAIPlayer* pBot, const Vector StartPoint, const Vector EndPoin
if (pBot->Edict->v.origin.z < nearestLadderTop.z) if (pBot->Edict->v.origin.z < nearestLadderTop.z)
{
Vector LadderNormal = UTIL_GetNearestLadderNormal(StartPoint);
LadderNormal = UTIL_GetVectorNormal2D(LadderNormal);
edict_t* NearestLadder = UTIL_GetNearestLadderAtPoint(StartPoint);
Vector NearestPointOnLadder = UTIL_GetClosestPointOnEntityToLocation(pBot->Edict->v.origin, NearestLadder);
Vector OrientationToLadder = UTIL_GetVectorNormal2D(pBot->Edict->v.origin - NearestPointOnLadder);
Vector LookPoint = NearestPointOnLadder + Vector(0.0f, 0.0f, 20.0f);
if (UTIL_GetDotProduct2D(LadderNormal, OrientationToLadder) < 0.8f)
{
Vector MovePoint = NearestPointOnLadder + (LadderNormal * 32.0f);
pBot->desiredMovementDir = UTIL_GetVectorNormal2D(MovePoint - pBot->Edict->v.origin);
}
else
{ {
Vector nearestLadderPoint = UTIL_GetNearestLadderCentrePoint(pEdict); Vector nearestLadderPoint = UTIL_GetNearestLadderCentrePoint(pEdict);
nearestLadderPoint.z = pEdict->v.origin.z; nearestLadderPoint.z = pEdict->v.origin.z;
pBot->desiredMovementDir = UTIL_GetVectorNormal2D(nearestLadderPoint - pEdict->v.origin); pBot->desiredMovementDir = UTIL_GetVectorNormal2D(NearestPointOnLadder - pEdict->v.origin);
}
Vector LookPoint = nearestLadderPoint + Vector(0.0f, 0.0f, 20.0f);
BotMoveLookAt(pBot, LookPoint); BotMoveLookAt(pBot, LookPoint);
} }

View file

@ -2420,14 +2420,34 @@ AvHAICombatStrategy GetBotCombatStrategyForTarget(AvHAIPlayer* pBot, enemy_statu
{ {
if (FNullEnt(CurrentEnemy->PlayerEdict) || !IsPlayerActiveInGame(CurrentEnemy->PlayerEdict)) { return COMBAT_STRATEGY_IGNORE; } if (FNullEnt(CurrentEnemy->PlayerEdict) || !IsPlayerActiveInGame(CurrentEnemy->PlayerEdict)) { return COMBAT_STRATEGY_IGNORE; }
AvHAICombatStrategy IdealStrategy;
if (IsPlayerAlien(pBot->Edict)) if (IsPlayerAlien(pBot->Edict))
{ {
return GetAlienCombatStrategyForTarget(pBot, CurrentEnemy); IdealStrategy = GetAlienCombatStrategyForTarget(pBot, CurrentEnemy);
} }
else else
{ {
return GetMarineCombatStrategyForTarget(pBot, CurrentEnemy); IdealStrategy = GetMarineCombatStrategyForTarget(pBot, CurrentEnemy);
} }
if (IdealStrategy == COMBAT_STRATEGY_ATTACK)
{
// If we want to attack, but we can't reach the enemy and don't have a ranged weapon then ignore them entirely. Otherwise, skirmish instead
if (!UTIL_PointIsReachable(pBot->BotNavInfo.NavProfile, pBot->CurrentFloorPosition, UTIL_GetFloorUnderEntity(CurrentEnemy->PlayerEdict), max_ai_use_reach))
{
if (IsPlayerOnos(pBot->Edict) || IsPlayerSkulk(pBot->Edict) || (IsPlayerFade(pBot->Edict) && !PlayerHasWeapon(pBot->Player, WEAPON_FADE_ACIDROCKET)))
{
return COMBAT_STRATEGY_IGNORE;
}
else
{
return COMBAT_STRATEGY_SKIRMISH;
}
}
}
return IdealStrategy;
} }
AvHAICombatStrategy GetAlienCombatStrategyForTarget(AvHAIPlayer* pBot, enemy_status* CurrentEnemy) AvHAICombatStrategy GetAlienCombatStrategyForTarget(AvHAIPlayer* pBot, enemy_status* CurrentEnemy)
@ -4091,7 +4111,7 @@ void AIPlayerSetWantsAndNeedsMarineTask(AvHAIPlayer* pBot, AvHAIPlayerTask* Task
AvHTeamNumber BotTeam = pBot->Player->GetTeam(); AvHTeamNumber BotTeam = pBot->Player->GetTeam();
bool bNeedsHealth = pBot->Edict->v.health < (pBot->Edict->v.max_health * 0.9f); bool bNeedsHealth = pBot->Edict->v.health < (pBot->Edict->v.max_health * 0.9f);
bool bNeedsAmmo = UTIL_GetPlayerPrimaryAmmoReserve(pBot->Player) < (UTIL_GetPlayerPrimaryMaxAmmoReserve(pBot->Player) * 0.9f); bool bNeedsAmmo = UTIL_GetPlayerPrimaryAmmoReserve(pBot->Player) < (UTIL_GetPlayerPrimaryMaxAmmoReserve(pBot->Player) * 0.75f);
if (bNeedsHealth || bNeedsAmmo) if (bNeedsHealth || bNeedsAmmo)
{ {
@ -4121,7 +4141,7 @@ void AIPlayerSetWantsAndNeedsMarineTask(AvHAIPlayer* pBot, AvHAIPlayerTask* Task
NearestArmouryFilter.ReachabilityFlags = pBot->BotNavInfo.NavProfile.ReachabilityFlag; NearestArmouryFilter.ReachabilityFlags = pBot->BotNavInfo.NavProfile.ReachabilityFlag;
NearestArmouryFilter.IncludeStatusFlags = STRUCTURE_STATUS_COMPLETED; NearestArmouryFilter.IncludeStatusFlags = STRUCTURE_STATUS_COMPLETED;
NearestArmouryFilter.ExcludeStatusFlags = STRUCTURE_STATUS_RECYCLING; NearestArmouryFilter.ExcludeStatusFlags = STRUCTURE_STATUS_RECYCLING;
NearestArmouryFilter.MaxSearchRadius = (bTaskIsUrgent) ? UTIL_MetresToGoldSrcUnits(20.0f) : UTIL_MetresToGoldSrcUnits(5.0f); NearestArmouryFilter.MaxSearchRadius = (bTaskIsUrgent) ? UTIL_MetresToGoldSrcUnits(20.0f) : UTIL_MetresToGoldSrcUnits(3.0f);
AvHAIBuildableStructure NearestArmoury = AITAC_FindClosestDeployableToLocation(pBot->Edict->v.origin, &NearestArmouryFilter); AvHAIBuildableStructure NearestArmoury = AITAC_FindClosestDeployableToLocation(pBot->Edict->v.origin, &NearestArmouryFilter);

View file

@ -839,7 +839,7 @@ int AIMGR_GetNumAIPlayersWithRoleOnTeam(AvHTeamNumber Team, AvHAIBotRole Role, A
{ {
if (&(*it) == IgnoreAIPlayer) { continue; } if (&(*it) == IgnoreAIPlayer) { continue; }
if (it->Player->GetTeam() == Team) if (it->Player->GetTeam() == Team && IsPlayerActiveInGame((*it).Edict))
{ {
if (it->BotRole == Role) if (it->BotRole == Role)
{ {

View file

@ -153,7 +153,7 @@ bool IsPlayerOnLadder(const edict_t* Player)
Vector NearestPointOnLadder = UTIL_GetClosestPointOnEntityToLocation(Player->v.origin, NearestLadder); Vector NearestPointOnLadder = UTIL_GetClosestPointOnEntityToLocation(Player->v.origin, NearestLadder);
Vector NearestPointOnPlayer = UTIL_GetClosestPointOnEntityToLocation(NearestPointOnLadder, Player); Vector NearestPointOnPlayer = UTIL_GetClosestPointOnEntityToLocation(NearestPointOnLadder, Player);
return (vDist2DSq(NearestPointOnLadder, NearestPointOnPlayer) <= sqrf(4.0f)); return (vDist3DSq(NearestPointOnLadder, NearestPointOnPlayer) <= sqrf(2.0f));
} }
return (Player->v.movetype == MOVETYPE_FLY); return (Player->v.movetype == MOVETYPE_FLY);
@ -992,6 +992,31 @@ Vector UTIL_GetNearestSurfaceNormal(Vector SearchLocation)
return ClosestNormal; return ClosestNormal;
} }
Vector UTIL_GetLadderNormal(Vector SearchLocation, edict_t* Ladder)
{
if (FNullEnt(Ladder)) { return ZERO_VECTOR; }
if (vPointOverlaps3D(SearchLocation, Ladder->v.absmin, Ladder->v.absmax))
{
return UTIL_GetNearestSurfaceNormal(SearchLocation);
}
else
{
Vector CentrePoint = Ladder->v.absmin + (Ladder->v.size * 0.5f);
CentrePoint.z = SearchLocation.z;
trace_t TraceResult;
NS_TraceLine(SearchLocation, CentrePoint, 1, PM_WORLD_ONLY, -1, true, TraceResult);
if (TraceResult.fraction < 1.0f)
{
return TraceResult.plane.normal;
}
}
return ZERO_VECTOR;
}
Vector UTIL_GetNearestLadderNormal(Vector SearchLocation) Vector UTIL_GetNearestLadderNormal(Vector SearchLocation)
{ {
TraceResult result; TraceResult result;

View file

@ -172,6 +172,8 @@ Vector UTIL_GetNearestLadderTopPoint(edict_t* pEdict);
Vector UTIL_GetNearestLadderTopPoint(const Vector SearchLocation); Vector UTIL_GetNearestLadderTopPoint(const Vector SearchLocation);
Vector UTIL_GetNearestLadderBottomPoint(edict_t* pEdict); Vector UTIL_GetNearestLadderBottomPoint(edict_t* pEdict);
Vector UTIL_GetLadderNormal(Vector SearchLocation, edict_t* Ladder);
Vector UTIL_GetNearestSurfaceNormal(Vector SearchLocation); Vector UTIL_GetNearestSurfaceNormal(Vector SearchLocation);
#endif #endif

View file

@ -5843,11 +5843,6 @@ Vector AITAC_FindNewTeamRelocationPoint(AvHTeamNumber Team)
MinDist = ThisDist; MinDist = ThisDist;
} }
} }
} }
// No hives to relocate to // No hives to relocate to

View file

@ -1272,9 +1272,9 @@ void BotProgressMineStructureTask(AvHAIPlayer* pBot, AvHAIPlayerTask* Task)
} }
} }
float DistToPlaceLocation = vDist2DSq(pBot->Edict->v.origin, Task->TaskLocation); float DistToPlaceLocation = vDist3DSq(pBot->Edict->v.origin, Task->TaskLocation);
if (DistToPlaceLocation < sqrf(UTIL_MetresToGoldSrcUnits(5.0f))) if (DistToPlaceLocation < sqrf(50.0f))
{ {
pBot->DesiredCombatWeapon = WEAPON_MARINE_MINES; pBot->DesiredCombatWeapon = WEAPON_MARINE_MINES;
} }