Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions src/game/server/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -1548,6 +1548,7 @@ set(UNITY_SOURCE_NEO_BOT
neo/bot/behavior/neo_bot_pause.cpp
neo/bot/behavior/neo_bot_retreat_to_cover.cpp
neo/bot/behavior/neo_bot_retreat_from_grenade.cpp
neo/bot/behavior/neo_bot_retreat_from_hazard_area.cpp
neo/bot/behavior/neo_bot_scenario_monitor.cpp
neo/bot/behavior/neo_bot_seek_and_destroy.cpp
neo/bot/behavior/neo_bot_seek_weapon.cpp
Expand Down
29 changes: 29 additions & 0 deletions src/game/server/NextBot/NextBotVisionInterface.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@
#include "neo_player.h"
#include "neo_smokelineofsightblocker.h"
#include "bot/neo_bot.h"
#include "bot/neo_bot_path_reservation.h"
#include "nav_mesh.h"
#endif

#include "tier0/vprof.h"
Expand Down Expand Up @@ -794,6 +796,33 @@ bool IVision::IsLineOfSightClearToEntity( const CBaseEntity *subject, Vector *vi
UTIL_TraceLine( GetBot()->GetBodyInterface()->GetEyePosition(), firstPosition, MASK_BLOCKLOS_AND_NPCS|CONTENTS_IGNORE_NODRAW_OPAQUE, &filter, &result );
if ( result.DidHit() )
{
// Check if first center traceline hit any blocking smoke
if (neo_bot_path_reservation_enable.GetBool()
&& result.m_pEnt
&& FStrEq(result.m_pEnt->GetClassname(), SMOKELINEOFSIGHTBLOCKER_ENTITYNAME))
Comment thread
sunzenshen marked this conversation as resolved.
{
auto pSmoke = static_cast<CNEOSmokeLineOfSightBlocker*>(result.m_pEnt);
Comment thread
sunzenshen marked this conversation as resolved.
// Assume that threat could be hiding inside navarea where smoke blocked sight
if (neoBot)
{
int team = neoBot->GetTeamNumber();

CNavArea *smokeArea = TheNavMesh->GetNearestNavArea(result.endpos);
if (smokeArea)
{
// Register smoke sightlines for team to avoid as hazardous
CNEOBotPathReservations()->AddSmokeHazard(smokeArea->GetID(), pSmoke->GetNextThink(), team);
Comment thread
sunzenshen marked this conversation as resolved.
}

CNavArea *myArea = neoBot->GetLastKnownArea();
if (myArea)
{
// Also register the area I saw the smoke from as hazardous
CNEOBotPathReservations()->AddSmokeHazard(myArea->GetID(), pSmoke->GetNextThink(), team, false);
}
}
}

UTIL_TraceLine( GetBot()->GetBodyInterface()->GetEyePosition(), secondPosition, MASK_BLOCKLOS_AND_NPCS|CONTENTS_IGNORE_NODRAW_OPAQUE, &filter, &result );

if ( result.DidHit() )
Expand Down
21 changes: 16 additions & 5 deletions src/game/server/neo/bot/behavior/neo_bot_attack.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@ class CSearchForAttackCover : public ISearchSurroundingAreasFunctor
m_threatArea = threat->GetLastKnownArea();
m_goalArea = goalArea ? goalArea : m_threatArea; // prioritize movement towards input goal area or threat
m_myDistToGoalSq = m_goalArea ? ( m_goalArea->GetCenter() - m_me->GetAbsOrigin() ).LengthSqr() : 0;
m_onStuckPenalty = neo_bot_path_reservation_onstuck_penalty.GetFloat();
}

bool IsBetterCandidate( CNavArea *area, float avoidPenalty ) const
Expand Down Expand Up @@ -120,6 +121,20 @@ class CSearchForAttackCover : public ISearchSurroundingAreasFunctor
return true; // skip our starting area
}

// Skip areas that are hazardous or where bots get stuck
if ( neo_bot_path_reservation_enable.GetBool() )
{
int navAreaId = area->GetID();
if (CNEOBotPathReservations()->IsAreaHazardous(navAreaId, m_me))
{
return true;
}
if (CNEOBotPathReservations()->GetAreaAvoidPenalty(navAreaId) >= m_onStuckPenalty)
Comment thread
sunzenshen marked this conversation as resolved.
{
return true;
}
}

float avoidPenalty = neo_bot_path_reservation_enable.GetBool()
? CNEOBotPathReservations()->GetAreaAvoidPenalty( area->GetID() )
: 0.0f;
Expand Down Expand Up @@ -215,6 +230,7 @@ class CSearchForAttackCover : public ISearchSurroundingAreasFunctor
const CNavArea *m_myArea; // reference point of myself
const CNavArea *m_threatArea; // reference point of the threat
float m_myDistToGoalSq; // the bot's current distance to the threat
float m_onStuckPenalty; // cache onstuck penalty
};


Expand Down Expand Up @@ -468,11 +484,6 @@ QueryResultType CNEOBotAttack::ShouldRetreat( const INextBot *me ) const
return ANSWER_UNDEFINED;
}

if ( m_goalArea && m_attackCoverArea )
{
return ANSWER_NO;
Comment thread
sunzenshen marked this conversation as resolved.
}

return ANSWER_UNDEFINED;
}

Expand Down
46 changes: 27 additions & 19 deletions src/game/server/neo/bot/behavior/neo_bot_grenade_dispatch.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@
#include "weapon_grenade.h"
#include "weapon_smokegrenade.h"

ConVar sv_neo_bot_grenade_polite_frag("sv_neo_bot_grenade_polite_frag", "1", FCVAR_NONE, "Force bots to consider teammates when throwing frag grenades.", true, 0, true, 1);
ConVar sv_neo_bot_grenade_polite_smoke("sv_neo_bot_grenade_polite_smoke", "1", FCVAR_NONE, "Force bots to consider teammates when throwing smoke grenades.", true, 0, true, 1);
Comment thread
sunzenshen marked this conversation as resolved.
ConVar sv_neo_bot_grenade_use_frag("sv_neo_bot_grenade_use_frag", "1", FCVAR_NONE, "Allow bots to use frag grenades", true, 0, true, 1);
ConVar sv_neo_bot_grenade_use_smoke("sv_neo_bot_grenade_use_smoke", "1", FCVAR_NONE, "Allow bots to use smoke grenades", true, 0, true, 1);
ConVar sv_neo_bot_grenade_throw_cooldown("sv_neo_bot_grenade_throw_cooldown", "10", FCVAR_NONE, "Cooldown in seconds between grenade throws for bots");
Expand Down Expand Up @@ -78,29 +80,32 @@ Action< CNEOBot > *CNEOBotGrenadeDispatch::ChooseGrenadeThrowBehavior( const CNE
// Should I toss a smoke grenade?
if ( pSmokeGrenade && (me->GetClass() == NEO_CLASS_SUPPORT) )
{
for ( int i = 1; i <= gpGlobals->maxClients; i++ )
if ( sv_neo_bot_grenade_polite_smoke.GetBool() )
{
CNEO_Player *pPlayer = ToNEOPlayer( UTIL_PlayerByIndex( i ) );
if ( !pPlayer || !pPlayer->IsAlive() || pPlayer == me )
for ( int i = 1; i <= gpGlobals->maxClients; i++ )
{
continue;
}
CNEO_Player *pPlayer = ToNEOPlayer( UTIL_PlayerByIndex( i ) );
if ( !pPlayer || !pPlayer->IsAlive() || pPlayer == me )
{
continue;
}

if ( !me->IsEnemy( pPlayer ) )
{
if ( !pPlayer->IsBot() && pPlayer->GetClass() != NEO_CLASS_SUPPORT )
if ( !me->IsEnemy( pPlayer ) )
{
// Avoid blocking the vision of a friendly human
// (Bots benefit from concealment without the disorientation)
return nullptr;
if ( !pPlayer->IsBot() && pPlayer->GetClass() != NEO_CLASS_SUPPORT )
{
// Avoid blocking the vision of a friendly human
// (Bots benefit from concealment without the disorientation)
return nullptr;
}
}
}
else
{
if ( pPlayer->GetClass() == NEO_CLASS_SUPPORT )
else
{
// Avoid giving an enemy with thermal vision a free smoke screen
return nullptr;
if ( pPlayer->GetClass() == NEO_CLASS_SUPPORT )
{
// Avoid giving an enemy with thermal vision a free smoke screen
return nullptr;
}
}
}
}
Expand All @@ -111,9 +116,12 @@ Action< CNEOBot > *CNEOBotGrenadeDispatch::ChooseGrenadeThrowBehavior( const CNE
// Should I toss a frag grenade?
if ( pFragGrenade )
{
if ( !CNEOBotGrenadeThrowFrag::IsFragSafe( me, threat->GetLastKnownPosition() ) )
if ( sv_neo_bot_grenade_polite_frag.GetBool() )
{
return nullptr;
if ( !CNEOBotGrenadeThrowFrag::IsFragSafe( me, threat->GetLastKnownPosition() ) )
{
return nullptr;
}
}

return new CNEOBotGrenadeThrowFrag( pFragGrenade, threat );
Expand Down
11 changes: 11 additions & 0 deletions src/game/server/neo/bot/behavior/neo_bot_grenade_throw_frag.cpp
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
#include "cbase.h"
#include "bot/neo_bot.h"
#include "bot/neo_bot_path_compute.h"
#include "bot/neo_bot_path_reservation.h"
#include "bot/behavior/neo_bot_grenade_throw_frag.h"
#include "neo_gamerules.h"
#include "neo_player.h"
#include "weapon_neobasecombatweapon.h"

#include "nav_mesh.h"
#include "nav_pathfind.h"

extern ConVar sv_neo_grenade_blast_radius;
Expand Down Expand Up @@ -106,6 +108,15 @@ CNEOBotGrenadeThrow::ThrowTargetResult CNEOBotGrenadeThrowFrag::UpdateGrenadeTar
return THROW_TARGET_CANCEL; // risk of friendly fire
}

// Register explosive hazard at the target position
// so the throwing bot's team can avoid the trajectory and landing areas
CNavArea *area = TheNavMesh->GetNearestNavArea(m_vecTarget);
if (area)
{
int team = me->GetTeamNumber();
CNEOBotPathReservations()->AddFragHazard(area->GetID(), gpGlobals->curtime + sv_neo_grenade_fuse_timer.GetFloat(), team);
Comment thread
sunzenshen marked this conversation as resolved.
}

return THROW_TARGET_READY;
}

Expand Down
31 changes: 31 additions & 0 deletions src/game/server/neo/bot/behavior/neo_bot_retreat_from_grenade.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@
#include "bot/behavior/neo_bot_retreat_from_grenade.h"
#include "bot/behavior/neo_bot_retreat_to_cover.h"
#include "bot/neo_bot_path_compute.h"
#include "bot/neo_bot_path_reservation.h"
#include "nav_mesh.h"
#include "sdk/sdk_basegrenade_projectile.h"

// memdbgon must be the last include file in a .cpp file!!!
Expand Down Expand Up @@ -72,6 +74,7 @@ class CSearchForCoverFromGrenade : public ISearchSurroundingAreasFunctor
{
m_me = me;
m_grenade = grenade;
m_onStuckPenalty = neo_bot_path_reservation_onstuck_penalty.GetFloat();
m_pGrenadeStats = dynamic_cast<CBaseGrenadeProjectile *>( grenade );
m_safeRadiusSqr = m_pGrenadeStats ? Square(m_pGrenadeStats->m_DmgRadius * sv_neo_bot_grenade_frag_safety_range_multiplier.GetFloat()) : 0.0f;

Expand All @@ -91,6 +94,20 @@ class CSearchForCoverFromGrenade : public ISearchSurroundingAreasFunctor
return false; // can't search if there's no threat source
}

// Skip areas that are hazardous or where bots get stuck
if ( neo_bot_path_reservation_enable.GetBool() )
{
int navAreaId = area->GetID();
if (CNEOBotPathReservations()->IsAreaHazardous(navAreaId, m_me))
{
return true;
}
if (CNEOBotPathReservations()->GetAreaAvoidPenalty(navAreaId) >= m_onStuckPenalty)
{
return true;
}
}

if ( m_pGrenadeStats )
{
if ( ( area->GetCenter() - m_pGrenadeStats->GetAbsOrigin() ).LengthSqr() < m_safeRadiusSqr * 2 )
Expand Down Expand Up @@ -138,6 +155,7 @@ class CSearchForCoverFromGrenade : public ISearchSurroundingAreasFunctor
CNEOBot *m_me;
CBaseEntity *m_grenade;
CBaseGrenadeProjectile *m_pGrenadeStats;
float m_onStuckPenalty;
float m_safeRadiusSqr;
CUtlVector< CNavArea * > m_coverAreaVector;
};
Expand Down Expand Up @@ -181,6 +199,19 @@ ActionResult< CNEOBot > CNEOBotRetreatFromGrenade::OnStart( CNEOBot *me, Action<
m_grenade = FindDangerousGrenade( me );
}

if ( !m_grenade ) // not a duplicate, check FindDangerousGrenade result
{
return Done("No grenade found");
}

// Register explosive hazard for the bot's team at the grenade's initial position
CNavArea *grenadeArea = TheNavMesh->GetNearestNavArea( m_grenade->GetAbsOrigin() );
if (grenadeArea)
{
int team = me->GetTeamNumber();
CNEOBotPathReservations()->AddFragHazard(grenadeArea->GetID(), gpGlobals->curtime + sv_neo_grenade_fuse_timer.GetFloat(), team);
}

// Sometimes grenades can be in a bad limbo state, so force exit eventually
m_expiryTimer.Start( sv_neo_grenade_fuse_timer.GetFloat() );

Expand Down
Loading