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.

240 lines
6.1 KiB

4 years ago
//========= Copyright Valve Corporation, All rights reserved. ============//
// tf_bot_creep_wave.cpp
// Move in a "creep wave" to the next available control point to capture it
// Michael Booth, August 2010
#include "cbase.h"
#ifdef TF_CREEP_MODE
#include "team.h"
#include "team_control_point_master.h"
#include "bot/tf_bot_manager.h"
#include "bot/tf_bot.h"
#include "bot/behavior/scenario/creep_wave/tf_bot_creep_wave.h"
ConVar tf_creep_aggro_range( "tf_creep_aggro_range", "250" );
ConVar tf_creep_give_up_range( "tf_creep_give_up_range", "300" );
CTFPlayer *FindNearestEnemy( CTFBot *me, float maxRange )
{
CBasePlayer *closest = NULL;
float closeRangeSq = maxRange * maxRange;
for( int i=1; i<=gpGlobals->maxClients; ++i )
{
CBasePlayer *player = static_cast< CBasePlayer * >( UTIL_PlayerByIndex( i ) );
if ( !player )
continue;
if ( FNullEnt( player->edict() ) )
continue;
if ( me->IsFriend( player ) )
continue;
if ( !player->IsAlive() )
continue;
float rangeSq = me->GetRangeSquaredTo( player );
if ( rangeSq < closeRangeSq )
{
if ( me->IsLineOfFireClear( player ) )
{
closeRangeSq = rangeSq;
closest = player;
}
}
}
return (CTFPlayer *)closest;
}
//---------------------------------------------------------------------------------------------
ActionResult< CTFBot > CTFBotCreepWave::OnStart( CTFBot *me, Action< CTFBot > *priorAction )
{
me->StopLookingAroundForEnemies();
m_stuckTimer.Invalidate();
me->GetPlayerClass()->SetCustomModel( "models/bots/bot_heavy.mdl", USE_CLASS_ANIMATIONS );
me->UpdateModel();
return Continue();
}
//---------------------------------------------------------------------------------------------
ActionResult< CTFBot > CTFBotCreepWave::Update( CTFBot *me, float interval )
{
if ( !me->IsAlive() && me->StateGet() != TF_STATE_DYING )
{
// remove dead creeps for now
engine->ServerCommand( UTIL_VarArgs( "kickid %d\n", me->GetUserID() ) );
}
CBaseCombatWeapon *melee = me->Weapon_GetSlot( TF_WPN_TYPE_MELEE );
if ( melee )
{
me->Weapon_Switch( melee );
}
CUtlVector< CTeamControlPoint * > captureVector;
TFGameRules()->CollectCapturePoints( me, &captureVector );
if ( captureVector.Count() == 0 )
{
return Continue();
}
if ( m_repathTimer.IsElapsed() )
{
m_repathTimer.Start( RandomFloat( 1.0f, 2.0f ) );
CTFBotPathCost cost( me, FASTEST_ROUTE );
m_path.Compute( me, captureVector[0]->WorldSpaceCenter(), cost );
}
m_path.Update( me );
if ( m_stuckTimer.HasStarted() )
{
// juke and dodge to escape stuck situation
switch( RandomInt( 0, 3 ) )
{
case 0: me->PressBackwardButton(); break;
case 1: me->PressForwardButton(); break;
case 2: me->PressLeftButton(); break;
case 3: me->PressRightButton(); break;
}
}
CTFPlayer *enemy = FindNearestEnemy( me, tf_creep_aggro_range.GetFloat() );
if ( enemy )
{
me->SpeakConceptIfAllowed( MP_CONCEPT_PLAYER_INCOMING );
return SuspendFor( new CTFBotCreepAttack( enemy ), "Attacking nearby enemy" );
}
return Continue();
}
//---------------------------------------------------------------------------------------------
EventDesiredResult< CTFBot > CTFBotCreepWave::OnKilled( CTFBot *me, const CTakeDamageInfo &info )
{
if ( info.GetAttacker() && info.GetAttacker()->IsPlayer() && me->IsEnemy( info.GetAttacker() ) )
{
TheTFBots().OnCreepKilled( ToTFPlayer( info.GetAttacker() ) );
}
return TryContinue();
}
//---------------------------------------------------------------------------------------------
EventDesiredResult< CTFBot > CTFBotCreepWave::OnStuck( CTFBot *me )
{
m_stuckTimer.Start();
return TryContinue();
}
//---------------------------------------------------------------------------------------------
EventDesiredResult< CTFBot > CTFBotCreepWave::OnUnStuck( CTFBot *me )
{
m_stuckTimer.Invalidate();
return TryContinue();
}
//---------------------------------------------------------------------------------------------
//---------------------------------------------------------------------------------------------
CTFBotCreepAttack::CTFBotCreepAttack( CTFPlayer *victim )
{
m_victim = victim;
}
//---------------------------------------------------------------------------------------------
ActionResult< CTFBot > CTFBotCreepAttack::OnStart( CTFBot *me, Action< CTFBot > *priorAction )
{
return Continue();
}
//---------------------------------------------------------------------------------------------
ActionResult< CTFBot > CTFBotCreepAttack::Update( CTFBot *me, float interval )
{
if ( !me->IsAlive() && me->StateGet() != TF_STATE_DYING )
{
// remove dead creeps for now
engine->ServerCommand( UTIL_VarArgs( "kickid %d\n", me->GetUserID() ) );
}
if ( m_victim.Get() == NULL || !m_victim->IsAlive() )
{
me->SpeakConceptIfAllowed( MP_CONCEPT_PLAYER_JEERS );
return Done( "Killed victim" );
}
if ( me->IsRangeGreaterThan( m_victim, tf_creep_give_up_range.GetFloat() ) ||
!me->IsLineOfFireClear( m_victim ) )
{
me->SpeakConceptIfAllowed( MP_CONCEPT_PLAYER_NEGATIVE );
return Done( "Lost victim" );
}
CTFPlayer *newVictim = FindNearestEnemy( me, tf_creep_aggro_range.GetFloat() );
if ( newVictim )
{
float newRangeSq = me->GetRangeSquaredTo( newVictim );
float victimRangeSq = me->GetRangeSquaredTo( m_victim );
if ( newRangeSq < victimRangeSq )
{
// switch to closer target
m_victim = newVictim;
me->SpeakConceptIfAllowed( MP_CONCEPT_PLAYER_BATTLECRY );
}
}
CBaseCombatWeapon *melee = me->Weapon_GetSlot( TF_WPN_TYPE_MELEE );
if ( melee )
{
me->Weapon_Switch( melee );
}
me->GetBodyInterface()->AimHeadTowards( m_victim, IBody::CRITICAL, 0.2f, NULL, "Looking at enemy" );
// swing weapon
me->PressFireButton();
// beeline towards our victim
const float combatRange = 40.0f;
if ( me->IsRangeGreaterThan( m_victim, combatRange ) )
{
me->GetLocomotionInterface()->Approach( m_victim->GetAbsOrigin() );
}
else
{
// juke and dodge to avoid interpenetration
switch( RandomInt( 0, 3 ) )
{
case 0: me->PressBackwardButton(); break;
case 1: me->PressForwardButton(); break;
case 2: me->PressLeftButton(); break;
case 3: me->PressRightButton(); break;
}
}
return Continue();
}
#endif // TF_CREEP_MODE