Modified source engine (2017) developed by valve and leaked in 2020. Not for commercial purporses
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

262 lines
7.9 KiB

4 years ago
//========= Copyright Valve Corporation, All rights reserved. ============//
// tf_bot_guard_area.cpp
// Defend an area against intruders
// Michael Booth, October 2009
#include "cbase.h"
#ifdef TF_RAID_MODE
#include "tf_player.h"
#include "bot/tf_bot.h"
#include "team_control_point_master.h"
#include "econ_entity_creation.h"
#include "bot/behavior/tf_bot_retreat_to_cover.h"
#include "bot/behavior/sniper/tf_bot_sniper_attack.h"
#include "bot/behavior/engineer/tf_bot_engineer_build.h"
#include "bot/behavior/medic/tf_bot_medic_heal.h"
#include "bot/behavior/scenario/raid/tf_bot_wander.h"
#include "bot/behavior/scenario/raid/tf_bot_guard_area.h"
#include "bot/behavior/tf_bot_attack.h"
#include "bot/behavior/demoman/tf_bot_prepare_stickybomb_trap.h"
#include "nav_mesh.h"
extern ConVar tf_bot_path_lookahead_range;
ConVar tf_bot_guard_aggro_range( "tf_bot_guard_aggro_range", "750", FCVAR_CHEAT );
//ConVar tf_bot_guard_give_up_range( "tf_bot_guard_give_up_range", "1250", FCVAR_CHEAT );
ConVar tf_raid_special_vocalize_min_interval( "tf_raid_special_vocalize_min_interval", "10", FCVAR_CHEAT );
ConVar tf_raid_special_vocalize_max_interval( "tf_raid_special_vocalize_max_interval", "15", FCVAR_CHEAT );
//---------------------------------------------------------------------------------------------
ActionResult< CTFBot > CTFBotGuardArea::OnStart( CTFBot *me, Action< CTFBot > *priorAction )
{
m_chasePath.SetMinLookAheadDistance( me->GetDesiredPathLookAheadRange() );
/*
// give this guy a hat!
randomitemcriteria_t criteria;
criteria.iItemLevel = AE_USE_SCRIPT_VALUE;
criteria.iItemQuality = AE_USE_SCRIPT_VALUE;
criteria.vecAbsOrigin = me->GetAbsOrigin();
criteria.vecAbsAngles = vec3_angle;
switch( me->GetPlayerClass()->GetClassIndex() )
{
case TF_CLASS_SCOUT: criteria.pszItemName = "Scout Hat 1"; break;
case TF_CLASS_SNIPER: criteria.pszItemName = "Sniper Hat 1"; break;
case TF_CLASS_SOLDIER: criteria.pszItemName = "Soldier Pot Hat"; break;
case TF_CLASS_DEMOMAN: criteria.pszItemName = "Demo Top Hat"; break;
case TF_CLASS_MEDIC: criteria.pszItemName = "Medic Hat 1"; break;
case TF_CLASS_HEAVYWEAPONS: criteria.pszItemName = "Heavy Ushanka Hat"; break;
case TF_CLASS_PYRO: criteria.pszItemName = "Pyro Chicken Hat"; break;
case TF_CLASS_SPY: criteria.pszItemName = "Spy Derby Hat"; break;
case TF_CLASS_ENGINEER: criteria.pszItemName = "Engineer Hat 1"; break;
default: criteria.pszItemName = ""; break;
}
CBaseEntity *hat = ItemGeneration()->GenerateRandomItem( &criteria );
if ( hat )
{
// Fake global id
static int s_nFakeID = 1;
static_cast< CEconEntity * >( hat )->GetAttributeContainer()->GetItem()->SetItemID( s_nFakeID++ );
DispatchSpawn( hat );
static_cast< CEconEntity * >( hat )->GetAttributeContainer()->GetItem()->GenerateAttributes();
static_cast< CEconEntity * >( hat )->GiveTo( me );
}
else
{
Msg( "Failed to create hat\n" );
}
*/
return Continue();
}
//---------------------------------------------------------------------------------------------
class CFindVantagePoint : public ISearchSurroundingAreasFunctor
{
public:
CFindVantagePoint( void )
{
m_vantageArea = NULL;
}
virtual bool operator() ( CNavArea *baseArea, CNavArea *priorArea, float travelDistanceSoFar )
{
if ( travelDistanceSoFar > 2000.0f )
return false;
CTFNavArea *area = (CTFNavArea *)baseArea;
CTeam *raidingTeam = GetGlobalTeam( TF_TEAM_BLUE );
for( int i=0; i<raidingTeam->GetNumPlayers(); ++i )
{
CTFPlayer *player = (CTFPlayer *)raidingTeam->GetPlayer(i);
if ( !player->IsAlive() || !player->GetLastKnownArea() )
continue;
CTFNavArea *playerArea = (CTFNavArea *)player->GetLastKnownArea();
if ( playerArea->IsCompletelyVisible( area ) )
{
// nearby area from which we can see the enemy team
m_vantageArea = area;
return false;
}
}
return true;
}
CTFNavArea *m_vantageArea;
};
//---------------------------------------------------------------------------------------------
ActionResult< CTFBot > CTFBotGuardArea::Update( CTFBot *me, float interval )
{
// emit vocalizations to warn players we're in the area
if ( m_vocalizeTimer.IsElapsed() )
{
m_vocalizeTimer.Start( RandomFloat( tf_raid_special_vocalize_min_interval.GetFloat(), tf_raid_special_vocalize_max_interval.GetFloat() ) );
me->SpeakConceptIfAllowed( MP_CONCEPT_PLAYER_JEERS );
}
if ( me->IsPlayerClass( TF_CLASS_MEDIC ) )
{
return SuspendFor( new CTFBotMedicHeal );
}
if ( me->IsPlayerClass( TF_CLASS_ENGINEER ) )
{
return SuspendFor( new CTFBotEngineerBuild );
}
const CKnownEntity *threat = me->GetVisionInterface()->GetPrimaryKnownThreat();
if ( threat && threat->IsVisibleRecently() )
{
m_pathToVantageArea.Invalidate();
CTFNavArea *myArea = (CTFNavArea *)me->GetLastKnownArea();
CTFNavArea *threatArea = (CTFNavArea *)threat->GetLastKnownArea();
if ( myArea && threatArea )
{
if ( threatArea->GetIncursionDistance( TF_TEAM_BLUE ) < myArea->GetIncursionDistance( TF_TEAM_BLUE ) )
{
if ( me->IsRangeGreaterThan( threat->GetLastKnownPosition(), tf_bot_guard_aggro_range.GetFloat() ) )
{
// threat is far off and hasn't reached us yet - hide until they are closer
return SuspendFor( new CTFBotRetreatToCover, "Hiding until threat gets closer" );
}
}
}
// attack!
return SuspendFor( new CTFBotAttack, "Attacking nearby threat" );
}
else
{
// no enemy is visible
Vector moveTo = me->GetAbsOrigin();
// if point is being captured, move to it
CTeamControlPoint *point = me->GetMyControlPoint();
if ( point && point->LastContestedAt() > 0.0f && ( gpGlobals->curtime - point->LastContestedAt() ) < 5.0f )
{
// the point is, or was very recently, contested - defend it!
moveTo = point->GetAbsOrigin();
}
else if ( me->GetHomeArea() )
{
// no enemy is visible - return to our home position
moveTo = me->GetHomeArea()->GetCenter();
}
if ( !m_pathToPoint.IsValid() || m_repathTimer.IsElapsed() )
{
CTFBotPathCost cost( me, FASTEST_ROUTE );
m_pathToPoint.Compute( me, moveTo, cost );
m_repathTimer.Start( RandomFloat( 2.0f, 3.0f ) );
}
if ( ( me->GetAbsOrigin() - moveTo ).IsLengthGreaterThan( 25.0f ) )
{
m_pathToPoint.Update( me );
}
if ( me->GetHomeArea() == me->GetLastKnownArea() )
{
// at home
if ( CTFBotPrepareStickybombTrap::IsPossible( me ) )
{
return SuspendFor( new CTFBotPrepareStickybombTrap, "Laying sticky bombs!" );
}
}
/*
// no enemy is visible - move to where we can see them
if ( !m_pathToVantageArea.IsValid() )
{
CTFNavArea *vantageArea = me->FindVantagePoint();
if ( vantageArea )
{
CTFBotPathCost cost( me, FASTEST_ROUTE );
m_pathToVantageArea.Compute( me, vantageArea->GetCenter(), cost );
}
}
m_pathToVantageArea.Update( me );
*/
}
return Continue();
}
//---------------------------------------------------------------------------------------------
EventDesiredResult< CTFBot > CTFBotGuardArea::OnStuck( CTFBot *me )
{
m_chasePath.Invalidate();
m_pathToPoint.Invalidate();
m_pathToVantageArea.Invalidate();
return TryContinue();
}
//---------------------------------------------------------------------------------------------
EventDesiredResult< CTFBot > CTFBotGuardArea::OnMoveToSuccess( CTFBot *me, const Path *path )
{
return TryContinue();
}
//---------------------------------------------------------------------------------------------
EventDesiredResult< CTFBot > CTFBotGuardArea::OnMoveToFailure( CTFBot *me, const Path *path, MoveToFailureType reason )
{
return TryContinue();
}
//---------------------------------------------------------------------------------------------
QueryResultType CTFBotGuardArea::ShouldRetreat( const INextBot *me ) const
{
return ANSWER_NO;
}
//---------------------------------------------------------------------------------------------
EventDesiredResult< CTFBot > CTFBotGuardArea::OnCommandApproach( CTFBot *me, const Vector &pos, float range )
{
return TryContinue();
}
#endif // TF_RAID_MODE