Improved lerk flight

* Better lerk flight
* Fixed bots switching weapons rapidly
This commit is contained in:
RGreenlees 2024-04-22 19:56:16 +01:00 committed by pierow
parent 540194cc6e
commit cfc65e1f5a
5 changed files with 248 additions and 80 deletions

View file

@ -55,6 +55,14 @@ edict_t* UTIL_TraceEntity(const edict_t* pEdict, const Vector& start, const Vect
return hit.pHit;
}
edict_t* UTIL_TraceEntityHull(const edict_t* pEdict, const Vector& start, const Vector& end)
{
TraceResult hit;
edict_t* IgnoreEdict = (!FNullEnt(pEdict)) ? pEdict->v.pContainingEntity : NULL;
UTIL_TraceHull(start, end, dont_ignore_monsters, head_hull, IgnoreEdict, &hit);
return hit.pHit;
}
Vector UTIL_GetTraceHitLocation(const Vector Start, const Vector End)
{
TraceResult hit;

View file

@ -11,6 +11,7 @@ bool UTIL_QuickTrace(const edict_t* pEdict, const Vector& start, const Vector& e
bool UTIL_QuickHullTrace(const edict_t* pEdict, const Vector& start, const Vector& end, bool bAllowStartSolid = false);
bool UTIL_QuickHullTrace(const edict_t* pEdict, const Vector& start, const Vector& end, int hullNum, bool bAllowStartSolid = false);
edict_t* UTIL_TraceEntity(const edict_t* pEdict, const Vector& start, const Vector& end);
edict_t* UTIL_TraceEntityHull(const edict_t* pEdict, const Vector& start, const Vector& end);
Vector UTIL_GetTraceHitLocation(const Vector Start, const Vector End);
Vector UTIL_GetHullTraceHitLocation(const Vector Start, const Vector End, int HullNum);

View file

@ -1706,14 +1706,7 @@ dtStatus FindFlightPathToPoint(const nav_profile &NavProfile, Vector FromLocatio
bot_path_node NextPathNode;
if (CurrFlags == SAMPLE_POLYFLAGS_LIFT)
{
NextPathNode.flag = CurrFlags;
}
else
{
NextPathNode.flag = SAMPLE_POLYFLAGS_WALK;
}
NextPathNode.area = CurrArea;
NextPathNode.poly = StraightPolyPath[nVert];
@ -1723,17 +1716,23 @@ dtStatus FindFlightPathToPoint(const nav_profile &NavProfile, Vector FromLocatio
{
float MaxHeight = (CurrFlags == SAMPLE_POLYFLAGS_JUMP) ? fmaxf(PrevPoint.z, NextPathPoint.z) + 60.0f : UTIL_FindZHeightForWallClimb(PrevPoint, NextPathPoint, head_hull);
Vector PotentialNextPoint = PrevPoint + (UTIL_GetVectorNormal2D(NextPathPoint - PrevPoint) * 2.0f);;
PotentialNextPoint.z = MaxHeight;
if (UTIL_QuickTrace(nullptr, PrevPoint, PotentialNextPoint))
{
NextPathNode.requiredZ = MaxHeight;
NextPathNode.Location = PrevPoint;
NextPathNode.Location.z = MaxHeight;
NextPathNode.Location = PotentialNextPoint;
NextPathNode.FromLocation = PrevPoint;
PrevPoint = NextPathNode.Location;
path.push_back(NextPathNode);
}
NextPathNode.requiredZ = MaxHeight;
NextPathNode.Location = NextPathPoint;
NextPathNode.Location = NextPathPoint - (UTIL_GetVectorNormal2D(NextPathPoint - PrevPoint) * 2.0f);
NextPathNode.Location.z = MaxHeight;
NextPathNode.FromLocation = PrevPoint;
@ -1741,12 +1740,25 @@ dtStatus FindFlightPathToPoint(const nav_profile &NavProfile, Vector FromLocatio
path.push_back(NextPathNode);
}
else if (CurrFlags == SAMPLE_POLYFLAGS_LADDER || CurrFlags == SAMPLE_POLYFLAGS_FALL)
else if (CurrFlags == SAMPLE_POLYFLAGS_FALL)
{
float MaxHeight = fmaxf(PrevPoint.z, NextPathPoint.z);
NextPathNode.requiredZ = MaxHeight;
NextPathNode.Location = (PrevPoint.z < NextPathPoint.z) ? PrevPoint : NextPathPoint;
NextPathNode.Location = NextPathPoint;
NextPathNode.Location.z = PrevPoint.z;
NextPathNode.FromLocation = PrevPoint;
PrevPoint = NextPathNode.Location;
path.push_back(NextPathNode);
}
else if (CurrFlags == SAMPLE_POLYFLAGS_LADDER)
{
float MaxHeight = fmaxf(PrevPoint.z, NextPathPoint.z);
NextPathNode.requiredZ = MaxHeight;
NextPathNode.Location = (PrevPoint.z < NextPathPoint.z) ? (PrevPoint + (UTIL_GetVectorNormal2D(NextPathPoint - PrevPoint) * 2.0f)) : NextPathPoint;
NextPathNode.Location.z = MaxHeight;
NextPathNode.FromLocation = PrevPoint;
@ -6674,6 +6686,8 @@ void SkipAheadInFlightPath(AvHAIPlayer* pBot)
for (auto it = prev(BotNavInfo->CurrentPath.end()); it != next(CurrentPathPoint); it--)
{
if (it->area == SAMPLE_POLYAREA_CROUCH) { continue; }
Vector NextFlightPoint = UTIL_FindHighestSuccessfulTracePoint(pBot->Edict->v.origin, it->FromLocation, it->Location, 5.0f, 50.0f, 200.0f);
// If we can directly reach the end point, set our path point to the end of the path and go for it
@ -6694,6 +6708,133 @@ void SkipAheadInFlightPath(AvHAIPlayer* pBot)
}
}
LerkFlightBehaviour BotFlightWalkMove(AvHAIPlayer* pBot, Vector FromLocation, Vector ToLocation)
{
Vector LookLocation = ToLocation;
Vector ClosestPointOnLine = vClosestPointOnLine(FromLocation, ToLocation, pBot->Edict->v.origin);
if (fabs(pBot->Edict->v.origin.z - ClosestPointOnLine.z) > 8.0f)
{
if (pBot->Edict->v.origin.z > ClosestPointOnLine.z)
{
LookLocation.z -= 32.0f;
}
else
{
LookLocation.z += 32.0f;
}
}
BotMoveLookAt(pBot, LookLocation);
Vector MoveDir = UTIL_GetVectorNormal(ToLocation - FromLocation);
Vector VelocityDir = UTIL_GetVectorNormal(pBot->Edict->v.velocity);
float MoveDot = UTIL_GetDotProduct(MoveDir, VelocityDir);
if (MoveDot < 0.7f || vDist2DSq(pBot->Edict->v.origin, FromLocation) > sqrf(100.0f) && vDist2DSq(pBot->Edict->v.origin, ToLocation) > sqrf(100.0f))
{
float CurrentSpeed = pBot->Edict->v.velocity.Length2D();
Vector ThisMoveDir = UTIL_GetVectorNormal2D(ToLocation - pBot->Edict->v.origin);
Vector NewVelocity = ThisMoveDir * fmaxf(CurrentSpeed, 100.0f);
NewVelocity.z = pBot->Edict->v.velocity.z;
pBot->Edict->v.velocity = NewVelocity;
}
pBot->desiredMovementDir = UTIL_GetVectorNormal2D(pBot->Edict->v.angles);
return (vSize3D(pBot->Edict->v.velocity) < 500.0f && GetPlayerEnergy(pBot->Edict) > 0.1f) ? FLIGHT_FLAP : FLIGHT_GLIDE;
}
LerkFlightBehaviour BotFlightFallMove(AvHAIPlayer* pBot, Vector FromLocation, Vector ToLocation)
{
Vector LookLocation = ToLocation;
Vector ClosestPointOnLine = vClosestPointOnLine(FromLocation, ToLocation, pBot->Edict->v.origin);
if (fabs(pBot->Edict->v.origin.z - ClosestPointOnLine.z) > 8.0f)
{
if (pBot->Edict->v.origin.z > ClosestPointOnLine.z)
{
LookLocation.z -= 32.0f;
}
else
{
LookLocation.z += 32.0f;
}
}
BotMoveLookAt(pBot, LookLocation);
if (pBot->BotNavInfo.IsOnGround)
{
pBot->desiredMovementDir = UTIL_GetVectorNormal2D(ToLocation - FromLocation);
}
else
{
pBot->desiredMovementDir = UTIL_GetVectorNormal2D(pBot->Edict->v.angles);
}
return pBot->BotNavInfo.IsOnGround ? FLIGHT_DROP : FLIGHT_GLIDE;
}
LerkFlightBehaviour BotFlightClimbMove(AvHAIPlayer* pBot, Vector FromLocation, Vector ToLocation, float RequiredZ)
{
Vector LookLocation = ToLocation;
Vector MoveDir = UTIL_GetVectorNormal2D(ToLocation - FromLocation);
if (vIsZero(MoveDir))
{
MoveDir = UTIL_GetVectorNormal2D(pBot->Edict->v.angles);
}
Vector ClosestPointOnLine = vClosestPointOnLine(FromLocation, ToLocation, pBot->Edict->v.origin);
float DistFromLine = vDist2DSq(pBot->Edict->v.origin, ClosestPointOnLine);
Vector ThisMoveDir = MoveDir;
float CurrentSpeed = pBot->Edict->v.velocity.Length2D();
Vector NewVelocity = ThisMoveDir * fmaxf(CurrentSpeed, 100.0f);
NewVelocity.z = pBot->Edict->v.velocity.z;
pBot->Edict->v.velocity = NewVelocity;
pBot->desiredMovementDir = UTIL_GetVectorNormal2D(pBot->Edict->v.angles);
if (UTIL_QuickTrace(pBot->Edict, pBot->Edict->v.origin, ToLocation))
{
BotMoveLookAt(pBot, ToLocation);
}
else
{
Vector LookLocation = pBot->Edict->v.origin + (MoveDir * 100.0f);
LookLocation.z = RequiredZ;
BotMoveLookAt(pBot, LookLocation);
}
if (pBot->Edict->v.origin.z - RequiredZ > 4.0f)
{
return FLIGHT_DROP;
}
else
{
pBot->Edict->v.velocity.z = fmaxf(pBot->Edict->v.velocity.z, 10.0f);
}
UTIL_DrawLine(INDEXENT(1), pBot->Edict->v.origin, pBot->Edict->v.origin + UTIL_GetVectorNormal(pBot->Edict->v.velocity) * 100.0f, 255, 0, 0);
return FLIGHT_FLAP;
}
void BotFollowFlightPath(AvHAIPlayer* pBot, bool bAllowSkip)
{
if (pBot->BotNavInfo.CurrentPath.size() == 0 || pBot->BotNavInfo.CurrentPathPoint >= pBot->BotNavInfo.CurrentPath.size())
@ -6729,8 +6870,6 @@ void BotFollowFlightPath(AvHAIPlayer* pBot, bool bAllowSkip)
}
}
if (CurrentPathPoint->flag == SAMPLE_POLYFLAGS_LIFT)
{
LiftMove(pBot, CurrentPathPoint->FromLocation, CurrentMoveDest);
@ -6746,7 +6885,9 @@ void BotFollowFlightPath(AvHAIPlayer* pBot, bool bAllowSkip)
NextFlags = (SamplePolyFlags)next(CurrentPathPoint)->flag;
}
if (bAllowSkip && CurrentPathPoint->area != SAMPLE_POLYAREA_CROUCH && CurrentPathPoint->flag != SAMPLE_POLYFLAGS_LIFT && NextArea != SAMPLE_POLYAREA_CROUCH && NextFlags != SAMPLE_POLYFLAGS_LIFT)
bool bShouldSkipAhead = bAllowSkip && (CurrentPathPoint->area == SAMPLE_POLYAREA_GROUND && CurrentPathPoint->flag == SAMPLE_POLYFLAGS_WALK);
if (bShouldSkipAhead)
{
SkipAheadInFlightPath(pBot);
CurrentPathPoint = (BotNavInfo->CurrentPath.begin() + BotNavInfo->CurrentPathPoint);
@ -6754,11 +6895,23 @@ void BotFollowFlightPath(AvHAIPlayer* pBot, bool bAllowSkip)
ClosestPointToPath = vClosestPointOnLine(CurrentPathPoint->FromLocation, CurrentPathPoint->Location, pEdict->v.origin);
if (bAllowSkip && vDist3DSq(pBot->Edict->v.origin, ClosestPointToPath) > sqrf(GetPlayerRadius(pBot->Edict) * 3.0f))
if (bAllowSkip)
{
bool bStrayedOffPath = vDist3DSq(pBot->Edict->v.origin, ClosestPointToPath) > sqrf(GetPlayerRadius(pBot->Edict) * 3.0f);
bool bNoDirectRoute = false;
if ((CurrentPathPoint->area == SAMPLE_POLYAREA_GROUND || CurrentPathPoint->area == SAMPLE_POLYAREA_CROUCH) && CurrentPathPoint->flag == SAMPLE_POLYFLAGS_WALK)
{
bNoDirectRoute = !UTIL_QuickHullTrace(pBot->Edict, pBot->Edict->v.origin, CurrentPathPoint->Location, false);
}
if (bStrayedOffPath || bNoDirectRoute)
{
MoveDirectlyTo(pBot, CurrentPathPoint->Location);
ClearBotPath(pBot);
return;
}
}
CurrentMoveDest = CurrentPathPoint->Location;
Vector MoveFrom = CurrentPathPoint->FromLocation;
@ -6766,68 +6919,52 @@ void BotFollowFlightPath(AvHAIPlayer* pBot, bool bAllowSkip)
unsigned char CurrentMoveArea = CurrentPathPoint->area;
unsigned char NextMoveArea = (next(CurrentPathPoint) != BotNavInfo->CurrentPath.end()) ? next(CurrentPathPoint)->area : CurrentMoveArea;
Vector MoveDir = UTIL_GetVectorNormal(CurrentMoveDest - MoveFrom);
LerkFlightBehaviour FlightBehaviour = FLIGHT_FLAP;
float CurrentSpeed = vSize3D(pEdict->v.velocity);
if (vDist2DSq(pEdict->v.origin, MoveFrom) > sqrf(100.0f) && vDist2DSq(pEdict->v.origin, CurrentMoveDest) > sqrf(100.0f))
switch (CurrentPathPoint->flag)
{
Vector NewVelocity = MoveDir;
if (vDist3DSq(pEdict->v.origin, ClosestPointToPath) > sqrf(16.0f))
{
NewVelocity = UTIL_GetVectorNormal((ClosestPointToPath + (MoveDir * 100.0f)) - pEdict->v.origin);
}
NewVelocity = NewVelocity * CurrentSpeed;
pEdict->v.velocity = NewVelocity;
case SAMPLE_POLYFLAGS_WALLCLIMB:
case SAMPLE_POLYFLAGS_LADDER:
FlightBehaviour = BotFlightClimbMove(pBot, CurrentPathPoint->FromLocation, CurrentPathPoint->Location, CurrentPathPoint->requiredZ);
break;
case SAMPLE_POLYFLAGS_FALL:
FlightBehaviour = BotFlightFallMove(pBot, CurrentPathPoint->FromLocation, CurrentPathPoint->Location);
break;
default:
FlightBehaviour = BotFlightWalkMove(pBot, CurrentPathPoint->FromLocation, CurrentPathPoint->Location);
break;
}
bool bMustHugGround = (CurrentMoveArea == SAMPLE_POLYAREA_CROUCH || NextMoveArea == SAMPLE_POLYAREA_CROUCH);
if (!bMustHugGround || MoveFrom.z <= CurrentMoveDest.z)
{
if (CurrentSpeed < 500.f && GetPlayerEnergy(pBot->Edict) > 0.1f)
{
if (!(pEdict->v.oldbuttons & IN_JUMP))
if (FlightBehaviour == FLIGHT_GLIDE)
{
pBot->Button |= IN_JUMP;
}
else
else if (FlightBehaviour == FLIGHT_FLAP)
{
if (gpGlobals->time - BotNavInfo->LastFlapTime < 0.2f)
if (gpGlobals->time - BotNavInfo->LastFlapTime > 0.2f)
{
pBot->Button |= IN_JUMP;
}
else
{
BotNavInfo->LastFlapTime = gpGlobals->time;
}
}
}
else
Vector StartTrace = pBot->Edict->v.origin;
Vector EndTrace = StartTrace + (UTIL_GetVectorNormal2D(pBot->Edict->v.angles) * 32.0f);
edict_t* BlockingEdict = UTIL_TraceEntityHull(pBot->Edict, StartTrace, EndTrace);
if (!FNullEnt(BlockingEdict) && (IsEdictStructure(BlockingEdict) || IsEdictPlayer(BlockingEdict)))
{
pBot->Button |= IN_JUMP;
pBot->Edict->v.velocity.z = 150.0f;
}
}
Vector LookLocation = CurrentMoveDest;
if (pEdict->v.origin.z < CurrentPathPoint->requiredZ)
{
LookLocation.z += 32.0f;
}
BotMoveLookAt(pBot, LookLocation);
pBot->desiredMovementDir = UTIL_GetForwardVector2D(pEdict->v.v_angle);
CheckAndHandleBreakableObstruction(pBot, MoveFrom, CurrentMoveDest, SAMPLE_POLYFLAGS_WALK);
CheckAndHandleDoorObstruction(pBot);
BotMovementInputs(pBot);
}
void BotFollowSwimPath(AvHAIPlayer* pBot)
@ -7510,6 +7647,11 @@ float UTIL_FindZHeightForWallClimb(const Vector ClimbStart, const Vector ClimbEn
if (hit.flFraction >= 1.0f && !hit.fStartSolid)
{
if (UTIL_QuickHullTrace(nullptr, EndTrace, EndTrace + Vector(0.0f, 0.0f, 8.0f), false))
{
CurrTraceStart.z += 8.0f;
}
return CurrTraceStart.z;
}
else

View file

@ -73,6 +73,13 @@ enum SamplePolyFlags
SAMPLE_POLYFLAGS_ALL = -1 // All abilities.
};
// What should the lerk do for this movement?
enum LerkFlightBehaviour
{
FLIGHT_DROP = 0, // Drop like a stone
FLIGHT_GLIDE, // Hold jump to glide
FLIGHT_FLAP // Rapidly tap jump to flap and speed up
};
// Door reference. Not used, but is a future feature to allow bots to track if a door is open or not, and how to open it etc.
typedef struct _NAV_DOOR

View file

@ -2955,6 +2955,13 @@ bool BombardierCombatThink(AvHAIPlayer* pBot)
bool RegularMarineCombatThink(AvHAIPlayer* pBot)
{
#ifdef DEBUG
if (pBot == AIMGR_GetDebugAIPlayer())
{
bool bBreak = true; // Add a break point here if you want to debug a specific bot
}
#endif
AvHTeamNumber BotTeam = pBot->Player->GetTeam();
AvHTeamNumber EnemyTeam = AIMGR_GetEnemyTeam(BotTeam);
@ -2981,6 +2988,8 @@ bool RegularMarineCombatThink(AvHAIPlayer* pBot)
// Run away and restock
if (pBot->CurrentCombatStrategy == COMBAT_STRATEGY_RETREAT)
{
pBot->DesiredCombatWeapon = DesiredCombatWeapon;
if (NearestHealthPack && (pBot->Edict->v.health < pBot->Edict->v.max_health * 0.7f))
{
MoveTo(pBot, NearestHealthPack->Location, MOVESTYLE_NORMAL);
@ -3007,7 +3016,17 @@ bool RegularMarineCombatThink(AvHAIPlayer* pBot)
{
if (IsPlayerInUseRange(pBot->Edict, NearestArmouryRef.edict))
{
if (UTIL_GetPlayerPrimaryAmmoReserve(pBot->Player) < UTIL_GetPlayerPrimaryMaxAmmoReserve(pBot->Player) || UTIL_GetPlayerSecondaryAmmoReserve(pBot->Player) >= UTIL_GetPlayerPrimaryWeaponMaxClipSize(pBot->Player))
{
pBot->DesiredCombatWeapon = UTIL_GetPlayerPrimaryWeapon(pBot->Player);
}
else
{
pBot->DesiredCombatWeapon = UTIL_GetPlayerSecondaryWeapon(pBot->Player);
}
BotUseObject(pBot, NearestArmouryRef.edict, true);
BotReloadWeapons(pBot);
return true;
}
}
@ -3069,11 +3088,6 @@ bool RegularMarineCombatThink(AvHAIPlayer* pBot)
{
pBot->DesiredCombatWeapon = DesiredCombatWeapon;
if (GetPlayerCurrentWeapon(pBot->Player) != DesiredCombatWeapon)
{
return true;
}
if (vIsZero(pBot->LastSafeLocation))
{
pBot->LastSafeLocation = AITAC_GetTeamStartingLocation(BotTeam);
@ -3175,12 +3189,8 @@ bool RegularMarineCombatThink(AvHAIPlayer* pBot)
// Go for the kill. Maintain desired distance and pursue when needed
if (pBot->CurrentCombatStrategy == COMBAT_STRATEGY_ATTACK)
{
pBot->DesiredCombatWeapon = DesiredCombatWeapon;
if (GetPlayerCurrentWeapon(pBot->Player) != DesiredCombatWeapon)
{
return true;
}
bool bCanUsePrimaryWeapon = UTIL_GetPlayerPrimaryWeaponClipAmmo(pBot->Player) > 0;
pBot->DesiredCombatWeapon = (!TrackedEnemyRef->bIsVisible && bCanUsePrimaryWeapon) ? UTIL_GetPlayerPrimaryWeapon(pBot->Player) : DesiredCombatWeapon;
if (vIsZero(pBot->LastSafeLocation))
{