From 9e0b42dbf452d56a735bfc2b52741b7d68b8c65a Mon Sep 17 00:00:00 2001 From: RGreenlees Date: Fri, 9 Feb 2024 18:47:11 +0000 Subject: [PATCH] Fix skulk movement on ladders --- main/source/mod/AIPlayers/AvHAIHelper.cpp | 3 +- main/source/mod/AIPlayers/AvHAINavigation.cpp | 158 ++++++++++-------- main/source/mod/AIPlayers/AvHAIPlayer.cpp | 28 +++- .../mod/AIPlayers/AvHAIPlayerManager.cpp | 18 +- main/source/mod/AIPlayers/AvHAITask.cpp | 19 ++- 5 files changed, 141 insertions(+), 85 deletions(-) diff --git a/main/source/mod/AIPlayers/AvHAIHelper.cpp b/main/source/mod/AIPlayers/AvHAIHelper.cpp index 13241317..48b8fc87 100644 --- a/main/source/mod/AIPlayers/AvHAIHelper.cpp +++ b/main/source/mod/AIPlayers/AvHAIHelper.cpp @@ -159,8 +159,9 @@ Vector UTIL_GetFloorUnderEntity(const edict_t* Edict) TraceResult hit; Vector EntityCentre = UTIL_GetCentreOfEntity(Edict) + Vector(0.0f, 0.0f, 1.0f); + Vector TraceEnd = (EntityCentre - Vector(0.0f, 0.0f, 1000.0f)); - UTIL_TraceHull(EntityCentre, (EntityCentre - Vector(0.0f, 0.0f, 1000.0f)), ignore_monsters, head_hull, Edict->v.pContainingEntity, &hit); + UTIL_TraceHull(EntityCentre, TraceEnd, ignore_monsters, head_hull, Edict->v.pContainingEntity, &hit); if (hit.flFraction < 1.0f) { diff --git a/main/source/mod/AIPlayers/AvHAINavigation.cpp b/main/source/mod/AIPlayers/AvHAINavigation.cpp index fe0d6267..760efee2 100644 --- a/main/source/mod/AIPlayers/AvHAINavigation.cpp +++ b/main/source/mod/AIPlayers/AvHAINavigation.cpp @@ -1853,7 +1853,16 @@ dtStatus FindPathClosestToPoint(AvHAIPlayer* pBot, const BotMoveStyle MoveStyle, Vector CurrMoveDest = NextPathNode.Location; - NextPathNode.flag = SAMPLE_POLYFLAGS_WALLCLIMB; + if (NextPathNode.Location.z > NodeFromLocation.z) + { + NextPathNode.flag = SAMPLE_POLYFLAGS_WALLCLIMB; + CurrFlags = SAMPLE_POLYFLAGS_WALLCLIMB; + } + else + { + NextPathNode.flag = SAMPLE_POLYFLAGS_FALL; + CurrFlags = SAMPLE_POLYFLAGS_FALL; + } NextPathNode.Location = NearestLadderTopPoint; @@ -1862,7 +1871,7 @@ dtStatus FindPathClosestToPoint(AvHAIPlayer* pBot, const BotMoveStyle MoveStyle, NextPathNode.Location = CurrMoveDest; NextPathNode.FromLocation = NearestLadderTopPoint; - CurrFlags = SAMPLE_POLYFLAGS_WALLCLIMB; + } } @@ -2025,7 +2034,16 @@ bool HasBotReachedPathPoint(const AvHAIPlayer* pBot) } } case SAMPLE_POLYFLAGS_WALLCLIMB: - return bAtOrPastDestination && fabs(pEdict->v.origin.z - MoveTo.z) < 50.0f; + { + if (!bIsAtFinalPathPoint && next(pBot->BotNavInfo.CurrentPathPoint)->flag == SAMPLE_POLYFLAGS_WALLCLIMB) + { + Vector ClosestPointToPath = vClosestPointOnLine(MoveFrom, MoveTo, pEdict->v.origin); + + return vEquals(ClosestPointToPath, MoveTo, 5.0f); + } + + return bAtOrPastDestination && fabs(pEdict->v.origin.z - MoveTo.z) < 50.0f; + } case SAMPLE_POLYFLAGS_LADDER: { if (MoveTo.z > MoveFrom.z) @@ -2649,7 +2667,6 @@ edict_t* UTIL_GetDoorBlockingPathPoint(const Vector FromLocation, const Vector T } } - return nullptr; } @@ -3430,8 +3447,6 @@ void SkulkLadderMove(AvHAIPlayer* pBot, const Vector StartPoint, const Vector En { pBot->Button &= ~IN_DUCK; - ClimbRightNormal = -LadderRightNormal; - Vector HullTraceTo = EndPoint; HullTraceTo.z = pBot->CollisionHullBottomLocation.z; @@ -3467,71 +3482,18 @@ void SkulkLadderMove(AvHAIPlayer* pBot, const Vector StartPoint, const Vector En // Still climbing the ladder. Look up, and move left/right on the ladder to avoid any blockages - Vector StartLeftTrace = pBot->CollisionHullTopLocation - (ClimbRightNormal * GetPlayerRadius(pBot->Player)); - Vector StartRightTrace = pBot->CollisionHullTopLocation + (ClimbRightNormal * GetPlayerRadius(pBot->Player)); + Vector LookLocation = StartPoint - (LadderNormal * 100.0f); + LookLocation.z = EndPoint.z + 50.0f; - 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)); - - // Look up at the top of the ladder - - // If we are blocked going up the ladder, face the ladder and slide left/right to avoid blockage - if (bBlockedLeft && !bBlockedRight) - { - Vector LookLocation = pBot->Edict->v.origin - (pBot->CurrentLadderNormal * 50.0f); - LookLocation.z = RequiredClimbHeight + 100.0f; - BotMoveLookAt(pBot, LookLocation); - - pBot->desiredMovementDir = ClimbRightNormal; - return; - } - - if (bBlockedRight && !bBlockedLeft) - { - Vector LookLocation = pBot->Edict->v.origin - (pBot->CurrentLadderNormal * 50.0f); - LookLocation.z = RequiredClimbHeight + 100.0f; - BotMoveLookAt(pBot, LookLocation); - - pBot->desiredMovementDir = -ClimbRightNormal; - return; - } - - Vector LookLocation = UTIL_GetNearestLadderTopPoint(pBot->Edict); - - LookLocation.z = RequiredClimbHeight + 100.0f; BotMoveLookAt(pBot, LookLocation); - - pBot->desiredMovementDir = -UTIL_GetNearestLadderNormal(pBot->Edict); + pBot->desiredMovementDir = -LadderNormal; } } else { - - // We're going down the ladder - - Vector StartLeftTrace = pBot->CollisionHullBottomLocation - (LadderRightNormal * (GetPlayerRadius(pBot->Player) + 2.0f)); - Vector StartRightTrace = pBot->CollisionHullBottomLocation + (LadderRightNormal * (GetPlayerRadius(pBot->Player) + 2.0f)); - - 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)); - - if (bBlockedLeft) - { - pBot->desiredMovementDir = LadderRightNormal; - return; - } - - if (bBlockedRight) - { - pBot->desiredMovementDir = -LadderRightNormal; - return; - } - - pBot->desiredMovementDir = pBot->CurrentLadderNormal; - - BotMoveLookAt(pBot, EndPoint); + FallMove(pBot, StartPoint, EndPoint); } } @@ -4110,6 +4072,29 @@ void WallClimbMove(AvHAIPlayer* pBot, const Vector StartPoint, const Vector EndP } } + if (IsPlayerClimbingWall(pBot->Edict)) + { + Vector RightDir = UTIL_GetCrossProduct(vForward, UP_VECTOR); + + Vector LeftCheckStart = pBot->Edict->v.origin - (RightDir * (GetPlayerRadius(pBot->Player) + 2.0f)); + Vector LeftCheckEnd = LeftCheckStart + Vector(0.0f, 0.0f, 50.0f); + + Vector RightCheckStart = pBot->Edict->v.origin + (RightDir * (GetPlayerRadius(pBot->Player) + 2.0f)); + Vector RightCheckEnd = RightCheckStart + Vector(0.0f, 0.0f, 50.0f); + + if (!UTIL_QuickTrace(pBot->Edict, LeftCheckStart, LeftCheckEnd)) + { + if (UTIL_QuickTrace(pBot->Edict, RightCheckStart, RightCheckEnd)) + { + pBot->desiredMovementDir = UTIL_GetVectorNormal2D(vForward + RightDir); + } + } + else if (!UTIL_QuickTrace(pBot->Edict, RightCheckStart, RightCheckEnd)) + { + pBot->desiredMovementDir = UTIL_GetVectorNormal2D(vForward - RightDir); + } + } + BotMoveLookAt(pBot, LookLocation); } @@ -4185,6 +4170,8 @@ void MoveToWithoutNav(AvHAIPlayer* pBot, const Vector Destination) void MoveDirectlyTo(AvHAIPlayer* pBot, const Vector Destination) { + pBot->BotNavInfo.StuckInfo.bPathFollowFailed = false; + if (vIsZero(Destination)) { return; } Vector CurrentPos = (pBot->BotNavInfo.IsOnGround) ? pBot->Edict->v.origin : pBot->CurrentFloorPosition; @@ -4964,7 +4951,7 @@ bool AbortCurrentMove(AvHAIPlayer* pBot, const Vector NewDestination) Vector ClosestPointOnLine = vClosestPointOnLine2D(MoveFrom, MoveTo, pBot->Edict->v.origin); - bool bAtOrPastMovement = (vEquals2D(ClosestPointOnLine, MoveFrom, 1.0f) || vEquals2D(ClosestPointOnLine, MoveTo, 1.0f)); + bool bAtOrPastMovement = (vEquals2D(ClosestPointOnLine, MoveFrom, 1.0f) && fabsf(pBot->Edict->v.origin.z - MoveFrom.z) <= 50.0f ) || (vEquals2D(ClosestPointOnLine, MoveTo, 1.0f) && fabsf(pBot->Edict->v.origin.z - MoveTo.z) <= 50.0f) ; if ((pBot->Edict->v.flags & FL_ONGROUND) && bAtOrPastMovement) { @@ -4977,17 +4964,29 @@ bool AbortCurrentMove(AvHAIPlayer* pBot, const Vector NewDestination) if (flag == SAMPLE_POLYFLAGS_LIFT) { - if (UTIL_PointIsDirectlyReachable(pBot->CurrentFloorPosition, MoveFrom) || UTIL_PointIsDirectlyReachable(pBot->CurrentFloorPosition, MoveTo)) + if (pBot->BotNavInfo.MovementTask.TaskType != MOVE_TASK_NONE) { - return true; + if (NAV_IsMovementTaskStillValid(pBot)) + { + NAV_ProgressMovementTask(pBot); + return false; + } + else + { + NAV_ClearMovementTask(pBot); + ClearBotPath(pBot); + return true; + } } if (bReverseCourse) { + if (UTIL_PointIsDirectlyReachable(pBot->CurrentFloorPosition, MoveFrom)) { return true; } LiftMove(pBot, MoveTo, MoveFrom); } else { + if (UTIL_PointIsDirectlyReachable(pBot->CurrentFloorPosition, MoveTo)) { return true; } LiftMove(pBot, MoveFrom, MoveTo); } } @@ -5131,11 +5130,15 @@ void UpdateBotStuck(AvHAIPlayer* pBot) return; } - BotJump(pBot); - if (!IsPlayerSkulk(pBot->Edict)) + if (!vIsZero(pBot->desiredMovementDir)) { - pBot->Button |= IN_DUCK; - } + //BotJump(pBot); + + if (!IsPlayerSkulk(pBot->Edict)) + { + pBot->Button |= IN_DUCK; + } + } } } @@ -5388,6 +5391,7 @@ bool MoveTo(AvHAIPlayer* pBot, const Vector Destination, const BotMoveStyle Move { if (vIsZero(Destination) || (vDist2D(pBot->Edict->v.origin, Destination) <= 6.0f && (fabs(pBot->CollisionHullBottomLocation.z - Destination.z) < 50.0f))) { + pBot->BotNavInfo.StuckInfo.bPathFollowFailed = false; ClearBotMovement(pBot); return true; } @@ -5458,7 +5462,7 @@ bool MoveTo(AvHAIPlayer* pBot, const Vector Destination, const BotMoveStyle Move { pBot->BotNavInfo.StuckInfo.bPathFollowFailed = true; - if (!vIsZero(BotNavInfo->LastNavMeshPosition)) + if (!UTIL_PointIsOnNavmesh(pBot->CollisionHullBottomLocation, pBot->BotNavInfo.NavProfile) && !vIsZero(BotNavInfo->LastNavMeshPosition)) { MoveDirectlyTo(pBot, BotNavInfo->LastNavMeshPosition); @@ -5585,16 +5589,26 @@ Vector FindClosestPointBackOnPath(AvHAIPlayer* pBot) { Vector NewMoveLocation = ZERO_VECTOR; + Vector NewMoveFromLocation = ZERO_VECTOR; for (auto it = BackwardsPath.rbegin(); it != BackwardsPath.rend(); it++) { if (UTIL_QuickTrace(pBot->Edict, pBot->Edict->v.origin, it->Location)) { NewMoveLocation = it->Location; + NewMoveFromLocation = it->FromLocation; break; } } + if (!vIsZero(NewMoveLocation)) + { + if (vDist2DSq(pBot->Edict->v.origin, NewMoveLocation) < sqrf(GetPlayerRadius(pBot->Player))) + { + NewMoveLocation = NewMoveLocation - (UTIL_GetVectorNormal2D(NewMoveLocation - NewMoveFromLocation) * 100.0f); + } + } + return NewMoveLocation; } @@ -6250,7 +6264,7 @@ bool UTIL_PointIsOnNavmesh(const Vector Location, const nav_profile &NavProfile) dtPolyRef FoundPoly; float NavNearest[3]; - float pCheckExtents[3] = { 5.0f, 72.0f, 5.0f }; + float pCheckExtents[3] = { 5.0f, 50.0f, 5.0f }; dtStatus success = m_navQuery->findNearestPoly(pCheckLoc, pCheckExtents, m_navFilter, &FoundPoly, NavNearest); diff --git a/main/source/mod/AIPlayers/AvHAIPlayer.cpp b/main/source/mod/AIPlayers/AvHAIPlayer.cpp index fd24d358..d67cd804 100644 --- a/main/source/mod/AIPlayers/AvHAIPlayer.cpp +++ b/main/source/mod/AIPlayers/AvHAIPlayer.cpp @@ -1772,6 +1772,11 @@ void DroneThink(AvHAIPlayer* pBot) AIDEBUG_DrawBotPath(pBot); + if (pBot->BotNavInfo.CurrentPathPoint != pBot->BotNavInfo.CurrentPath.end()) + { + UTIL_DrawLine(INDEXENT(1), pBot->Edict->v.origin, pBot->BotNavInfo.CurrentPathPoint->Location, 0, 255, 255); + } + } void SetNewAIPlayerRole(AvHAIPlayer* pBot, AvHAIBotRole NewRole) @@ -3245,8 +3250,13 @@ void AIPlayerSetMarineAssaultPrimaryTask(AvHAIPlayer* pBot, AvHAIPlayerTask* Tas if (NearestEmptyHive) { - AITASK_SetSecureHiveTask(pBot, Task, NearestEmptyHive->HiveEntity->edict(), NearestEmptyHive->FloorLocation, false); - return; + Vector ActualMoveLocation = FindClosestNavigablePointToDestination(pBot->BotNavInfo.NavProfile, pBot->CurrentFloorPosition, NearestEmptyHive->FloorLocation, UTIL_MetresToGoldSrcUnits(5.0f)); + + if (!vIsZero(ActualMoveLocation)) + { + AITASK_SetSecureHiveTask(pBot, Task, NearestEmptyHive->HiveEntity->edict(), NearestEmptyHive->FloorLocation, false); + return; + } } // Go to a good siege location if phase gates available @@ -3846,6 +3856,8 @@ void AIPlayerThink(AvHAIPlayer* pBot) if (pBot == AIMGR_GetDebugAIPlayer()) { bool bBreak = true; + + AIDEBUG_DrawBotPath(pBot); } switch (GetGameRules()->GetMapMode()) @@ -3949,6 +3961,14 @@ void AIPlayerReceiveBuildOrder(AvHAIPlayer* pBot, edict_t* BuildTarget) void AIPlayerReceiveMoveOrder(AvHAIPlayer* pBot, Vector Destination) { + Vector NavMoveLocation = AdjustPointForPathfinding(Destination); + + Vector ActualMoveLocation = FindClosestNavigablePointToDestination(pBot->BotNavInfo.NavProfile, pBot->CurrentFloorPosition, NavMoveLocation, UTIL_MetresToGoldSrcUnits(5.0f)); + + if (vIsZero(ActualMoveLocation)) // Don't try to follow an invalid move order + { + return; + } const AvHAIResourceNode* ResNodeRef = AITAC_GetNearestResourceNodeToLocation(Destination); @@ -3971,14 +3991,14 @@ void AIPlayerReceiveMoveOrder(AvHAIPlayer* pBot, Vector Destination) { if (!AICOMM_IsHiveFullySecured(pBot, HiveRef, false)) { - AITASK_SetSecureHiveTask(pBot, &pBot->CommanderTask, HiveRef->HiveEntity->edict(), Destination, false); + AITASK_SetSecureHiveTask(pBot, &pBot->CommanderTask, HiveRef->HiveEntity->edict(), ActualMoveLocation, 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 - AITASK_SetMoveTask(pBot, &pBot->CommanderTask, Destination, true); + AITASK_SetMoveTask(pBot, &pBot->CommanderTask, ActualMoveLocation, true); pBot->CommanderTask.bIssuedByCommander = true; } diff --git a/main/source/mod/AIPlayers/AvHAIPlayerManager.cpp b/main/source/mod/AIPlayers/AvHAIPlayerManager.cpp index 63c8e506..f2b29e81 100644 --- a/main/source/mod/AIPlayers/AvHAIPlayerManager.cpp +++ b/main/source/mod/AIPlayers/AvHAIPlayerManager.cpp @@ -27,6 +27,8 @@ int BotNameIndex = 0; float AIStartedTime = 0.0f; // Used to give 5-second grace period before adding bots +bool bHasRoundStarted = false; + extern int m_spriteTexture; Vector DebugVector1 = ZERO_VECTOR; @@ -130,20 +132,20 @@ void AIMGR_UpdateAIPlayerCounts() if (!GetGameRules()->GetGameStarted()) { - if (CurrentFillTiming == FILLTIMING_ROUNDSTART) { return; } + if (CurrentFillTiming == FILLTIMING_ROUNDSTART) { return; } // Do nothing if we're only meant to add bots after round start, and the round hasn't started if (CurrentFillTiming == FILLTIMING_ALLHUMANS) { for (int i = 1; i <= gpGlobals->maxClients; i++) { edict_t* PlayerEdict = INDEXENT(i); - if (FNullEnt(PlayerEdict) || PlayerEdict->free || (PlayerEdict->v.flags & FL_FAKECLIENT)) { continue; } + if (FNullEnt(PlayerEdict) || PlayerEdict->free || (PlayerEdict->v.flags & FL_FAKECLIENT)) { continue; } // Ignore fake clients AvHPlayer* PlayerRef = dynamic_cast(CBaseEntity::Instance(PlayerEdict)); if (!PlayerRef) { continue; } - if (PlayerRef->GetInReadyRoom()) { return; } + if (PlayerRef->GetInReadyRoom()) { return; } // If there is a human in the ready room, don't add any more bots } } } @@ -609,7 +611,7 @@ void AIMGR_UpdateAIPlayers() { BotDeltaTime = ThinkDelta; - if (ShouldBotThink(bot)) + if (bHasRoundStarted && ShouldBotThink(bot)) { if (bot->bIsInactive) { @@ -620,7 +622,7 @@ void AIMGR_UpdateAIPlayers() UpdateBotChat(bot); - AIPlayerThink(bot); + DroneThink(bot); EndBotFrame(bot); @@ -836,6 +838,8 @@ void AIMGR_ResetRound() UTIL_PopulateWeldableObstacles(); ALERT(at_console, "AI Manager Reset Round\n"); + + bHasRoundStarted = false; } void AIMGR_RoundStarted() @@ -850,6 +854,8 @@ void AIMGR_RoundStarted() UTIL_UpdateDoors(true); UTIL_UpdateTileCache(); + + bHasRoundStarted = true; } @@ -906,6 +912,8 @@ void AIMGR_NewMap() } AIMGR_BotPrecache(); + + bHasRoundStarted = false; } AvHAIPlayer* AIMGR_GetAICommander(AvHTeamNumber Team) diff --git a/main/source/mod/AIPlayers/AvHAITask.cpp b/main/source/mod/AIPlayers/AvHAITask.cpp index 13a341b4..4fbead69 100644 --- a/main/source/mod/AIPlayers/AvHAITask.cpp +++ b/main/source/mod/AIPlayers/AvHAITask.cpp @@ -372,11 +372,11 @@ bool AITASK_IsTouchTaskStillValid(AvHAIPlayer* pBot, AvHAIPlayerTask* Task) bool AITASK_IsMoveTaskStillValid(AvHAIPlayer* pBot, AvHAIPlayerTask* Task) { - if (!Task->TaskLocation) { return false; } + if (vIsZero(Task->TaskLocation)) { return false; } if (pBot->BotNavInfo.NavProfile.bFlyingProfile && vEquals(pBot->Edict->v.origin, Task->TaskLocation, 50.0f)) { return false; } - return (vDist2DSq(pBot->Edict->v.origin, Task->TaskLocation) > sqrf(max_player_use_reach) || !UTIL_PointIsDirectlyReachable(pBot->CurrentFloorPosition, Task->TaskLocation)); + return (vDist2DSq(pBot->Edict->v.origin, Task->TaskLocation) > sqrf(GetPlayerRadius(pBot->Player)) || fabsf(pBot->Edict->v.origin.z - Task->TaskLocation.z) > 50.0f); } bool AITASK_IsWeldTaskStillValid(AvHAIPlayer* pBot, AvHAIPlayerTask* Task) @@ -3055,8 +3055,21 @@ void AITASK_SetMoveTask(AvHAIPlayer* pBot, AvHAIPlayerTask* Task, const Vector L if (vIsZero(Location)) { return; } + Vector MoveStart = AdjustPointForPathfinding(pBot->CurrentFloorPosition); + Vector MoveEnd = AdjustPointForPathfinding(Location); + // Get as close as possible to desired location - Vector MoveLocation = FindClosestNavigablePointToDestination(pBot->BotNavInfo.NavProfile, pBot->CurrentFloorPosition, Location, UTIL_MetresToGoldSrcUnits(20.0f)); + Vector MoveLocation = FindClosestNavigablePointToDestination(pBot->BotNavInfo.NavProfile, MoveStart, MoveEnd, UTIL_MetresToGoldSrcUnits(1.0f)); + + if (vIsZero(MoveLocation)) + { + Vector ReverseMove = FindClosestNavigablePointToDestination(pBot->BotNavInfo.NavProfile, MoveEnd, MoveStart, UTIL_MetresToGoldSrcUnits(5.0f)); + + if (!vIsZero(ReverseMove)) + { + MoveLocation = MoveEnd; + } + } if (!vIsZero(MoveLocation)) {