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
240 lines
6.1 KiB
//========= 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
|