Fix skulk movement on ladders

This commit is contained in:
RGreenlees 2024-02-09 18:47:11 +00:00 committed by pierow
parent 451810e07b
commit 9e0b42dbf4
5 changed files with 141 additions and 85 deletions

View file

@ -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)
{

View file

@ -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);

View file

@ -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;
}

View file

@ -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<AvHPlayer*>(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)

View file

@ -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))
{