mirror of
https://github.com/nillerusr/source-engine.git
synced 2026-08-17 22:11:58 +00:00
1
This commit is contained in:
@@ -0,0 +1,240 @@
|
||||
//========= 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
|
||||
@@ -0,0 +1,57 @@
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
// tf_bot_creep_wave.h
|
||||
// Move in a "creep wave" to the next available control point to capture it
|
||||
// Michael Booth, August 2010
|
||||
|
||||
#ifndef TF_BOT_CREEP_WAVE_H
|
||||
#define TF_BOT_CREEP_WAVE_H
|
||||
|
||||
#ifdef TF_CREEP_MODE
|
||||
|
||||
#include "Path/NextBotPathFollow.h"
|
||||
#include "Path/NextBotChasePath.h"
|
||||
|
||||
|
||||
CTFBot *FindNearestEnemyCreep( CTFBot *me );
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
class CTFBotCreepWave : public Action< CTFBot >
|
||||
{
|
||||
public:
|
||||
virtual ActionResult< CTFBot > OnStart( CTFBot *me, Action< CTFBot > *priorAction );
|
||||
virtual ActionResult< CTFBot > Update( CTFBot *me, float interval );
|
||||
|
||||
virtual EventDesiredResult< CTFBot > OnKilled( CTFBot *me, const CTakeDamageInfo &info );
|
||||
virtual EventDesiredResult< CTFBot > OnStuck( CTFBot *me );
|
||||
virtual EventDesiredResult< CTFBot > OnUnStuck( CTFBot *me );
|
||||
|
||||
virtual const char *GetName( void ) const { return "CreepWave"; };
|
||||
|
||||
private:
|
||||
PathFollower m_path;
|
||||
CountdownTimer m_repathTimer;
|
||||
IntervalTimer m_stuckTimer;
|
||||
};
|
||||
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
class CTFBotCreepAttack : public Action< CTFBot >
|
||||
{
|
||||
public:
|
||||
CTFBotCreepAttack( CTFPlayer *victim );
|
||||
|
||||
virtual ActionResult< CTFBot > OnStart( CTFBot *me, Action< CTFBot > *priorAction );
|
||||
virtual ActionResult< CTFBot > Update( CTFBot *me, float interval );
|
||||
|
||||
virtual const char *GetName( void ) const { return "CreepAttack"; };
|
||||
|
||||
private:
|
||||
CHandle< CTFPlayer > m_victim;
|
||||
};
|
||||
|
||||
|
||||
#endif // TF_CREEP_MODE
|
||||
|
||||
#endif // TF_BOT_CREEP_WAVE_H
|
||||
Reference in New Issue
Block a user