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.

247 lines
6.4 KiB

5 years ago
//========= Copyright Valve Corporation, All rights reserved. ============//
// bot_npc_decoy.cpp
// A NextBot non-player decoy that imitates a real player
// Michael Booth, January 2011
#include "cbase.h"
#include "tf_player.h"
#include "tf_gamerules.h"
#include "tf_team.h"
#include "nav_mesh/tf_nav_area.h"
#include "bot_npc_decoy.h"
#include "econ_wearable.h"
LINK_ENTITY_TO_CLASS( bot_npc_decoy, CBotNPCDecoy );
PRECACHE_REGISTER( bot_npc_decoy );
ConVar tf_decoy_lifetime( "tf_decoy_lifetime", "5", FCVAR_CHEAT, "The lifetime of a decoy, in seconds" );
//-----------------------------------------------------------------------------------------------------
CBotNPCDecoy::CBotNPCDecoy()
{
ALLOCATE_INTENTION_INTERFACE( CBotNPCDecoy );
m_locomotor = new CBotNPCDecoyLocomotion( this );
m_body = new CBotNPCBody( this );
m_eyeOffset = vec3_origin;
}
//-----------------------------------------------------------------------------------------------------
CBotNPCDecoy::~CBotNPCDecoy()
{
DEALLOCATE_INTENTION_INTERFACE;
if ( m_locomotor )
delete m_locomotor;
if ( m_body )
delete m_body;
}
//-----------------------------------------------------------------------------------------------------
void CBotNPCDecoy::Precache()
{
BaseClass::Precache();
}
//-----------------------------------------------------------------------------------------------------
void CBotNPCDecoy::Spawn( void )
{
BaseClass::Spawn();
SetCollisionGroup( COLLISION_GROUP_NONE );
SetSolid( SOLID_NONE );
AddSolidFlags( FSOLID_NOT_SOLID );
CTFPlayer *owner = ToTFPlayer( GetOwnerEntity() );
if ( !owner )
{
Warning( "Decoy spawned without an owner\n" );
return;
}
int ownerClass = owner->m_Shared.InCond( TF_COND_DISGUISED ) ? owner->m_Shared.GetDisguiseClass() : owner->GetPlayerClass()->GetClassIndex();
int ownerTeam = owner->m_Shared.InCond( TF_COND_DISGUISED ) ? owner->m_Shared.GetDisguiseTeam() : owner->GetTeamNumber();
SetModel( GetPlayerClassData( ownerClass )->m_szModelName );
ChangeTeam( ownerTeam );
if ( ownerTeam == TF_TEAM_BLUE )
{
m_nSkin = 1;
}
else
{
m_nSkin = 0;
}
SetAbsOrigin( owner->GetAbsOrigin() );
SetAbsAngles( owner->GetAbsAngles() );
SetAbsVelocity( owner->GetAbsVelocity() );
Vector headPos;
QAngle headAngles;
if ( GetAttachment( "head", headPos, headAngles ) )
{
m_eyeOffset = headPos - GetAbsOrigin();
}
CTFWeaponBase *theirWeapon = owner->m_Shared.GetDisguiseWeapon();
if ( !theirWeapon )
{
theirWeapon = owner->GetActiveTFWeapon();
}
if ( theirWeapon )
{
CBaseAnimating *weapon = (CBaseAnimating *)CreateEntityByName( "prop_dynamic" );
if ( weapon )
{
weapon->SetModel( theirWeapon->GetWorldModel() );
// bonemerge the weapon into our model
weapon->FollowEntity( this, true );
// choose the appropriate run animation for this weapon
switch( theirWeapon->GetTFWpnData().m_iWeaponType )
{
case TF_WPN_TYPE_PRIMARY:
m_runActivity = ACT_MP_RUN_PRIMARY;
break;
case TF_WPN_TYPE_SECONDARY:
m_runActivity = ACT_MP_RUN_SECONDARY;
break;
case TF_WPN_TYPE_MELEE:
default:
m_runActivity = ACT_MP_RUN_MELEE;
break;
}
}
}
}
//---------------------------------------------------------------------------------------------
unsigned int CBotNPCDecoy::PhysicsSolidMaskForEntity( void ) const
{
// Only collide with the other team
int teamContents = ( GetTeamNumber() == TF_TEAM_RED ) ? CONTENTS_BLUETEAM : CONTENTS_REDTEAM;
return BaseClass::PhysicsSolidMaskForEntity() | teamContents;
}
//---------------------------------------------------------------------------------------------
bool CBotNPCDecoy::ShouldCollide( int collisionGroup, int contentsMask ) const
{
if ( collisionGroup == COLLISION_GROUP_PLAYER_MOVEMENT )
{
switch( GetTeamNumber() )
{
case TF_TEAM_RED:
if ( !( contentsMask & CONTENTS_REDTEAM ) )
return false;
break;
case TF_TEAM_BLUE:
if ( !( contentsMask & CONTENTS_BLUETEAM ) )
return false;
break;
}
}
return BaseClass::ShouldCollide( collisionGroup, contentsMask );
}
//---------------------------------------------------------------------------------------------
//---------------------------------------------------------------------------------------------
float CBotNPCDecoyLocomotion::GetRunSpeed( void ) const
{
CTFPlayer *owner = ToTFPlayer( GetBot()->GetEntity()->GetOwnerEntity() );
if ( !owner )
{
return 0.0f;
}
int ownerClass = owner->m_Shared.InCond( TF_COND_DISGUISED ) ? owner->m_Shared.GetDisguiseClass() : owner->GetPlayerClass()->GetClassIndex();
return GetPlayerClassData( ownerClass )->m_flMaxSpeed;
}
//---------------------------------------------------------------------------------------------
// return maximum acceleration of locomotor
float CBotNPCDecoyLocomotion::GetMaxAcceleration( void ) const
{
return 1500.0f;
}
//---------------------------------------------------------------------------------------------
// return maximum deceleration of locomotor
float CBotNPCDecoyLocomotion::GetMaxDeceleration( void ) const
{
return 1500.0f;
}
//---------------------------------------------------------------------------------------------
//---------------------------------------------------------------------------------------------
class CBotNPCDecoyBehavior : public Action< CBotNPCDecoy >
{
public:
virtual ActionResult< CBotNPCDecoy > OnStart( CBotNPCDecoy *me, Action< CBotNPCDecoy > *priorAction )
{
m_timer.Start( tf_decoy_lifetime.GetFloat() );
// play running animation
if ( !me->GetBodyInterface()->IsActivity( me->GetRunActivity() ) )
{
me->GetBodyInterface()->StartActivity( me->GetRunActivity() );
}
return Continue();
}
virtual ActionResult< CBotNPCDecoy > Update( CBotNPCDecoy *me, float interval )
{
if ( m_timer.IsElapsed() )
{
// we're out of time
UTIL_Remove( me );
return Done( "Lifetime expired" );
}
CTFPlayer *owner = ToTFPlayer( me->GetOwnerEntity() );
if ( !owner )
{
UTIL_Remove( me );
return Done( "No owner!" );
}
Vector forward;
me->GetVectors( &forward, NULL, NULL );
me->GetLocomotionInterface()->SetDesiredSpeed( FLT_MAX ); // this is just a rate limiter
me->GetLocomotionInterface()->Run();
me->GetLocomotionInterface()->Approach( me->GetAbsOrigin() + 100.0f * forward );
return Continue();
}
virtual const char *GetName( void ) const { return "Behavior"; } // return name of this action
private:
CountdownTimer m_timer;
};
IMPLEMENT_INTENTION_INTERFACE( CBotNPCDecoy, CBotNPCDecoyBehavior );