diff options
Diffstat (limited to 'game/server/tf/bot_npc/bot_npc_decoy.cpp')
| -rw-r--r-- | game/server/tf/bot_npc/bot_npc_decoy.cpp | 246 |
1 files changed, 246 insertions, 0 deletions
diff --git a/game/server/tf/bot_npc/bot_npc_decoy.cpp b/game/server/tf/bot_npc/bot_npc_decoy.cpp new file mode 100644 index 0000000..757a467 --- /dev/null +++ b/game/server/tf/bot_npc/bot_npc_decoy.cpp @@ -0,0 +1,246 @@ +//========= 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 ); + |