summaryrefslogtreecommitdiff
path: root/game/server/tf/bot_npc/bot_npc_archer.cpp
diff options
context:
space:
mode:
authorFluorescentCIAAfricanAmerican <[email protected]>2020-04-22 12:56:21 -0400
committerFluorescentCIAAfricanAmerican <[email protected]>2020-04-22 12:56:21 -0400
commit3bf9df6b2785fa6d951086978a3e66f49427166a (patch)
tree2c0f1f0c63c4832882bc93814ebd2c2b1c6224e5 /game/server/tf/bot_npc/bot_npc_archer.cpp
downloadarchived-source-engine-2018-hl2-src-master.tar.xz
archived-source-engine-2018-hl2-src-master.zip
Diffstat (limited to 'game/server/tf/bot_npc/bot_npc_archer.cpp')
-rw-r--r--game/server/tf/bot_npc/bot_npc_archer.cpp402
1 files changed, 402 insertions, 0 deletions
diff --git a/game/server/tf/bot_npc/bot_npc_archer.cpp b/game/server/tf/bot_npc/bot_npc_archer.cpp
new file mode 100644
index 0000000..592def4
--- /dev/null
+++ b/game/server/tf/bot_npc/bot_npc_archer.cpp
@@ -0,0 +1,402 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+// bot_npc_archer.cpp
+// A NextBot non-player derived archer
+// Michael Booth, November 2010
+
+#include "cbase.h"
+
+#include "tf_player.h"
+#include "tf_gamerules.h"
+#include "tf_team.h"
+#include "tf_projectile_arrow.h"
+#include "tf_weapon_grenade_pipebomb.h"
+#include "nav_mesh/tf_nav_area.h"
+#include "bot_npc_archer.h"
+#include "NextBot/Path/NextBotChasePath.h"
+#include "econ_wearable.h"
+#include "team_control_point_master.h"
+#include "particle_parse.h"
+#include "CRagdollMagnet.h"
+#include "NextBot/Behavior/BehaviorMoveTo.h"
+
+ConVar tf_bot_npc_archer_health( "tf_bot_npc_archer_health", "100", FCVAR_CHEAT );
+
+ConVar tf_bot_npc_archer_speed( "tf_bot_npc_archer_speed", "100", FCVAR_CHEAT );
+
+ConVar tf_bot_npc_archer_shoot_interval( "tf_bot_npc_archer_shoot_interval", "2", FCVAR_CHEAT ); // 2
+ConVar tf_bot_npc_archer_arrow_damage( "tf_bot_npc_archer_arrow_damage", "75", FCVAR_CHEAT );
+
+
+//-----------------------------------------------------------------
+// The Bot NPC
+//-----------------------------------------------------------------------------------------------------
+LINK_ENTITY_TO_CLASS( bot_npc_archer, CBotNPCArcher );
+
+PRECACHE_REGISTER( bot_npc_archer );
+
+
+//-----------------------------------------------------------------------------------------------------
+CBotNPCArcher::CBotNPCArcher()
+{
+ ALLOCATE_INTENTION_INTERFACE( CBotNPCArcher );
+
+ m_locomotor = new NextBotGroundLocomotion( this );
+ m_body = new CBotNPCBody( this );
+
+ m_eyeOffset = vec3_origin;
+ m_homePos = vec3_origin;
+}
+
+
+//-----------------------------------------------------------------------------------------------------
+CBotNPCArcher::~CBotNPCArcher()
+{
+ DEALLOCATE_INTENTION_INTERFACE;
+
+ if ( m_locomotor )
+ delete m_locomotor;
+
+ if ( m_body )
+ delete m_body;
+}
+
+//-----------------------------------------------------------------------------------------------------
+void CBotNPCArcher::Precache()
+{
+ BaseClass::Precache();
+
+ PrecacheModel( "models/player/sniper.mdl" );
+ PrecacheModel( "models/weapons/c_models/c_bow/c_bow.mdl" );
+}
+
+
+//-----------------------------------------------------------------------------------------------------
+void CBotNPCArcher::Spawn( void )
+{
+ BaseClass::Spawn();
+
+ SetModel( "models/player/sniper.mdl" );
+
+ m_bow = (CBaseAnimating *)CreateEntityByName( "prop_dynamic" );
+ if ( m_bow )
+ {
+ m_bow->SetModel( "models/weapons/c_models/c_bow/c_bow.mdl" );
+
+ // bonemerge into our model
+ m_bow->FollowEntity( this, true );
+ }
+
+ int health = tf_bot_npc_archer_health.GetInt();
+ SetHealth( health );
+ SetMaxHealth( health );
+
+ ChangeTeam( TF_TEAM_RED );
+
+ Vector headPos;
+ QAngle headAngles;
+ if ( GetAttachment( "head", headPos, headAngles ) )
+ {
+ m_eyeOffset = headPos - GetAbsOrigin();
+ }
+
+ m_homePos = GetAbsOrigin();
+}
+
+
+//---------------------------------------------------------------------------------------------
+unsigned int CBotNPCArcher::PhysicsSolidMaskForEntity( void ) const
+{
+ // Only collide with the other team
+ int teamContents = ( GetTeamNumber() == TF_TEAM_RED ) ? CONTENTS_BLUETEAM : CONTENTS_REDTEAM;
+
+ return BaseClass::PhysicsSolidMaskForEntity() | teamContents;
+}
+
+
+//---------------------------------------------------------------------------------------------
+bool CBotNPCArcher::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 );
+}
+
+
+//---------------------------------------------------------------------------------------------
+//---------------------------------------------------------------------------------------------
+class CBotNPCArcherSurrender : public Action< CBotNPCArcher >
+{
+public:
+ virtual ActionResult< CBotNPCArcher > OnStart( CBotNPCArcher *me, Action< CBotNPCArcher > *priorAction );
+ virtual const char *GetName( void ) const { return "Surrender"; } // return name of this action
+};
+
+
+inline ActionResult< CBotNPCArcher > CBotNPCArcherSurrender::OnStart( CBotNPCArcher *me, Action< CBotNPCArcher > *priorAction )
+{
+ CBaseAnimating *bow = me->GetBow();
+ if ( bow )
+ {
+ bow->AddEffects( EF_NODRAW );
+ }
+
+ me->GetBodyInterface()->StartActivity( ACT_MP_STAND_LOSERSTATE );
+
+ return Continue();
+}
+
+
+//---------------------------------------------------------------------------------------------
+//---------------------------------------------------------------------------------------------
+class CBotNPCArcherShootBow : public Action< CBotNPCArcher >
+{
+public:
+ CBotNPCArcherShootBow( CTFPlayer *target )
+ {
+ m_target = target;
+ }
+
+ virtual ActionResult< CBotNPCArcher > OnStart( CBotNPCArcher *me, Action< CBotNPCArcher > *priorAction );
+ virtual ActionResult< CBotNPCArcher > Update( CBotNPCArcher *me, float interval );
+
+ virtual const char *GetName( void ) const { return "ShootBow"; } // return name of this action
+
+private:
+ CHandle< CTFPlayer > m_target;
+};
+
+
+//---------------------------------------------------------------------------------------------
+ActionResult< CBotNPCArcher > CBotNPCArcherShootBow::OnStart( CBotNPCArcher *me, Action< CBotNPCArcher > *priorAction )
+{
+ if ( !m_target )
+ {
+ return Done( "No target" );
+ }
+
+ me->GetLocomotionInterface()->FaceTowards( m_target->WorldSpaceCenter() );
+ me->AddGesture( ACT_MP_ATTACK_STAND_ITEM2 );
+
+ // fire arrow
+ const float arrowSpeed = 2000.0f;
+ const float arrowGravity = 0.2f;
+
+ Vector muzzleOrigin;
+ QAngle muzzleAngles;
+ if ( me->GetBow()->GetAttachment( "muzzle", muzzleOrigin, muzzleAngles ) == false )
+ {
+ return Done( "No muzzle attachment!" );
+ }
+
+ // lead target
+ float range = me->GetRangeTo( m_target->EyePosition() );
+ float flightTime = range / arrowSpeed;
+
+ Vector aimSpot = m_target->EyePosition() + m_target->GetAbsVelocity() * flightTime;
+
+ Vector to = aimSpot - muzzleOrigin;
+ VectorAngles( to, muzzleAngles );
+
+ CTFProjectile_Arrow *arrow = CTFProjectile_Arrow::Create( muzzleOrigin, muzzleAngles, arrowSpeed, arrowGravity, TF_PROJECTILE_ARROW, me, me );
+ if ( arrow )
+ {
+ arrow->SetLauncher( me );
+ arrow->SetCritical( false );
+
+ arrow->SetDamage( tf_bot_npc_archer_arrow_damage.GetFloat() );
+
+ me->EmitSound( "Weapon_CompoundBow.Single" );
+ }
+
+ return Continue();
+}
+
+
+//---------------------------------------------------------------------------------------------
+ActionResult< CBotNPCArcher > CBotNPCArcherShootBow::Update( CBotNPCArcher *me, float interval )
+{
+ if ( me->IsSequenceFinished() )
+ {
+ return Done();
+ }
+
+ return Continue();
+}
+
+
+//---------------------------------------------------------------------------------------------
+//---------------------------------------------------------------------------------------------
+class CBotNPCArcherGuardSpot : public Action< CBotNPCArcher >
+{
+public:
+ virtual ActionResult< CBotNPCArcher > OnStart( CBotNPCArcher *me, Action< CBotNPCArcher > *priorAction )
+ {
+ me->GetBodyInterface()->StartActivity( ACT_MP_STAND_ITEM2 );
+
+ return Continue();
+ }
+
+ CTFPlayer *GetVictim( CBotNPCArcher *me )
+ {
+ CUtlVector< CTFPlayer * > playerVector;
+ CollectPlayers( &playerVector, TF_TEAM_BLUE, COLLECT_ONLY_LIVING_PLAYERS );
+
+ CTFPlayer *closeVictim = NULL;
+ float victimRangeSq = FLT_MAX;
+
+ for( int i=0; i<playerVector.Count(); ++i )
+ {
+ float rangeSq = me->GetRangeSquaredTo( playerVector[i] );
+ if ( rangeSq < victimRangeSq )
+ {
+ if ( playerVector[i]->m_Shared.IsStealthed() )
+ {
+ continue;
+ }
+
+ if ( me->IsLineOfSightClear( playerVector[i] ) )
+ {
+ closeVictim = playerVector[i];
+ victimRangeSq = rangeSq;
+ }
+ }
+ }
+
+ return closeVictim;
+ }
+
+ virtual ActionResult< CBotNPCArcher > Update( CBotNPCArcher *me, float interval )
+ {
+ if ( TFGameRules()->GetActiveBoss() == NULL )
+ {
+ // the Boss has been defeated - give up
+ return ChangeTo( new CBotNPCArcherSurrender, "The Boss is dead! I give up!" );
+ }
+
+ CTFPlayer *victim = GetVictim( me );
+
+ if ( victim )
+ {
+ // look at visible victim out of range
+ me->GetLocomotionInterface()->FaceTowards( victim->WorldSpaceCenter() );
+
+ if ( m_shootTimer.IsElapsed() )
+ {
+ m_shootTimer.Start( tf_bot_npc_archer_shoot_interval.GetFloat() );
+
+ return SuspendFor( new CBotNPCArcherShootBow( victim ), "Fire!" );
+ }
+ }
+
+ if ( me->GetLocomotionInterface()->IsAttemptingToMove() )
+ {
+ // play running animation
+ if ( !me->GetBodyInterface()->IsActivity( ACT_MP_DEPLOYED_IDLE_ITEM2 ) )
+ {
+ me->GetBodyInterface()->StartActivity( ACT_MP_DEPLOYED_IDLE_ITEM2 );
+ }
+ }
+ else
+ {
+ // standing still
+ if ( !me->GetBodyInterface()->IsActivity( ACT_MP_STAND_ITEM2 ) )
+ {
+ me->GetBodyInterface()->StartActivity( ACT_MP_STAND_ITEM2 );
+ }
+ }
+
+ return Continue();
+ }
+
+ virtual const char *GetName( void ) const { return "GuardSpot"; } // return name of this action
+
+private:
+ CountdownTimer m_shootTimer;
+};
+
+
+//---------------------------------------------------------------------------------------------
+//---------------------------------------------------------------------------------------------
+class CBotNPCArcherMoveToMark : public Action< CBotNPCArcher >
+{
+public:
+ virtual ActionResult< CBotNPCArcher > OnStart( CBotNPCArcher *me, Action< CBotNPCArcher > *priorAction )
+ {
+ ShortestPathCost cost;
+ m_path.Compute( me, me->GetHomePosition(), cost );
+
+ me->GetBodyInterface()->StartActivity( ACT_MP_RUN_ITEM2 );
+
+ return Continue();
+ }
+
+ virtual ActionResult< CBotNPCArcher > Update( CBotNPCArcher *me, float interval )
+ {
+ m_path.Update( me );
+
+ if ( !m_path.IsValid() )
+ {
+ return ChangeTo( new CBotNPCArcherGuardSpot, "Reached my mark" );
+ }
+
+ return Continue();
+ }
+
+ virtual const char *GetName( void ) const { return "MoveToMark"; } // return name of this action
+
+private:
+ PathFollower m_path;
+};
+
+
+//---------------------------------------------------------------------------------------------
+//---------------------------------------------------------------------------------------------
+class CBotNPCArcherBehavior : public Action< CBotNPCArcher >
+{
+public:
+ virtual Action< CBotNPCArcher > *InitialContainedAction( CBotNPCArcher *me )
+ {
+ return new CBotNPCArcherMoveToMark;
+ }
+
+ virtual ActionResult< CBotNPCArcher > Update( CBotNPCArcher *me, float interval )
+ {
+ return Continue();
+ }
+
+ virtual EventDesiredResult< CBotNPCArcher > OnKilled( CBotNPCArcher *me, const CTakeDamageInfo &info )
+ {
+ // Calculate death force
+ Vector forceVector = me->CalcDamageForceVector( info );
+
+ // See if there's a ragdoll magnet that should influence our force.
+ CRagdollMagnet *magnet = CRagdollMagnet::FindBestMagnet( me );
+ if ( magnet )
+ {
+ forceVector += magnet->GetForceVector( me );
+ }
+
+ me->BecomeRagdoll( info, forceVector );
+
+ return TryDone();
+ }
+
+ virtual const char *GetName( void ) const { return "Behavior"; } // return name of this action
+};
+
+
+IMPLEMENT_INTENTION_INTERFACE( CBotNPCArcher, CBotNPCArcherBehavior );