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
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,20 @@ ActionResult<CNEOBot> CNEOBotRetreatFromHazardArea::Update(CNEOBot *me, float in
CNEOBotPathCompute(me, m_path, m_safeArea->GetCenter(), RETREAT_ROUTE);
}

// Possibly don't want to cloak with grenade/smoke hazards yet
// because in such situations either the threat noticed you already
// or because they didn't notice you yet, you shouldn't announce your position
if (CNEOBotPathReservations()->IsAreaNpcTurretHazard(myArea->GetID(), me))
{
me->EnableCloak(3.0f);
if (me->IsCloakEnabled())
{
// The tank's motion vision only ignores cloaked players under 180 u/s
me->ReleaseRunButton();
me->PressSneakButton(0.3f);
}
}
Comment thread
sunmachine marked this conversation as resolved.

m_path.Update(me);
return Continue();
}
Expand Down
31 changes: 31 additions & 0 deletions src/game/server/neo/bot/behavior/neo_bot_tactical_monitor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -316,6 +316,33 @@ ActionResult< CNEOBot > CNEOBotTacticalMonitor::WatchForLadders( CNEOBot *me )
}


//-----------------------------------------------------------------------------------------
// A bot in a hurry does not retreat from the tank, so it cloaks in the tank's line of fire and keeps going:
// the tank's motion vision ignores cloaked players under 180 u/s
void CNEOBotTacticalMonitor::CloakPastNpcTurret( CNEOBot *me )
{
if ( me->m_hCommandingPlayer.Get() )
{
return;
}

CNavArea *myArea = me->GetLastKnownArea();
if ( !myArea || !CNEOBotPathReservations()->IsAreaNpcTurretHazard( myArea->GetID(), me ) )
{
return;
}

me->EnableCloak( 3.0f );

// An Assault stays under that speed unless it sprints, while a Recon is over it anyway and keeps its pace
if ( me->IsCloakEnabled() && ( me->GetClass() == NEO_CLASS_ASSAULT ) )
{
// the child behaviors moved first this update, so this cancels their run press
me->ReleaseRunButton();
}
}


//-----------------------------------------------------------------------------------------
ActionResult< CNEOBot > CNEOBotTacticalMonitor::Update( CNEOBot *me, float interval )
{
Expand Down Expand Up @@ -394,6 +421,10 @@ ActionResult< CNEOBot > CNEOBotTacticalMonitor::Update( CNEOBot *me, float inter
return scavengeResult;
}
}
else
{
CloakPastNpcTurret( me );
}

#if 0 // NEO TODO (Adam) search for dropped weapons to resupply ammunition
bool isAvailable = ( me->GetIntentionInterface()->ShouldHurry( me ) != ANSWER_YES );
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,4 +41,5 @@ class CNEOBotTacticalMonitor : public Action< CNEOBot >

void AvoidBumpingFriends(CNEOBot* me);
ActionResult< CNEOBot > WatchForLadders(CNEOBot* me);
void CloakPastNpcTurret(CNEOBot* me);
};
94 changes: 93 additions & 1 deletion src/game/server/neo/bot/neo_bot_path_reservation.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -340,6 +340,7 @@ void CNEOBotPathReservationSystem::AddDeadlyHazard(int navAreaID, float expireTi
blank.hazardExpireTime = expireTime;
blank.smokeExpireTime = 0.0f;
blank.smokePropagateTime = 0.0f;
blank.npcTurretExpireTime = 0.0f;
index = m_HazardAreas[teamID].Insert(navAreaID, blank);
}
else
Expand Down Expand Up @@ -414,6 +415,7 @@ void CNEOBotPathReservationSystem::AddSmokeHazard(int navAreaID, float expireTim
blank.hazardExpireTime = 0.0f;
blank.smokeExpireTime = expireTime;
blank.smokePropagateTime = 0.0f;
blank.npcTurretExpireTime = 0.0f;
index = m_HazardAreas[teamID].Insert(navAreaID, blank);
}
else
Expand Down Expand Up @@ -444,6 +446,90 @@ void CNEOBotPathReservationSystem::AddSmokeHazard(int navAreaID, float expireTim
}
}

//-------------------------------------------------------------------------------------------------
// Functor to propagate a neo_npc_targetsystem turret hazard to PVS-adjacent areas
struct CNEOFunctorPropagatePVSNpcTurretHazard
{
CNEOFunctorPropagatePVSNpcTurretHazard(float expireTime, int teamID)
: m_expireTime(expireTime), m_teamID(teamID)
{
}

bool operator()(CNavArea *area)
{
CNEOBotPathReservations()->AddNpcTurretHazard(area->GetID(), m_expireTime, m_teamID, false);
return true;
}

float m_expireTime;
int m_teamID;
};

//-------------------------------------------------------------------------------------------------
// Area tagged by neo_npc_targetsystem turret, whose motion vision
// cannot see slow cloaked players, so bots escaping it should cloak
void CNEOBotPathReservationSystem::AddNpcTurretHazard(int navAreaID, float expireTime, int teamID, bool propagatePVS)
{
if ( !neo_bot_path_reservation_avoid_penalty_enable.GetBool() )
{
return;
}

if ( (teamID < 0) || (teamID >= TEAM__TOTAL) )
{
return;
}

// Kept apart from deadly hazards, so a bot in a hurry can accept the turret's risk
int index = m_HazardAreas[teamID].Find(navAreaID);
if ( !m_HazardAreas[teamID].IsValidIndex(index) )
{
HazardInfo blank;
blank.hazardExpireTime = 0.0f;
blank.smokeExpireTime = 0.0f;
blank.smokePropagateTime = 0.0f;
blank.npcTurretExpireTime = 0.0f;
index = m_HazardAreas[teamID].Insert(navAreaID, blank);
}

// Inform the bots in every area the turret can see to turn on cloak
m_HazardAreas[teamID][index].npcTurretExpireTime = expireTime;

if ( propagatePVS )
{
CNavArea *area = TheNavMesh->GetNavAreaByID(navAreaID);
if (area)
{
// Same visible set as a propagated deadly hazard
CNEOFunctorPropagatePVSNpcTurretHazard propagate(expireTime, teamID);
area->ForAllCompletelyVisibleAreas(propagate);
}
}
}

//-------------------------------------------------------------------------------------------------
bool CNEOBotPathReservationSystem::IsAreaNpcTurretHazard(int navAreaID, const CNEOBot *me) const
{
if ( !neo_bot_path_reservation_avoid_penalty_enable.GetBool() || !me )
{
return false;
}

int teamID = me->GetTeamNumber();
if ( (teamID < 0) || (teamID >= TEAM__TOTAL) )
{
return false;
}

int index = m_HazardAreas[teamID].Find(navAreaID);
if ( !m_HazardAreas[teamID].IsValidIndex(index) )
{
return false;
}

return m_HazardAreas[teamID][index].npcTurretExpireTime > gpGlobals->curtime;
}

//-------------------------------------------------------------------------------------------------
float CNEOBotPathReservationSystem::GetAreaHazardousTime(int navAreaID, const CNEOBot *me) const
{
Expand Down Expand Up @@ -476,6 +562,12 @@ float CNEOBotPathReservationSystem::GetAreaHazardousTime(int navAreaID, const CN
return hazardTimeLeft;
}

auto npcTurretTimeLeft = h.npcTurretExpireTime - gpGlobals->curtime;
if (npcTurretTimeLeft > 0)
{
return npcTurretTimeLeft;
}

// Support class can see through smoke
if (me->GetClass() != NEO_CLASS_SUPPORT)
{
Expand All @@ -497,7 +589,7 @@ bool CNEOBotPathReservationSystem::IsAreaHazardous(int navAreaID, const CNEOBot
}

//-------------------------------------------------------------------------------------------------
// Unlike IsAreaHazardous, smoke does not count: only marks that can kill, such as a frag grenade's blast area
// Unlike IsAreaHazardous, smoke and the turret's sightline do not count: only marks that can kill, such as a frag grenade's blast area
bool CNEOBotPathReservationSystem::IsAreaDeadlyHazard(int navAreaID, const CNEOBot *me) const
{
if (!neo_bot_path_reservation_avoid_penalty_enable.GetBool())
Expand Down
3 changes: 3 additions & 0 deletions src/game/server/neo/bot/neo_bot_path_reservation.h
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ struct HazardInfo
float smokeExpireTime; // when the smoke hazard risk expires
float hazardExpireTime; // when a general deadly hazard risk expires
float smokePropagateTime; // expiry this area has already propagated to its visible set
float npcTurretExpireTime; // when a neo_npc_targetsystem hazard expires
};

struct BotReservedAreas_t
Expand Down Expand Up @@ -89,6 +90,8 @@ class CNEOBotPathReservationSystem
void AddDeadlyHazard(int navAreaID, float expireTime, int teamID, bool propagatePVS = false);
void AddFragHazard(int navAreaID, float expireTime, int teamID);
void AddSmokeHazard(int navAreaID, float expireTime, int teamID, bool propagatePVS = true);
void AddNpcTurretHazard(int navAreaID, float expireTime, int teamID, bool propagatePVS = true);
bool IsAreaNpcTurretHazard(int navAreaID, const CNEOBot *me) const;
float GetAreaHazardousTime(int navAreaID, const CNEOBot *me) const;
bool IsAreaHazardous(int navAreaID, const CNEOBot *me) const;
bool IsAreaDeadlyHazard(int navAreaID, const CNEOBot *me) const;
Expand Down
88 changes: 88 additions & 0 deletions src/game/server/neo/neo_npc_targetsystem.cpp
Original file line number Diff line number Diff line change
@@ -1,11 +1,19 @@
#include "neo_npc_targetsystem.h"
#include "neo_player.h"
#include "ammodef.h"
#include "nav_mesh.h"
#include "NextBotManager.h"
#include "bot/neo_bot_path_reservation.h"

#include "tier0/memdbgon.h"

#define CLOAKED_VELOCITY_THRESHOLD 32400 // 180 horizontal velocity. Slightly under sprint/wigglerun speed

// Bot hazard timing
static constexpr float BOT_HAZARD_REACTION_TIME = 0.25f;
static constexpr float BOT_HAZARD_INTERVAL = BOT_HAZARD_REACTION_TIME;
static constexpr float BOT_HAZARD_DURATION = 2.0f;

LINK_ENTITY_TO_CLASS(neo_npc_targetsystem, CNEO_NPCTargetSystem);

BEGIN_DATADESC(CNEO_NPCTargetSystem)
Expand Down Expand Up @@ -185,6 +193,7 @@ void CNEO_NPCTargetSystem::Think()
{
m_OnSpotted.FireOutput(pBestTarget, this);
m_bTargetAcquired = true;
m_flNextHazardTime = gpGlobals->curtime + BOT_HAZARD_REACTION_TIME;
}

if (bMiddleIgnore && !m_bMiddleIgnoreActive)
Expand Down Expand Up @@ -234,6 +243,8 @@ void CNEO_NPCTargetSystem::Think()
m_bMiddleIgnoreActive = false;
}

PublishBotHazards(pBestTarget);

// Optional - damage the target
if (m_hDamageSource && pBestTarget && (iNewZone == ZONE_MIDDLE))
{
Expand All @@ -260,6 +271,83 @@ void CNEO_NPCTargetSystem::Think()
SetNextThink(gpGlobals->curtime + 0.05f);
}

//-----------------------------------------------------------------------------
// Bot hazard publishing - Bots cannot fight this entity.
// Hazards: its own area for every team (run-over), the areas it can see
// for targeted teams, and its targeted player's area once acquired.
//-----------------------------------------------------------------------------

void CNEO_NPCTargetSystem::PublishBotHazards(CBasePlayer *pTarget)
{
if (!TheNavMesh->IsLoaded() || TheNextBots().GetNextBotCount() == 0)
{
return;
}

if (gpGlobals->curtime < m_flNextHazardTime)
{
return;
}

m_flNextHazardTime = gpGlobals->curtime + BOT_HAZARD_INTERVAL;
const float flExpireTime = gpGlobals->curtime + BOT_HAZARD_DURATION;

// A team is targeted if a living member passes the filter; on ntre_rogue_ctg
// the filter swaps on ghost pickup so the carrier's team is left out
bool bTeamTargeted[TEAM__TOTAL] = {};
for (int i = 1; i <= gpGlobals->maxClients; i++)
{
CBasePlayer *pPlayer = UTIL_PlayerByIndex(i);
if (!pPlayer || !pPlayer->IsAlive() || pPlayer->GetTeamNumber() < FIRST_GAME_TEAM)
{
continue;
}

if (!m_pFilter || m_pFilter->PassesFilter(this, pPlayer))
{
bTeamTargeted[pPlayer->GetTeamNumber()] = true;
}
}

// Mark areas PVS to the tank as do not hang out in my view
CNavArea *pOwnArea = TheNavMesh->GetNearestNavArea(GetAbsOrigin());
if (pOwnArea)
{
for (int iTeam = FIRST_GAME_TEAM; iTeam < TEAM__TOTAL; ++iTeam)
{
// Being run over is deadly even for a bot in a hurry, unlike the turret's sightline
CNEOBotPathReservations()->AddDeadlyHazard(pOwnArea->GetID(), flExpireTime, iTeam);

if (bTeamTargeted[iTeam])
{
AddVisibleHazard(pOwnArea, iTeam, flExpireTime);
}
}
Comment thread
sunmachine marked this conversation as resolved.
}

if (pTarget)
{
CNavArea *pTargetArea = TheNavMesh->GetNearestNavArea(pTarget->GetAbsOrigin());
if (pTargetArea)
{
// Don't propagate the PVS for the targeted bot location to avoid marking the areas around the corner
AddVisibleHazard(pTargetArea, pTarget->GetTeamNumber(), flExpireTime, false);
}
}
}

void CNEO_NPCTargetSystem::AddVisibleHazard(CNavArea *pArea, int iTeam, float flExpireTime, bool bPropagatePVS)
{
if (m_bMotionVision)
{
CNEOBotPathReservations()->AddNpcTurretHazard(pArea->GetID(), flExpireTime, iTeam, bPropagatePVS);
}
else
{
CNEOBotPathReservations()->AddDeadlyHazard(pArea->GetID(), flExpireTime, iTeam, bPropagatePVS);
}
}
Comment thread
sunmachine marked this conversation as resolved.

bool CNEO_NPCTargetSystem::CanSee(CBaseEntity *pEntity)
{
if (m_pFilter && m_pFilter->PassesFilter(this, pEntity))
Expand Down
6 changes: 6 additions & 0 deletions src/game/server/neo/neo_npc_targetsystem.h
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@
#include "cbase.h"
#include "filters.h"

class CNavArea;

class CNEO_NPCTargetSystem : public CBaseEntity
{
public:
Expand Down Expand Up @@ -45,6 +47,9 @@ class CNEO_NPCTargetSystem : public CBaseEntity
bool CanSee(CBaseEntity *pEntity);

private:
void PublishBotHazards(CBasePlayer *pTarget);
void AddVisibleHazard(CNavArea *pArea, int iTeam, float flExpireTime, bool bPropagatePVS = true);

enum TargetZone_e
{
ZONE_NONE = 0,
Expand All @@ -58,4 +63,5 @@ class CNEO_NPCTargetSystem : public CBaseEntity
bool m_bMiddleIgnoreActive = false;
float m_flNextFireTime = 0;
CBasePlayer *m_pLastBestTarget = nullptr;
float m_flNextHazardTime = 0;
};
Loading