diff --git a/main/source/mod/AvHAICommander.cpp b/main/source/mod/AvHAICommander.cpp index a7a0b8c0..a3032de2 100644 --- a/main/source/mod/AvHAICommander.cpp +++ b/main/source/mod/AvHAICommander.cpp @@ -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) { @@ -3252,7 +3252,7 @@ bool AICOMM_CheckForNextSupportAction(AvHAIPlayer* pBot) 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) { @@ -3265,7 +3265,7 @@ bool AICOMM_CheckForNextSupportAction(AvHAIPlayer* pBot) 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) { @@ -3399,6 +3399,13 @@ void AICOMM_CommanderThink(AvHAIPlayer* pBot) if (!vIsZero(pBot->RelocationSpot)) { + vector 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); if (RelocationHive) @@ -4026,19 +4033,29 @@ bool AICOMM_CheckForNextRelocationAction(AvHAIPlayer* pBot) { 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_ProjectPointToNavmesh(RelocationPoint, Vector(500.0f, 500.0f, 500.0f), GetBaseNavProfile(STRUCTURE_BASE_NAV_PROFILE)); - } + BuildPoint = UTIL_GetRandomPointOnNavmeshInRadius(GetBaseNavProfile(STRUCTURE_BASE_NAV_PROFILE), pBot->RelocationSpot, UTIL_MetresToGoldSrcUnits(2.0f)); 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; diff --git a/main/source/mod/AvHAINavigation.cpp b/main/source/mod/AvHAINavigation.cpp index 02b52b1c..dc860cbf 100644 --- a/main/source/mod/AvHAINavigation.cpp +++ b/main/source/mod/AvHAINavigation.cpp @@ -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; AvHPlayer* AIPlayer = pBot->Player; @@ -3857,48 +3884,173 @@ void LadderMove(AvHAIPlayer* pBot, const Vector StartPoint, const Vector EndPoin bool bIsGoingUpLadder = (EndPoint.z > StartPoint.z); - // Stop holding crouch if we're a skulk so we can climb up/down - if (IsPlayerSkulk(pBot->Edict)) + edict_t* Ladder = UTIL_GetNearestLadderAtPoint(StartPoint); + + if (!FNullEnt(Ladder)) { - pBot->Button &= ~IN_DUCK; + Vector LadderStart = Ladder->v.absmin; + Vector LadderEnd = Ladder->v.absmax; + LadderEnd.z = LadderStart.z; - edict_t* Ladder = UTIL_GetNearestLadderAtPoint(StartPoint); - - if (!FNullEnt(Ladder)) + // 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)) { - Vector LadderStart = Ladder->v.absmin; - Vector LadderEnd = Ladder->v.absmax; - 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 - if (vIntersects2D(StartPoint, EndPoint, LadderStart, LadderEnd)) + if (bIsGoingUpLadder) { - if (bIsGoingUpLadder) - { - WallClimbMove(pBot, StartPoint, EndPoint, RequiredClimbHeight); - } - else - { - FallMove(pBot, StartPoint, EndPoint); - } - return; + WallClimbMove(pBot, StartPoint, EndPoint, RequiredClimbHeight); } + else + { + FallMove(pBot, StartPoint, EndPoint); + } + 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)) { // We're on the ladder and actively climbing 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 { - CurrentLadderNormal = UTIL_GetNearestLadderNormal(pBot->CollisionHullBottomLocation + Vector(0.0f, 0.0f, 5.0f)); - } + CurrentLadderNormal = UTIL_GetNearestLadderNormal(pBot->Edict->v.origin); + } CurrentLadderNormal = UTIL_GetVectorNormal2D(CurrentLadderNormal); @@ -3948,7 +4100,7 @@ void LadderMove(AvHAIPlayer* pBot, const Vector StartPoint, const Vector EndPoin Vector LookLocation = EndPoint; 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 (UTIL_GetDotProduct(CurrentLadderNormal, vForward) > 0.75f) @@ -3956,17 +4108,14 @@ void LadderMove(AvHAIPlayer* pBot, const Vector StartPoint, const Vector EndPoin BotJump(pBot); } - if (!IsPlayerGorge(pEdict) && !IsPlayerLerk(pEdict) && !IsPlayerSkulk(pEdict)) + if (!IsPlayerGorge(pEdict) && !IsPlayerLerk(pEdict)) { Vector HeadTraceLocation = GetPlayerTopOfCollisionHull(pEdict, false); bool bHittingHead = !UTIL_QuickTrace(pBot->Edict, HeadTraceLocation, HeadTraceLocation + Vector(0.0f, 0.0f, 10.0f)); bool bClimbIntoVent = (NextArea == SAMPLE_POLYAREA_CROUCH); - if (!IsPlayerSkulk(pBot->Edict) && (bHittingHead || bClimbIntoVent)) - { - pBot->Button |= IN_DUCK; - } + pBot->Button |= IN_DUCK; } return; @@ -3978,7 +4127,7 @@ void LadderMove(AvHAIPlayer* pBot, const Vector StartPoint, const Vector EndPoin { pBot->desiredMovementDir = vForward; // 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; } @@ -3987,36 +4136,79 @@ void LadderMove(AvHAIPlayer* pBot, const Vector StartPoint, const Vector EndPoin Vector StartLeftTrace = 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)); - bool bBlockedRight = !UTIL_QuickTrace(pEdict, StartRightTrace, StartRightTrace + 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); + 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 (bBlockedLeft && !bBlockedRight) + if (bBlockedLeft) { Vector LookLocation = pBot->Edict->v.origin - (CurrentLadderNormal * 50.0f); LookLocation.z = RequiredClimbHeight + 100.0f; - BotMoveLookAt(pBot, LookLocation); + BotMoveLookAt(pBot, LookLocation, true); pBot->desiredMovementDir = ClimbRightNormal; return; } - if (bBlockedRight && !bBlockedLeft) + if (bBlockedRight) { Vector LookLocation = pBot->Edict->v.origin - (CurrentLadderNormal * 50.0f); LookLocation.z = RequiredClimbHeight + 100.0f; - BotMoveLookAt(pBot, LookLocation); + BotMoveLookAt(pBot, LookLocation, true); pBot->desiredMovementDir = -ClimbRightNormal; 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 - if (!IsPlayerGorge(pEdict) && !IsPlayerLerk(pEdict) && !IsPlayerSkulk(pEdict)) + if (!IsPlayerGorge(pEdict) && !IsPlayerLerk(pEdict)) { Vector HeadTraceLocation = GetPlayerTopOfCollisionHull(pEdict, false); @@ -4034,39 +4226,30 @@ void LadderMove(AvHAIPlayer* pBot, const Vector StartPoint, const Vector EndPoin Vector LookLocation = EndPoint; - if (!IsPlayerSkulk(pBot->Edict)) + float dot = UTIL_GetDotProduct2D(vForward, LadderRightNormal); + + // Get-off point is to the side of the ladder rather than right at the top + if (fabsf(dot) > 0.5f) { - float dot = UTIL_GetDotProduct2D(vForward, LadderRightNormal); - - // Get-off point is to the side of the ladder rather than right at the top - if (fabsf(dot) > 0.5f) + if (dot > 0.0f) { - if (dot > 0.0f) - { - LookLocation = pBot->Edict->v.origin + (LadderRightNormal * 50.0f); - } - else - { - LookLocation = pBot->Edict->v.origin - (LadderRightNormal * 50.0f); - } - + LookLocation = pBot->Edict->v.origin + (LadderRightNormal * 50.0f); } else { - // Get-off point is at the top of the ladder, so face the ladder - LookLocation = EndPoint - (CurrentLadderNormal * 50.0f); + LookLocation = pBot->Edict->v.origin - (LadderRightNormal * 50.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; + LookLocation = EndPoint - (CurrentLadderNormal * 50.0f); } - BotMoveLookAt(pBot, LookLocation); + LookLocation.z += 100.0f; + + BotMoveLookAt(pBot, LookLocation, true); if (RequiredClimbHeight > pBot->Edict->v.origin.z || IsPlayerSkulk(pBot->Edict)) { @@ -4116,28 +4299,20 @@ void LadderMove(AvHAIPlayer* pBot, const Vector StartPoint, const Vector EndPoin Vector LookLocation = EndPoint; - if (!IsPlayerSkulk(pBot->Edict)) - { - Vector FurthestView = UTIL_GetFurthestVisiblePointOnPath(pBot); + Vector FurthestView = UTIL_GetFurthestVisiblePointOnPath(pBot); - if (vIsZero(FurthestView)) - { - LookLocation = EndPoint + (CurrentLadderNormal * 100.0f); - } - - // We're close enough to the end that we can jump off the ladder - if (UTIL_QuickTrace(pBot->Edict, pBot->Edict->v.origin, EndPoint) && (pBot->CollisionHullBottomLocation.z - EndPoint.z < 100.0f)) - { - BotJump(pBot); - } - } - else + if (vIsZero(FurthestView)) { - LookLocation = pBot->CurrentEyePosition - (CurrentLadderNormal * 50.0f); - LookLocation.z -= 100.0f; + LookLocation = EndPoint + (CurrentLadderNormal * 100.0f); } - BotMoveLookAt(pBot, LookLocation); + // We're close enough to the end that we can jump off the ladder + if (UTIL_QuickTrace(pBot->Edict, pBot->Edict->v.origin, EndPoint) && (pBot->CollisionHullBottomLocation.z - EndPoint.z < 100.0f)) + { + BotJump(pBot); + } + + BotMoveLookAt(pBot, LookLocation, true); } return; @@ -4154,7 +4329,7 @@ void LadderMove(AvHAIPlayer* pBot, const Vector StartPoint, const Vector EndPoin pBot->desiredMovementDir = UTIL_GetVectorNormal2D(TargetPoint - pBot->Edict->v.origin); Vector LookPoint = TargetPoint + Vector(0.0f, 0.0f, 100.0f); - BotMoveLookAt(pBot, LookPoint); + BotMoveLookAt(pBot, LookPoint, true); 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 ((pBot->BotNavInfo.IsOnGround || IsPlayerSkulk(pBot->Edict)) && !bIsGoingUpLadder) + if (pBot->BotNavInfo.IsOnGround && !bIsGoingUpLadder) { if (vDist2DSq(pEdict->v.origin, StartPoint) < sqrf(32.0f)) { @@ -4221,12 +4396,29 @@ void LadderMove(AvHAIPlayer* pBot, const Vector StartPoint, const Vector EndPoin if (pBot->Edict->v.origin.z < nearestLadderTop.z) { + Vector LadderNormal = UTIL_GetNearestLadderNormal(StartPoint); + LadderNormal = UTIL_GetVectorNormal2D(LadderNormal); - Vector nearestLadderPoint = UTIL_GetNearestLadderCentrePoint(pEdict); - nearestLadderPoint.z = pEdict->v.origin.z; - pBot->desiredMovementDir = UTIL_GetVectorNormal2D(nearestLadderPoint - pEdict->v.origin); + edict_t* NearestLadder = UTIL_GetNearestLadderAtPoint(StartPoint); - Vector LookPoint = nearestLadderPoint + Vector(0.0f, 0.0f, 20.0f); + 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); + nearestLadderPoint.z = pEdict->v.origin.z; + pBot->desiredMovementDir = UTIL_GetVectorNormal2D(NearestPointOnLadder - pEdict->v.origin); + } BotMoveLookAt(pBot, LookPoint); } diff --git a/main/source/mod/AvHAIPlayer.cpp b/main/source/mod/AvHAIPlayer.cpp index ae9b17ce..93ae9d72 100644 --- a/main/source/mod/AvHAIPlayer.cpp +++ b/main/source/mod/AvHAIPlayer.cpp @@ -2420,14 +2420,34 @@ AvHAICombatStrategy GetBotCombatStrategyForTarget(AvHAIPlayer* pBot, enemy_statu { if (FNullEnt(CurrentEnemy->PlayerEdict) || !IsPlayerActiveInGame(CurrentEnemy->PlayerEdict)) { return COMBAT_STRATEGY_IGNORE; } + AvHAICombatStrategy IdealStrategy; + if (IsPlayerAlien(pBot->Edict)) { - return GetAlienCombatStrategyForTarget(pBot, CurrentEnemy); + IdealStrategy = GetAlienCombatStrategyForTarget(pBot, CurrentEnemy); } 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) @@ -4091,7 +4111,7 @@ void AIPlayerSetWantsAndNeedsMarineTask(AvHAIPlayer* pBot, AvHAIPlayerTask* Task AvHTeamNumber BotTeam = pBot->Player->GetTeam(); 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) { @@ -4121,7 +4141,7 @@ void AIPlayerSetWantsAndNeedsMarineTask(AvHAIPlayer* pBot, AvHAIPlayerTask* Task NearestArmouryFilter.ReachabilityFlags = pBot->BotNavInfo.NavProfile.ReachabilityFlag; NearestArmouryFilter.IncludeStatusFlags = STRUCTURE_STATUS_COMPLETED; 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); diff --git a/main/source/mod/AvHAIPlayerManager.cpp b/main/source/mod/AvHAIPlayerManager.cpp index 27309e9d..5744bef4 100644 --- a/main/source/mod/AvHAIPlayerManager.cpp +++ b/main/source/mod/AvHAIPlayerManager.cpp @@ -839,7 +839,7 @@ int AIMGR_GetNumAIPlayersWithRoleOnTeam(AvHTeamNumber Team, AvHAIBotRole Role, A { if (&(*it) == IgnoreAIPlayer) { continue; } - if (it->Player->GetTeam() == Team) + if (it->Player->GetTeam() == Team && IsPlayerActiveInGame((*it).Edict)) { if (it->BotRole == Role) { diff --git a/main/source/mod/AvHAIPlayerUtil.cpp b/main/source/mod/AvHAIPlayerUtil.cpp index 708bc8a3..0a23e1e1 100644 --- a/main/source/mod/AvHAIPlayerUtil.cpp +++ b/main/source/mod/AvHAIPlayerUtil.cpp @@ -153,7 +153,7 @@ bool IsPlayerOnLadder(const edict_t* Player) Vector NearestPointOnLadder = UTIL_GetClosestPointOnEntityToLocation(Player->v.origin, NearestLadder); 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); @@ -992,6 +992,31 @@ Vector UTIL_GetNearestSurfaceNormal(Vector SearchLocation) 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) { TraceResult result; diff --git a/main/source/mod/AvHAIPlayerUtil.h b/main/source/mod/AvHAIPlayerUtil.h index e0c9a0a1..ce30893a 100644 --- a/main/source/mod/AvHAIPlayerUtil.h +++ b/main/source/mod/AvHAIPlayerUtil.h @@ -172,6 +172,8 @@ Vector UTIL_GetNearestLadderTopPoint(edict_t* pEdict); Vector UTIL_GetNearestLadderTopPoint(const Vector SearchLocation); Vector UTIL_GetNearestLadderBottomPoint(edict_t* pEdict); +Vector UTIL_GetLadderNormal(Vector SearchLocation, edict_t* Ladder); + Vector UTIL_GetNearestSurfaceNormal(Vector SearchLocation); #endif \ No newline at end of file diff --git a/main/source/mod/AvHAITactical.cpp b/main/source/mod/AvHAITactical.cpp index 13b769be..a79e4bf9 100644 --- a/main/source/mod/AvHAITactical.cpp +++ b/main/source/mod/AvHAITactical.cpp @@ -5843,11 +5843,6 @@ Vector AITAC_FindNewTeamRelocationPoint(AvHTeamNumber Team) MinDist = ThisDist; } } - - - - - } // No hives to relocate to diff --git a/main/source/mod/AvHAITask.cpp b/main/source/mod/AvHAITask.cpp index c86b62fa..e5167fbd 100644 --- a/main/source/mod/AvHAITask.cpp +++ b/main/source/mod/AvHAITask.cpp @@ -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; }