diff options
Diffstat (limited to 'mp/src/game/server/hl2/npc_dog.cpp')
| -rw-r--r-- | mp/src/game/server/hl2/npc_dog.cpp | 3568 |
1 files changed, 1784 insertions, 1784 deletions
diff --git a/mp/src/game/server/hl2/npc_dog.cpp b/mp/src/game/server/hl2/npc_dog.cpp index bb8d8e60..6e05cf4d 100644 --- a/mp/src/game/server/hl2/npc_dog.cpp +++ b/mp/src/game/server/hl2/npc_dog.cpp @@ -1,1784 +1,1784 @@ -//========= Copyright Valve Corporation, All rights reserved. ============//
-//
-// Purpose: Implements d0g, the loving and caring head crushing Alyx companion.
-//
-//=============================================================================//
-
-#include "cbase.h"
-#include "npcevent.h"
-#include "ai_basenpc.h"
-#include "ai_network.h"
-#include "ai_navigator.h"
-#include "ai_motor.h"
-#include "ai_hull.h"
-#include "beam_shared.h"
-#include "ai_baseactor.h"
-#include "npc_rollermine.h"
-#include "saverestore_utlvector.h"
-#include "physics_bone_follower.h"
-#include "Sprite.h"
-#include "ai_behavior_follow.h"
-#include "collisionutils.h"
-
-// memdbgon must be the last include file in a .cpp file!!!
-#include "tier0/memdbgon.h"
-
-#define EFFECT_COUNT 4
-
-extern ConVar ai_debug_avoidancebounds;
-
-class CNPC_Dog : public CAI_BaseActor
-{
-public:
- DECLARE_DATADESC();
- DECLARE_CLASS( CNPC_Dog, CAI_BaseActor );
- Class_T Classify ( void );
- void Spawn( void );
- void Precache( void );
- void StartTask( const Task_t *pTask );
- void HandleAnimEvent( animevent_t *pEvent );
- int SelectSchedule( void );
-
- bool FindPhysicsObject( const char *pPickupName, CBaseEntity *pIgnore = NULL );
- void RunTask( const Task_t *pTask );
- void CreateBeams( void );
- void ClearBeams( void );
-
- void PrescheduleThink( void );
-
- bool CanTargetSeeMe( void );
-
- Vector FacingPosition( void ) { return WorldSpaceCenter(); }
- float GetHeadDebounce( void ) { return 0.8; } // how much of previous head turn to use
-
- void InputSetPickupTarget( inputdata_t &inputdata );
- void InputStartCatchThrowBehavior( inputdata_t &inputdata );
- void InputStopCatchThrowBehavior( inputdata_t &inputdata );
- void InputPlayerPickupObject( inputdata_t &inputdata );
-
- void InputStartWaitAndCatch( inputdata_t &inputdata );
- void InputStopWaitAndCatch( inputdata_t &inputdata );
- void InputSetThrowArcModifier( inputdata_t &inputdata );
- void InputSetThrowTarget( inputdata_t &inputdata );
-
- void InputTurnBoneFollowersOff( inputdata_t &inputdata );
- void InputTurnBoneFollowersOn( inputdata_t &inputdata );
-
- void CleanCatchAndThrow( bool bClearTimers = true );
- void SetTurnActivity ( void );
- void ThrowObject( const char *pAttachmentName );
- void PickupOrCatchObject( const char *pAttachmentName );
- void PullObject( bool bMantain );
- void SetupThrowTarget( void );
-
- void GatherConditions( void );
-
- Disposition_t IRelationType( CBaseEntity *pTarget );
-
- int OnTakeDamage_Alive( const CTakeDamageInfo &info );
-
- void MantainBoneFollowerCollisionGroups( int CollisionGroup );
- virtual void SetPlayerAvoidState( void );
-
-protected:
- enum
- {
- COND_DOG_LOST_PHYSICS_ENTITY = BaseClass::NEXT_CONDITION,
-
- NEXT_CONDITION,
- };
-
-protected:
- float m_flNextSwat;
- float m_flTimeToCatch;
- float m_flTimeToPull;
- EHANDLE m_hPhysicsEnt;
- EHANDLE m_hThrowTarget;
-
- int m_iPhysGunAttachment;
- bool m_bDoCatchThrowBehavior;
- bool m_bDoWaitforObjectBehavior;
- string_t m_sObjectName;
-
- COutputEvent m_OnThrow;
- COutputEvent m_OnCatch;
- COutputEvent m_OnPickup;
-
- float m_flThrowArcModifier;
- int m_iContainerMoveType;
- float m_flNextRouteTime;
-
- bool m_bHasObject;
- bool m_bBeamEffects;
-
- CUtlVector< CHandle <CBaseEntity> > m_hUnreachableObjects;
-
- // Contained Bone Follower manager
- CBoneFollowerManager m_BoneFollowerManager;
-
- bool CreateVPhysics( void );
- void UpdateOnRemove( void );
- void NPCThink( void );
- void Event_Killed( const CTakeDamageInfo &info );
-
- void CreateSprites( void );
- void ClearSprites( void );
- CHandle<CSprite> m_hGlowSprites[EFFECT_COUNT];
- CHandle<CBeam> m_hBeams[EFFECT_COUNT]; //This is temp.
-
- virtual bool CreateBehaviors( void );
- CAI_FollowBehavior m_FollowBehavior;
-
- bool m_bBoneFollowersActive;
-
-
-protected:
-
- DEFINE_CUSTOM_AI;
-};
-
-LINK_ENTITY_TO_CLASS( npc_dog, CNPC_Dog );
-
-BEGIN_DATADESC( CNPC_Dog )
- DEFINE_EMBEDDED( m_BoneFollowerManager ),
-// m_FollowBehavior
- DEFINE_FIELD( m_flNextSwat, FIELD_TIME ),
- DEFINE_FIELD( m_flTimeToCatch, FIELD_TIME ),
- DEFINE_FIELD( m_flTimeToPull, FIELD_TIME ),
- DEFINE_FIELD( m_hPhysicsEnt, FIELD_EHANDLE ),
- DEFINE_FIELD( m_hThrowTarget, FIELD_EHANDLE ),
- DEFINE_FIELD( m_iPhysGunAttachment, FIELD_INTEGER ),
- DEFINE_FIELD( m_bDoCatchThrowBehavior, FIELD_BOOLEAN ),
- DEFINE_FIELD( m_bDoWaitforObjectBehavior, FIELD_BOOLEAN ),
- DEFINE_FIELD( m_sObjectName, FIELD_STRING ),
- DEFINE_FIELD( m_flThrowArcModifier, FIELD_FLOAT ),
- DEFINE_FIELD( m_flNextRouteTime, FIELD_TIME ),
- DEFINE_FIELD( m_bHasObject, FIELD_BOOLEAN ),
- DEFINE_FIELD( m_iContainerMoveType, FIELD_INTEGER ),
- DEFINE_FIELD( m_bBeamEffects, FIELD_BOOLEAN ),
- DEFINE_FIELD( m_bBoneFollowersActive, FIELD_BOOLEAN ),
- DEFINE_UTLVECTOR( m_hUnreachableObjects, FIELD_EHANDLE ),
- DEFINE_AUTO_ARRAY( m_hGlowSprites, FIELD_EHANDLE ),
- DEFINE_AUTO_ARRAY( m_hBeams, FIELD_EHANDLE ),
- DEFINE_INPUTFUNC( FIELD_STRING, "SetPickupTarget", InputSetPickupTarget ),
- DEFINE_INPUTFUNC( FIELD_STRING, "StartCatchThrowBehavior", InputStartCatchThrowBehavior ),
- DEFINE_INPUTFUNC( FIELD_STRING, "StopCatchThrowBehavior", InputStopCatchThrowBehavior ),
- DEFINE_INPUTFUNC( FIELD_VOID, "PlayerPickupObject", InputPlayerPickupObject ),
- DEFINE_INPUTFUNC( FIELD_VOID, "StartWaitAndCatch", InputStartWaitAndCatch ),
- DEFINE_INPUTFUNC( FIELD_VOID, "StopWaitAndCatch", InputStopWaitAndCatch ),
- DEFINE_INPUTFUNC( FIELD_FLOAT, "SetThrowArcModifier", InputSetThrowArcModifier ),
- DEFINE_INPUTFUNC( FIELD_STRING, "SetThrowTarget", InputSetThrowTarget ),
- DEFINE_INPUTFUNC( FIELD_VOID, "TurnBoneFollowersOff", InputTurnBoneFollowersOff ),
- DEFINE_INPUTFUNC( FIELD_VOID, "TurnBoneFollowersOn", InputTurnBoneFollowersOn ),
- DEFINE_OUTPUT( m_OnThrow, "OnDogThrow"),
- DEFINE_OUTPUT( m_OnCatch, "OnDogCatch"),
- DEFINE_OUTPUT( m_OnPickup, "OnDogPickup"),
-
-END_DATADESC()
-
-#define DOG_PHYSOBJ_MOVE_TO_DIST 96
-#define DOG_PULL_DISTANCE 200
-#define DOG_CATCH_DISTANCE 48
-#define DOG_PULL_VELOCITY_MOD 0.1f
-#define DOG_PULL_ANGULARIMP_MOD 0.8f
-#define DOG_PULL_TO_GUN_VEL_MOD 2.0f
-#define DOG_MAX_THROW_MASS 250.0f
-#define DOG_PHYSGUN_ATTACHMENT_NAME "physgun"
-
-// These bones have physics shadows
-static const char *pFollowerBoneNames[] =
-{
- // head
- "Dog_Model.Eye",
- "Dog_Model.Pelvis",
-};
-
-enum
-{
- SCHED_DOG_FIND_OBJECT = LAST_SHARED_SCHEDULE,
- SCHED_DOG_CATCH_OBJECT,
- SCHED_DOG_WAIT_THROW_OBJECT,
-};
-
-//=========================================================
-// tasks
-//=========================================================
-enum
-{
- TASK_DOG_DELAY_SWAT = LAST_SHARED_TASK,
- TASK_DOG_GET_PATH_TO_PHYSOBJ,
- TASK_DOG_PICKUP_ITEM,
- TASK_DOG_LAUNCH_ITEM,
- TASK_DOG_FACE_OBJECT,
- TASK_DOG_WAIT_FOR_OBJECT,
- TASK_DOG_CATCH_OBJECT,
- TASK_DOG_WAIT_FOR_TARGET_TO_FACE,
- TASK_DOG_SETUP_THROW_TARGET,
-};
-
-int ACT_DOG_THROW;
-int ACT_DOG_PICKUP;
-int ACT_DOG_WAITING;
-int ACT_DOG_CATCH;
-
-int AE_DOG_THROW;
-int AE_DOG_PICKUP;
-int AE_DOG_CATCH;
-int AE_DOG_PICKUP_NOEFFECT;
-
-ConVar dog_max_wait_time( "dog_max_wait_time", "7" );
-ConVar dog_debug( "dog_debug", "0" );
-
-//-----------------------------------------------------------------------------
-// Classify - indicates this NPC's place in the
-// relationship table.
-//-----------------------------------------------------------------------------
-Class_T CNPC_Dog::Classify ( void )
-{
- return CLASS_PLAYER_ALLY_VITAL;
-}
-
-bool CNPC_Dog::CreateBehaviors( void )
-{
- AddBehavior( &m_FollowBehavior );
-
- return BaseClass::CreateBehaviors();
-}
-
-Disposition_t CNPC_Dog::IRelationType( CBaseEntity *pTarget )
-{
- if ( NPC_Rollermine_IsRollermine( pTarget ) )
- {
- if ( pTarget->HasSpawnFlags( SF_ROLLERMINE_FRIENDLY ) )
- return D_LI;
- }
-
- return BaseClass::IRelationType( pTarget );
-}
-
-//---------------------------------------------------------
-//---------------------------------------------------------
-bool CNPC_Dog::CreateVPhysics( void )
-{
- BaseClass::CreateVPhysics();
-
- if ( m_bBoneFollowersActive == true && !m_BoneFollowerManager.GetNumBoneFollowers() )
- {
- m_BoneFollowerManager.InitBoneFollowers( this, ARRAYSIZE(pFollowerBoneNames), pFollowerBoneNames );
- }
- return true;
-}
-
-//---------------------------------------------------------
-//---------------------------------------------------------
-void CNPC_Dog::UpdateOnRemove( void )
-{
- m_BoneFollowerManager.DestroyBoneFollowers();
- BaseClass::UpdateOnRemove();
-}
-
-void CNPC_Dog::GatherConditions( void )
-{
- if ( IsInAScript() )
- {
- ClearSenseConditions();
- return;
- }
-
- BaseClass::GatherConditions();
-}
-
-int CNPC_Dog::OnTakeDamage_Alive( const CTakeDamageInfo &info )
-{
- if ( IsInAScript() )
- return 0;
-
- return BaseClass::OnTakeDamage_Alive( info );
-}
-
-//-----------------------------------------------------------------------------
-// This function checks if Dog's collision group doesn't match his bone follower's and fixes them up.
-//-----------------------------------------------------------------------------
-void CNPC_Dog::MantainBoneFollowerCollisionGroups( int iCollisionGroup )
-{
- if ( m_bBoneFollowersActive == false )
- return;
-
- physfollower_t* pBone = m_BoneFollowerManager.GetBoneFollower( 0 );
-
- if ( pBone && pBone->hFollower && pBone->hFollower->GetCollisionGroup() != iCollisionGroup )
- {
- for ( int i = 0; i < m_BoneFollowerManager.GetNumBoneFollowers(); i++ )
- {
- pBone = m_BoneFollowerManager.GetBoneFollower( i );
-
- if ( pBone && pBone->hFollower )
- {
- pBone->hFollower->SetCollisionGroup( iCollisionGroup );
- }
- }
- }
-}
-
-void CNPC_Dog::SetPlayerAvoidState( void )
-{
- bool bIntersectingBoneFollowers = false;
- bool bIntersectingNPCBox = false;
-
- Vector vNothing;
-
- GetSequenceLinearMotion( GetSequence(), &vNothing );
- bool bIsMoving = ( IsMoving() || ( vNothing != vec3_origin ) );
-
- //If we are coming out of a script, check if we are stuck inside the player.
- if ( m_bPerformAvoidance || ( ShouldPlayerAvoid() && bIsMoving ) )
- {
- trace_t trace;
- Vector vMins, vMaxs;
- Vector vWorldMins, vWorldMaxs;
- Vector vPlayerMins, vPlayerMaxs;
- physfollower_t *pBone;
- int i;
-
- CBasePlayer *pLocalPlayer = AI_GetSinglePlayer();
-
- if ( pLocalPlayer )
- {
- vWorldMins = WorldAlignMins();
- vWorldMaxs = WorldAlignMaxs();
-
- vPlayerMins = pLocalPlayer->GetAbsOrigin() + pLocalPlayer->WorldAlignMins();
- vPlayerMaxs = pLocalPlayer->GetAbsOrigin() + pLocalPlayer->WorldAlignMaxs();
-
- // check if the player intersects the bounds of any of the bone followers
- for ( i = 0; i < m_BoneFollowerManager.GetNumBoneFollowers(); i++ )
- {
- pBone = m_BoneFollowerManager.GetBoneFollower( i );
- if ( pBone && pBone->hFollower )
- {
- pBone->hFollower->CollisionProp()->WorldSpaceSurroundingBounds( &vMins, &vMaxs );
- if ( IsBoxIntersectingBox( vMins, vMaxs, vPlayerMins, vPlayerMaxs ) )
- {
- bIntersectingBoneFollowers = true;
- break;
- }
- }
- }
-
- bIntersectingNPCBox = IsBoxIntersectingBox( GetAbsOrigin() + vWorldMins, GetAbsOrigin() + vWorldMaxs, vPlayerMins, vPlayerMaxs );
-
- if ( ai_debug_avoidancebounds.GetBool() )
- {
- int iRed = ( bIntersectingNPCBox == true ) ? 255 : 0;
-
- NDebugOverlay::Box( GetAbsOrigin(), vWorldMins, vWorldMaxs, iRed, 0, 255, 64, 0.1 );
-
- // draw the bounds of the bone followers
- for ( i = 0; i < m_BoneFollowerManager.GetNumBoneFollowers(); i++ )
- {
- pBone = m_BoneFollowerManager.GetBoneFollower( i );
- if ( pBone && pBone->hFollower )
- {
- pBone->hFollower->CollisionProp()->WorldSpaceSurroundingBounds( &vMins, &vMaxs );
- iRed = ( IsBoxIntersectingBox( vMins, vMaxs, vPlayerMins, vPlayerMaxs ) ) ? 255 : 0;
-
- NDebugOverlay::Box( vec3_origin, vMins, vMaxs, iRed, 0, 255, 64, 0.1 );
- }
- }
- }
- }
- }
-
- m_bPlayerAvoidState = ShouldPlayerAvoid();
- m_bPerformAvoidance = bIntersectingNPCBox || bIntersectingBoneFollowers;
-
- if ( GetCollisionGroup() == COLLISION_GROUP_NPC || GetCollisionGroup() == COLLISION_GROUP_NPC_ACTOR )
- {
- if ( bIntersectingNPCBox == true )
- {
- SetCollisionGroup( COLLISION_GROUP_NPC_ACTOR );
- }
- else
- {
- SetCollisionGroup( COLLISION_GROUP_NPC );
- }
-
- if ( bIntersectingBoneFollowers == true )
- {
- MantainBoneFollowerCollisionGroups( COLLISION_GROUP_NPC_ACTOR );
- }
- else
- {
- MantainBoneFollowerCollisionGroups( COLLISION_GROUP_NPC );
- }
- }
-}
-//---------------------------------------------------------
-//---------------------------------------------------------
-void CNPC_Dog::NPCThink( void )
-{
- BaseClass::NPCThink();
-
- if ( m_hPhysicsEnt == NULL )
- {
- ClearBeams();
- m_bHasObject = false;
- }
-
- if ( m_bHasObject == true )
- {
- RelaxAim();
- PullObject( true );
- }
-
-
- // update follower bones
- m_BoneFollowerManager.UpdateBoneFollowers(this);
-}
-
-//---------------------------------------------------------
-//---------------------------------------------------------
-void CNPC_Dog::Event_Killed( const CTakeDamageInfo &info )
-{
- m_BoneFollowerManager.DestroyBoneFollowers();
- BaseClass::Event_Killed( info );
-}
-
-//-----------------------------------------------------------------------------
-// Spawn
-//-----------------------------------------------------------------------------
-void CNPC_Dog::Spawn( void )
-{
- m_bBoneFollowersActive = true;
-
- Precache();
-
- BaseClass::Spawn();
-
- SetModel( "models/dog.mdl" );
-
- SetHullType( HULL_WIDE_HUMAN );
- SetHullSizeNormal();
-
- SetSolid( SOLID_BBOX );
- AddSolidFlags( FSOLID_NOT_STANDABLE );
- SetMoveType( MOVETYPE_STEP );
- SetBloodColor( BLOOD_COLOR_MECH );
-
- m_iHealth = 999;
- m_flFieldOfView = 0.5;// indicates the width of this NPC's forward view cone ( as a dotproduct result )
- m_NPCState = NPC_STATE_NONE;
-
- m_takedamage = DAMAGE_NO;
-
- CapabilitiesAdd( bits_CAP_MOVE_GROUND | bits_CAP_OPEN_DOORS | bits_CAP_TURN_HEAD | bits_CAP_ANIMATEDFACE );
- CapabilitiesAdd( bits_CAP_FRIENDLY_DMG_IMMUNE );
-
- NPCInit();
-
- m_iPhysGunAttachment = LookupAttachment( DOG_PHYSGUN_ATTACHMENT_NAME );
-
- m_bDoCatchThrowBehavior = false;
- m_bDoWaitforObjectBehavior = false;
- m_bHasObject = false;
- m_bBeamEffects = true;
-
- m_flThrowArcModifier = 1.0f;
-
- m_flNextSwat = gpGlobals->curtime;
- m_flNextRouteTime = gpGlobals->curtime;
-}
-
-
-void CNPC_Dog::PrescheduleThink( void )
-{
- BaseClass::PrescheduleThink();
-
- if ( m_hPhysicsEnt )
- {
- IPhysicsObject *pPhysObj = m_hPhysicsEnt->VPhysicsGetObject();
-
- if ( pPhysObj && pPhysObj->GetGameFlags() & FVPHYSICS_PLAYER_HELD )
- {
- m_hPhysicsEnt->SetOwnerEntity( NULL );
- }
- }
-
- if ( m_flTimeToCatch < gpGlobals->curtime )
- m_flTimeToCatch = 0.0f;
-
-
- if ( GetIdealActivity() == ACT_IDLE )
- {
- if ( m_hPhysicsEnt && m_bHasObject == true )
- {
- SetIdealActivity( (Activity)ACT_DOG_WAITING );
- }
- }
-}
-
-int CNPC_Dog::SelectSchedule ( void )
-{
- ClearCondition( COND_DOG_LOST_PHYSICS_ENTITY );
-
- if ( GetState() == NPC_STATE_SCRIPT || IsInAScript() )
- return BaseClass::SelectSchedule();
-
- if ( BehaviorSelectSchedule() )
- return BaseClass::SelectSchedule();
-
- if ( m_bDoWaitforObjectBehavior == true )
- {
- if ( m_hPhysicsEnt )
- return SCHED_DOG_CATCH_OBJECT;
- }
-
- if ( m_bDoCatchThrowBehavior == true )
- {
- if ( m_flTimeToCatch < 0.1 && m_flNextSwat <= gpGlobals->curtime )
- {
- return SCHED_DOG_FIND_OBJECT;
- }
-
- if ( m_flTimeToCatch > gpGlobals->curtime && m_hPhysicsEnt )
- return SCHED_DOG_CATCH_OBJECT;
- }
- else
- {
- if ( m_hPhysicsEnt )
- {
- if ( m_bHasObject == true )
- {
- return SCHED_DOG_WAIT_THROW_OBJECT;
- }
- }
- }
-
- return BaseClass::SelectSchedule();
-}
-
-void CNPC_Dog::PullObject( bool bMantain )
-{
- if ( m_hPhysicsEnt == NULL )
- {
- TaskFail( "Ack! No Phys Object!");
- return;
- }
-
- IPhysicsObject *pPhysObj = m_hPhysicsEnt->VPhysicsGetObject();
-
- if ( pPhysObj == NULL )
- {
- TaskFail( "Pulling object with no Phys Object?!" );
- return;
- }
-
- if( pPhysObj->GetGameFlags() & FVPHYSICS_PLAYER_HELD )
- {
- m_bHasObject = false;
- ClearBeams();
- TaskFail("Player Grabbed Ball");
- return;
- }
-
- CreateBeams();
-
- Vector vGunPos;
- GetAttachment( m_iPhysGunAttachment, vGunPos );
- float flDistance = ( vGunPos - m_hPhysicsEnt->WorldSpaceCenter() ).Length();
-
- if ( bMantain == false )
- {
- if ( flDistance <= DOG_CATCH_DISTANCE )
- {
- m_hPhysicsEnt->SetOwnerEntity( this );
-
- GetNavigator()->StopMoving();
-
- //Fire Output!
- m_OnPickup.FireOutput( this, this );
-
- m_bHasObject = true;
- ClearBeams();
- TaskComplete();
- return;
- }
- }
-
- Vector vDir = ( vGunPos - m_hPhysicsEnt->WorldSpaceCenter() );
-
- Vector vCurrentVel;
- float flCurrentVel;
- AngularImpulse vCurrentAI;
-
- pPhysObj->GetVelocity( &vCurrentVel, &vCurrentAI );
- flCurrentVel = vCurrentVel.Length();
-
- VectorNormalize( vCurrentVel );
- VectorNormalize( vDir );
-
- float flVelMod = DOG_PULL_VELOCITY_MOD;
-
- if ( bMantain == true )
- flVelMod *= 2;
-
- vCurrentVel = vCurrentVel * flCurrentVel * flVelMod;
-
- vCurrentAI = vCurrentAI * DOG_PULL_ANGULARIMP_MOD;
- pPhysObj->SetVelocity( &vCurrentVel, &vCurrentAI );
-
- vDir = vDir * flDistance * (DOG_PULL_TO_GUN_VEL_MOD * 2);
-
- Vector vAngle( 0, 0, 0 );
- pPhysObj->AddVelocity( &vDir, &vAngle );
-}
-
-//-----------------------------------------------------------------------------
-// Precache - precaches all resources this NPC needs
-//-----------------------------------------------------------------------------
-void CNPC_Dog::Precache( void )
-{
- PrecacheModel( "models/dog.mdl" );
-
- PrecacheScriptSound( "Weapon_PhysCannon.Launch" );
-
- PrecacheModel( "sprites/orangelight1.vmt" );
- PrecacheModel( "sprites/physcannon_bluelight2.vmt" );
- PrecacheModel( "sprites/glow04_noz.vmt" );
-
- BaseClass::Precache();
-}
-
-void CNPC_Dog::CleanCatchAndThrow( bool bClearTimers )
-{
- if ( m_hPhysicsEnt )
- {
- if ( m_bHasObject == true )
- {
- IPhysicsObject *pPhysObj = m_hPhysicsEnt->VPhysicsGetObject();
-
- m_hPhysicsEnt->SetParent( NULL );
- m_hPhysicsEnt->SetOwnerEntity( NULL );
-
- Vector vGunPos;
- QAngle angGunAngles;
- GetAttachment( m_iPhysGunAttachment, vGunPos, angGunAngles );
-
- if ( pPhysObj )
- {
- pPhysObj->Wake();
- pPhysObj->RemoveShadowController();
- pPhysObj->SetPosition( vGunPos, angGunAngles, true );
- }
- else
- {
- Warning( "CleanCatchAndThrow: m_hPhysicsEnt->VPhysicsGetObject == NULL!\n" );
- }
-
- m_hPhysicsEnt->SetMoveType( (MoveType_t)m_iContainerMoveType );
-
- if ( pPhysObj )
- {
- pPhysObj->RecheckCollisionFilter();
- }
-
- ClearBeams();
- }
-
- m_hPhysicsEnt = NULL;
- }
-
- if ( bClearTimers == true )
- {
- m_bDoCatchThrowBehavior = false;
- m_bDoWaitforObjectBehavior = false;
- m_flTimeToCatch = 0.0f;
- m_flNextSwat = 0.0f;
-
- SetCondition( COND_DOG_LOST_PHYSICS_ENTITY );
- }
-}
-
-void CNPC_Dog::InputPlayerPickupObject ( inputdata_t &inputdata )
-{
- if ( m_bDoWaitforObjectBehavior == true )
- {
- if ( m_hPhysicsEnt != inputdata.pCaller )
- {
- if ( m_hPhysicsEnt != NULL )
- CleanCatchAndThrow( false );
-
- //Reset this cause CleanCatchAndThrow clears it.
- m_bDoWaitforObjectBehavior = true;
- m_hPhysicsEnt = inputdata.pCaller;
- }
- }
- else if ( m_bDoCatchThrowBehavior == true )
- {
- if ( m_sObjectName != NULL_STRING )
- {
- if ( m_hPhysicsEnt != inputdata.pCaller )
- {
- if ( m_hPhysicsEnt != NULL )
- CleanCatchAndThrow( false );
-
- //Reset this cause CleanCatchAndThrow clears it.
- m_bDoCatchThrowBehavior = true;
- m_hPhysicsEnt = inputdata.pCaller;
- }
- }
- }
-}
-
-void CNPC_Dog::InputSetThrowArcModifier( inputdata_t &inputdata )
-{
- m_flThrowArcModifier = inputdata.value.Float();
-}
-
-void CNPC_Dog::InputSetPickupTarget( inputdata_t &inputdata )
-{
- CleanCatchAndThrow( false );
- FindPhysicsObject( inputdata.value.String() );
-}
-
-void CNPC_Dog::InputStartWaitAndCatch( inputdata_t &inputdata )
-{
- CleanCatchAndThrow();
- m_bDoWaitforObjectBehavior = true;
-}
-
-void CNPC_Dog::InputStopWaitAndCatch( inputdata_t &inputdata )
-{
- CleanCatchAndThrow();
-}
-
-void CNPC_Dog::InputStartCatchThrowBehavior( inputdata_t &inputdata )
-{
- CleanCatchAndThrow();
-
- m_sObjectName = MAKE_STRING( inputdata.value.String() );
- m_bDoCatchThrowBehavior = true;
-
- m_flTimeToCatch = 0.0f;
- m_flNextSwat = 0.0f;
-
- FindPhysicsObject( inputdata.value.String() );
-}
-
-void CNPC_Dog::InputStopCatchThrowBehavior( inputdata_t &inputdata )
-{
- m_bDoCatchThrowBehavior = false;
-
- m_flTimeToCatch = 0.0f;
- m_flNextSwat = 0.0f;
- m_sObjectName = NULL_STRING;
-
- CleanCatchAndThrow();
-}
-
-void CNPC_Dog::InputSetThrowTarget( inputdata_t &inputdata )
-{
- m_hThrowTarget = gEntList.FindEntityByName( NULL, inputdata.value.String(), NULL, inputdata.pActivator, inputdata.pCaller );
-}
-
-void CNPC_Dog::SetTurnActivity( void )
-{
- BaseClass::SetTurnActivity();
-
- if ( GetIdealActivity() == ACT_IDLE )
- {
- if ( m_hPhysicsEnt && m_bHasObject == true )
- SetIdealActivity( (Activity)ACT_DOG_WAITING );
- }
-}
-
-void CNPC_Dog::ThrowObject( const char *pAttachmentName )
-{
- if ( m_hPhysicsEnt )
- {
- m_bHasObject = false;
-
- IPhysicsObject *pPhysObj = m_hPhysicsEnt->VPhysicsGetObject();
-
- if ( pPhysObj )
- {
- Vector vGunPos;
- QAngle angGunAngles;
-
- AngularImpulse angVelocity = RandomAngularImpulse( -250 , -250 ) / pPhysObj->GetMass();
-
- InvalidateBoneCache();
-
- int iAttachment = LookupAttachment( pAttachmentName );
-
- if ( iAttachment == 0 )
- iAttachment = m_iPhysGunAttachment;
-
- GetAttachment( iAttachment, vGunPos, angGunAngles );
-
- pPhysObj->Wake();
-
- if ( pPhysObj->GetShadowController() )
- {
- m_hPhysicsEnt->SetParent( NULL );
- m_hPhysicsEnt->SetMoveType( (MoveType_t)m_iContainerMoveType );
- m_hPhysicsEnt->SetOwnerEntity( this );
-
- pPhysObj->RemoveShadowController();
- pPhysObj->SetPosition( m_hPhysicsEnt->GetLocalOrigin(), m_hPhysicsEnt->GetLocalAngles(), true );
-
- pPhysObj->RecheckCollisionFilter();
- pPhysObj->RecheckContactPoints();
- }
-
- if ( m_hThrowTarget == NULL )
- m_hThrowTarget = AI_GetSinglePlayer();
-
- Vector vThrowDirection;
-
- if ( m_hThrowTarget )
- {
- Vector vThrowOrigin = m_hThrowTarget->GetAbsOrigin();
-
- if ( m_hThrowTarget->IsPlayer() )
- vThrowOrigin = vThrowOrigin + Vector( random->RandomFloat( -128, 128 ), random->RandomFloat( -128, 128 ), 0 );
-
- Vector vecToss = VecCheckToss( this, vGunPos, vThrowOrigin, m_flThrowArcModifier, 1.0f, true );
-
- if( vecToss == vec3_origin )
- {
- // Fix up an impossible throw so dog will at least toss the box in the target's general direction instead of dropping it.
- // Also toss it up in the air so it will fall down and break. (Just throw the box up at a 45 degree angle)
- Vector forward, up;
- GetVectors( &forward, NULL, &up );
-
- vecToss = forward + up;
- VectorNormalize( vecToss );
-
- vecToss *= pPhysObj->GetMass() * 30.0f;
- }
-
- vThrowDirection = vecToss + ( m_hThrowTarget->GetSmoothedVelocity() / 2 );
-
- Vector vLinearDrag;
-
- Vector unitVel = vThrowDirection;
- VectorNormalize( unitVel );
-
- float flTest = 1000 / vThrowDirection.Length();
-
- float flDrag = pPhysObj->CalculateLinearDrag( vThrowDirection );
- vThrowDirection = vThrowDirection + ( unitVel * ( flDrag * flDrag ) ) / flTest;
-
- pPhysObj->SetVelocity( &vThrowDirection, &angVelocity );
-
- m_flTimeToCatch = gpGlobals->curtime + dog_max_wait_time.GetFloat();
-
- //Don't start pulling until the object is away from me.
- //We base the time on the throw velocity.
- m_flTimeToPull = gpGlobals->curtime + ( 1000 / vThrowDirection.Length() );
- }
-
- //Fire Output!
- m_OnThrow.FireOutput( this, this );
-
- ClearBeams();
-
- if ( m_bBeamEffects == true )
- {
- EmitSound( "Weapon_PhysCannon.Launch" );
-
- CBeam *pBeam = CBeam::BeamCreate( "sprites/orangelight1.vmt", 1.8 );
-
- if ( pBeam != NULL )
- {
- pBeam->PointEntInit( m_hPhysicsEnt->WorldSpaceCenter(), this );
- pBeam->SetEndAttachment( m_iPhysGunAttachment );
- pBeam->SetWidth( 6.4 );
- pBeam->SetEndWidth( 12.8 );
- pBeam->SetBrightness( 255 );
- pBeam->SetColor( 255, 255, 255 );
- pBeam->LiveForTime( 0.2f );
- pBeam->RelinkBeam();
- pBeam->SetNoise( 2 );
- }
-
- Vector shotDir = ( m_hPhysicsEnt->WorldSpaceCenter() - vGunPos );
- VectorNormalize( shotDir );
-
- CPVSFilter filter( m_hPhysicsEnt->WorldSpaceCenter() );
- te->GaussExplosion( filter, 0.0f, m_hPhysicsEnt->WorldSpaceCenter() - ( shotDir * 4.0f ), RandomVector(-1.0f, 1.0f), 0 );
- }
- }
- }
-}
-
-void CNPC_Dog::PickupOrCatchObject( const char *pAttachmentName )
-{
- if ( m_hPhysicsEnt )
- {
- InvalidateBoneCache();
-
- int iAttachment = LookupAttachment( pAttachmentName );
-
- if ( iAttachment == 0 )
- iAttachment = m_iPhysGunAttachment;
-
- // Move physobject to shadow
- IPhysicsObject *pPhysicsObject = m_hPhysicsEnt->VPhysicsGetObject();
- if ( pPhysicsObject )
- {
- pPhysicsObject->SetShadow( 1e4, 1e4, false, false );
- pPhysicsObject->UpdateShadow( GetAbsOrigin(), GetAbsAngles(), false, 0 );
- }
-
- m_iContainerMoveType = m_hPhysicsEnt->GetMoveType();
- m_hPhysicsEnt->SetMoveType( MOVETYPE_NONE );
-
- m_hPhysicsEnt->SetParent( this, iAttachment );
-
- m_hPhysicsEnt->SetLocalOrigin( vec3_origin );
- m_hPhysicsEnt->SetLocalAngles( vec3_angle );
-
- m_hPhysicsEnt->SetGroundEntity( NULL );
-
-
- if ( m_hPhysicsEnt->GetOwnerEntity() == NULL )
- m_hPhysicsEnt->SetOwnerEntity( this );
-
- if ( pPhysicsObject )
- pPhysicsObject->RecheckCollisionFilter();
-
- m_bHasObject = true;
-
- //Fire Output!
- m_OnPickup.FireOutput( this, this );
- }
-}
-
-//-----------------------------------------------------------------------------
-// HandleAnimEvent - catches the NPC-specific messages
-// that occur when tagged animation frames are played.
-//-----------------------------------------------------------------------------
-void CNPC_Dog::HandleAnimEvent( animevent_t *pEvent )
-{
- if ( pEvent->event == AE_DOG_THROW )
- {
- ThrowObject( pEvent->options );
- return;
- }
-
- if ( pEvent->event == AE_DOG_PICKUP || pEvent->event == AE_DOG_CATCH || pEvent->event == AE_DOG_PICKUP_NOEFFECT )
- {
- if ( pEvent->event == AE_DOG_PICKUP_NOEFFECT )
- m_bBeamEffects = false;
- else
- m_bBeamEffects = true;
-
- PickupOrCatchObject( pEvent->options );
- return;
- }
-
- BaseClass::HandleAnimEvent( pEvent );
-}
-
-void CNPC_Dog::ClearBeams( void )
-{
- ClearSprites();
-
- // Turn off sprites
- for ( int i = 0; i < EFFECT_COUNT; i++ )
- {
- if ( m_hBeams[i] != NULL )
- {
- UTIL_Remove( m_hBeams[i] );
- m_hBeams[i] = NULL;
- }
- }
-}
-
-void CNPC_Dog::ClearSprites( void )
-{
- // Turn off sprites
- for ( int i = 0; i < EFFECT_COUNT; i++ )
- {
- if ( m_hGlowSprites[i] != NULL )
- {
- UTIL_Remove( m_hGlowSprites[i] );
- m_hGlowSprites[i] = NULL;
- }
- }
-}
-
-void CNPC_Dog::CreateSprites( void )
-{
- //Create the glow sprites
- for ( int i = 0; i < EFFECT_COUNT; i++ )
- {
- if ( m_hGlowSprites[i] )
- continue;
-
- const char *attachNames[] =
- {
- "physgun",
- "thumb",
- "pinky",
- "index",
- };
-
- m_hGlowSprites[i] = CSprite::SpriteCreate( "sprites/glow04_noz.vmt", GetAbsOrigin(), false );
-
- m_hGlowSprites[i]->SetAttachment( this, LookupAttachment( attachNames[i] ) );
- m_hGlowSprites[i]->SetTransparency( kRenderGlow, 255, 128, 0, 64, kRenderFxNoDissipation );
- m_hGlowSprites[i]->SetBrightness( 255, 0.2f );
- m_hGlowSprites[i]->SetScale( 0.55f, 0.2f );
- }
-}
-
-void CNPC_Dog::CreateBeams( void )
-{
- if ( m_bBeamEffects == false )
- {
- ClearBeams();
- return;
- }
-
- CreateSprites();
-
- for ( int i = 0; i < EFFECT_COUNT; i++ )
- {
- if ( m_hBeams[i] )
- continue;
-
- const char *attachNames[] =
- {
- "physgun",
- "thumb",
- "pinky",
- "index",
- };
-
- m_hBeams[i] = CBeam::BeamCreate( "sprites/physcannon_bluelight2.vmt", 5.0 );
-
- m_hBeams[i]->EntsInit( m_hPhysicsEnt, this );
- m_hBeams[i]->SetEndAttachment( LookupAttachment( attachNames[i] ) );
- m_hBeams[i]->SetBrightness( 255 );
- m_hBeams[i]->SetColor( 255, 255, 255 );
- m_hBeams[i]->SetNoise( 5.5 );
- m_hBeams[i]->SetRenderMode( kRenderTransAdd );
- }
-
-}
-
-bool CNPC_Dog::FindPhysicsObject( const char *pPickupName, CBaseEntity *pIgnore )
-{
- CBaseEntity *pEnt = NULL;
- CBaseEntity *pNearest = NULL;
- float flDist;
- IPhysicsObject *pPhysObj = NULL;
- float flNearestDist = 99999;
-
- if ( pPickupName != NULL && strlen( pPickupName ) > 0 )
- {
- pEnt = gEntList.FindEntityByName( NULL, pPickupName );
-
- if ( m_hUnreachableObjects.Find( pEnt ) == -1 )
- {
- m_bHasObject = false;
- m_hPhysicsEnt = pEnt;
- return true;
- }
- }
-
- while ( ( pEnt = gEntList.FindEntityByClassname( pEnt, "prop_physics" ) ) != NULL )
- {
- //We don't want this one.
- if ( pEnt == pIgnore )
- continue;
-
- if ( m_hUnreachableObjects.Find( pEnt ) != -1 )
- continue;
-
- pPhysObj = pEnt->VPhysicsGetObject();
-
- if( pPhysObj == NULL )
- continue;
-
- if ( pPhysObj->GetMass() > DOG_MAX_THROW_MASS )
- continue;
-
- Vector center = pEnt->WorldSpaceCenter();
- flDist = UTIL_DistApprox2D( GetAbsOrigin(), center );
-
- vcollide_t *pCollide = modelinfo->GetVCollide( pEnt->GetModelIndex() );
-
- if ( pCollide == NULL )
- continue;
-
- if ( pPhysObj->GetGameFlags() & FVPHYSICS_PLAYER_HELD )
- continue;
-
- if ( pPhysObj->IsMoveable() == false )
- continue;
-
- if ( pEnt->GetCollisionGroup() == COLLISION_GROUP_DEBRIS ||
- pEnt->GetCollisionGroup() == COLLISION_GROUP_INTERACTIVE_DEBRIS )
- continue;
-
- if ( center.z > EyePosition().z )
- continue;
-
- if ( flDist >= flNearestDist )
- continue;
-
- if ( FVisible( pEnt ) == false )
- continue;
-
- pNearest = pEnt;
- flNearestDist = flDist;
- }
-
- m_bHasObject = false;
- m_hPhysicsEnt = pNearest;
-
- if ( dog_debug.GetBool() == true )
- {
- if ( pNearest )
- NDebugOverlay::Box( pNearest->WorldSpaceCenter(), pNearest->CollisionProp()->OBBMins(), pNearest->CollisionProp()->OBBMaxs(), 255, 0, 255, true, 3 );
- }
-
- if( m_hPhysicsEnt == NULL )
- {
- return false;
- }
- else
- {
- return true;
- }
-}
-
-//-----------------------------------------------------------------------------
-// Can me enemy see me?
-//-----------------------------------------------------------------------------
-bool CNPC_Dog::CanTargetSeeMe( void )
-{
- CBaseEntity *pEntity = m_hThrowTarget;
-
- if ( pEntity )
- {
- if ( pEntity->IsPlayer() == false )
- return true;
-
- CBasePlayer *pPlayer = dynamic_cast<CBasePlayer*>( pEntity );
-
- if ( pPlayer )
- {
- if ( m_hPhysicsEnt )
- {
- if ( pPlayer->FVisible( m_hPhysicsEnt ) == false )
- return false;
- }
-
- if ( pPlayer->FInViewCone( this ) )
- {
- return true;
- }
- }
- }
-
- return false;
-}
-
-
-//---------------------------------------------------------
-//---------------------------------------------------------
-void CNPC_Dog::RunTask( const Task_t *pTask )
-{
- switch( pTask->iTask )
- {
-
- case TASK_DOG_PICKUP_ITEM:
- {
- PullObject( false );
- }
- break;
-
- case TASK_DOG_GET_PATH_TO_PHYSOBJ:
- {
- //Check this cause our object might have been deleted.
- if ( m_hPhysicsEnt == NULL )
- FindPhysicsObject( NULL );
-
- //And if we still can't find anything, then just go away.
- if ( m_hPhysicsEnt == NULL )
- {
- TaskFail( "Can't find an object I like!" );
- return;
- }
-
- IPhysicsObject *pPhysicsObject = m_hPhysicsEnt->VPhysicsGetObject();
-
- Vector vecGoalPos;
- Vector vecDir;
-
- vecDir = GetLocalOrigin() - m_hPhysicsEnt->WorldSpaceCenter();
- VectorNormalize(vecDir);
- vecDir.z = 0;
-
- if ( m_hPhysicsEnt->GetOwnerEntity() == NULL )
- m_hPhysicsEnt->SetOwnerEntity( this );
-
- if ( pPhysicsObject )
- pPhysicsObject->RecheckCollisionFilter();
-
- vecGoalPos = m_hPhysicsEnt->WorldSpaceCenter() + (vecDir * DOG_PHYSOBJ_MOVE_TO_DIST );
-
- bool bBuiltRoute = false;
-
- //If I'm near my goal, then just walk to it.
- Activity aActivity = ACT_RUN;
-
- if ( ( vecGoalPos - GetLocalOrigin() ).Length() <= 128 )
- aActivity = ACT_WALK;
-
- bBuiltRoute = GetNavigator()->SetGoal( AI_NavGoal_t( vecGoalPos, aActivity ), AIN_NO_PATH_TASK_FAIL );
-
- if ( bBuiltRoute == true )
- TaskComplete();
- else
- {
- m_flTimeToCatch = gpGlobals->curtime + 0.1;
- m_flNextRouteTime = gpGlobals->curtime + 0.3;
- m_flNextSwat = gpGlobals->curtime + 0.1;
-
- if ( m_hUnreachableObjects.Find( m_hPhysicsEnt ) == -1 )
- m_hUnreachableObjects.AddToTail( m_hPhysicsEnt );
-
- m_hPhysicsEnt = NULL;
-
- GetNavigator()->ClearGoal();
- }
- }
- break;
-
- case TASK_WAIT:
- {
- if ( IsWaitFinished() )
- {
- TaskComplete();
- }
-
- if ( m_hPhysicsEnt )
- {
- if ( m_bHasObject == false )
- {
- GetMotor()->SetIdealYawToTarget( m_hPhysicsEnt->GetAbsOrigin() );
- GetMotor()->UpdateYaw();
- }
- }
-
- break;
- }
-
- case TASK_DOG_LAUNCH_ITEM:
- if( IsActivityFinished() )
- {
- if ( m_hPhysicsEnt )
- {
- m_hPhysicsEnt->SetOwnerEntity( NULL );
- }
-
- TaskComplete();
- }
- break;
-
- case TASK_DOG_WAIT_FOR_TARGET_TO_FACE:
- {
- if ( CanTargetSeeMe() )
- TaskComplete();
- }
- break;
-
- case TASK_WAIT_FOR_MOVEMENT:
- {
- if ( GetState() == NPC_STATE_SCRIPT || IsInAScript() )
- {
- BaseClass::RunTask( pTask );
- return;
- }
-
- if ( m_hPhysicsEnt != NULL )
- {
- IPhysicsObject *pPhysObj = m_hPhysicsEnt->VPhysicsGetObject();
-
- if ( !pPhysObj )
- {
- Warning( "npc_dog TASK_WAIT_FOR_MOVEMENT with NULL m_hPhysicsEnt->VPhysicsGetObject\n" );
- }
-
- if ( pPhysObj && pPhysObj->GetGameFlags() & FVPHYSICS_PLAYER_HELD )
- TaskFail( "Player picked it up!" );
-
- //If the object is moving then my old goal might not be valid
- //cancel the schedule and make it restart again in a bit.
- if ( pPhysObj && pPhysObj->IsAsleep() == false && GetNavigator()->IsGoalActive() == false )
- {
- Vector vecGoalPos;
- Vector vecDir;
-
- vecDir = GetLocalOrigin() - m_hPhysicsEnt->WorldSpaceCenter();
- VectorNormalize(vecDir);
- vecDir.z = 0;
-
- vecGoalPos = m_hPhysicsEnt->WorldSpaceCenter() + (vecDir * DOG_PHYSOBJ_MOVE_TO_DIST );
-
- GetNavigator()->ClearGoal();
-
- float flDistance = (vecGoalPos - GetLocalOrigin()).Length();
-
- //If I'm near my goal, then just walk to it.
- Activity aActivity = ACT_RUN;
-
- if ( ( vecGoalPos - GetLocalOrigin() ).Length() <= 128 )
- aActivity = ACT_WALK;
-
- GetNavigator()->SetGoal( AI_NavGoal_t( vecGoalPos, aActivity ), AIN_NO_PATH_TASK_FAIL );
-
- if ( flDistance <= DOG_PHYSOBJ_MOVE_TO_DIST )
- {
- TaskComplete();
- GetNavigator()->StopMoving();
- }
- }
- }
-
- BaseClass::RunTask( pTask );
- }
- break;
-
- case TASK_DOG_WAIT_FOR_OBJECT:
- {
- if ( m_hPhysicsEnt != NULL )
- {
- if ( FVisible( m_hPhysicsEnt ) == false )
- {
- m_flTimeToCatch = 0.0f;
- ClearBeams();
- TaskFail( "Lost sight of the object!" );
- m_hPhysicsEnt->SetOwnerEntity( NULL );
- return;
- }
-
- m_hPhysicsEnt->SetOwnerEntity( this );
-
- Vector vForward;
- AngleVectors( GetAbsAngles(), &vForward );
-
-
- Vector vGunPos;
- GetAttachment( m_iPhysGunAttachment, vGunPos );
-
- Vector vToObject = m_hPhysicsEnt->WorldSpaceCenter() - vGunPos;
- float flDistance = vToObject.Length();
-
- VectorNormalize( vToObject );
-
- SetAim( m_hPhysicsEnt->WorldSpaceCenter() - GetAbsOrigin() );
-
- CBasePlayer *pPlayer = AI_GetSinglePlayer();
-
- float flDistanceToPlayer = flDistance;
-
- if ( pPlayer )
- {
- flDistanceToPlayer = (pPlayer->GetAbsOrigin() - m_hPhysicsEnt->WorldSpaceCenter()).Length();
- }
-
- IPhysicsObject *pPhysObj = m_hPhysicsEnt->VPhysicsGetObject();
- if ( !pPhysObj )
- {
- Warning( "npc_dog: TASK_DOG_WAIT_FOR_OBJECT with m_hPhysicsEnt->VPhysicsGetObject == NULL\n" );
- }
-
- if ( pPhysObj && !( pPhysObj->GetGameFlags() & FVPHYSICS_PLAYER_HELD ) && flDistanceToPlayer > ( flDistance * 2 ) )
- {
- if ( m_flTimeToPull <= gpGlobals->curtime )
- {
- Vector vCurrentVel;
- float flCurrentVel;
- AngularImpulse vCurrentAI;
-
- pPhysObj->GetVelocity( &vCurrentVel, &vCurrentAI );
-
- flCurrentVel = vCurrentVel.Length();
- VectorNormalize( vCurrentVel );
-
- if ( pPhysObj && flDistance <= DOG_PULL_DISTANCE )
- {
- Vector vDir = ( vGunPos - m_hPhysicsEnt->WorldSpaceCenter() );
-
- VectorNormalize( vDir );
-
- vCurrentVel = vCurrentVel * ( flCurrentVel * DOG_PULL_VELOCITY_MOD );
-
- vCurrentAI = vCurrentAI * DOG_PULL_ANGULARIMP_MOD;
- pPhysObj->SetVelocity( &vCurrentVel, &vCurrentAI );
-
- vDir = vDir * flDistance * DOG_PULL_TO_GUN_VEL_MOD;
-
- Vector vAngle( 0, 0, 0 );
- pPhysObj->AddVelocity( &vDir, &vAngle );
-
- CreateBeams();
- }
-
- float flDot = DotProduct( vCurrentVel, vForward );
-
- if ( flDistance >= DOG_PULL_DISTANCE && flDistance <= ( DOG_PULL_DISTANCE * 2 ) && flDot > -0.3 )
- {
- if ( pPhysObj->IsAsleep() == false && !( pPhysObj->GetGameFlags() & FVPHYSICS_PLAYER_HELD ) )
- {
- Vector vecGoalPos;
- Vector vecDir;
-
- vecDir = GetLocalOrigin() - m_hPhysicsEnt->WorldSpaceCenter();
- VectorNormalize(vecDir);
- vecDir.z = 0;
-
- vecGoalPos = m_hPhysicsEnt->WorldSpaceCenter() + (vecDir * DOG_PHYSOBJ_MOVE_TO_DIST );
-
- GetNavigator()->ClearGoal();
-
- //If I'm near my goal, then just walk to it.
- Activity aActivity = ACT_RUN;
-
- if ( ( vecGoalPos - GetLocalOrigin() ).Length() <= 128 )
- aActivity = ACT_WALK;
-
- GetNavigator()->SetGoal( AI_NavGoal_t( vecGoalPos, aActivity ), AIN_NO_PATH_TASK_FAIL );
- }
- }
- }
- }
-
-
- float flDirDot = DotProduct( vToObject, vForward );
-
- if ( flDirDot < 0.2 )
- {
- GetMotor()->SetIdealYawToTarget( m_hPhysicsEnt->GetAbsOrigin() );
- GetMotor()->UpdateYaw();
- }
-
- if ( m_flTimeToCatch < gpGlobals->curtime && m_bDoWaitforObjectBehavior == false )
- {
- m_hPhysicsEnt->SetOwnerEntity( NULL );
- m_flTimeToCatch = 0.0f;
- ClearBeams();
- TaskFail( "Done waiting!" );
- }
- else if ( pPhysObj && ( flDistance <= DOG_CATCH_DISTANCE && !( pPhysObj->GetGameFlags() & FVPHYSICS_PLAYER_HELD ) ) )
- {
- AngularImpulse vZero( 0, 0, 0 );
- pPhysObj->SetVelocity( &vec3_origin, &vZero );
-
- GetNavigator()->StopMoving();
-
- //Fire Output!
- m_OnCatch.FireOutput( this, this );
- m_bHasObject = true;
- ClearBeams();
- TaskComplete();
- }
- }
- else
- {
- GetNavigator()->StopMoving();
-
- ClearBeams();
- TaskFail("No Physics Object!");
- }
-
- }
- break;
-
- case TASK_DOG_CATCH_OBJECT:
- if( IsActivityFinished() )
- {
- m_flTimeToCatch = 0.0f;
- TaskComplete();
- }
- break;
- default:
- BaseClass::RunTask( pTask );
- break;
- }
-}
-
-void CNPC_Dog::SetupThrowTarget( void )
-{
- if ( m_hThrowTarget == NULL )
- {
- m_hThrowTarget = AI_GetSinglePlayer();
- }
-
- SetTarget( m_hThrowTarget );
-}
-
-//---------------------------------------------------------
-//---------------------------------------------------------
-void CNPC_Dog::StartTask( const Task_t *pTask )
-{
- switch( pTask->iTask )
- {
-
- case TASK_DOG_SETUP_THROW_TARGET:
- {
- SetupThrowTarget();
- TaskComplete();
- }
- break;
- case TASK_DOG_GET_PATH_TO_PHYSOBJ:
- {
- FindPhysicsObject( STRING( m_sObjectName ) );
-
- if ( m_hPhysicsEnt == NULL )
- {
- FindPhysicsObject( NULL );
- return;
- }
-
- IPhysicsObject *pPhysicsObject = m_hPhysicsEnt->VPhysicsGetObject();
-
- Vector vecGoalPos;
- Vector vecDir;
-
- vecDir = GetLocalOrigin() - m_hPhysicsEnt->WorldSpaceCenter();
- VectorNormalize(vecDir);
- vecDir.z = 0;
-
- if ( m_hPhysicsEnt->GetOwnerEntity() == NULL )
- m_hPhysicsEnt->SetOwnerEntity( this );
-
- if ( pPhysicsObject )
- pPhysicsObject->RecheckCollisionFilter();
-
- vecGoalPos = m_hPhysicsEnt->WorldSpaceCenter() + (vecDir * DOG_PHYSOBJ_MOVE_TO_DIST );
-
- //If I'm near my goal, then just walk to it.
- Activity aActivity = ACT_RUN;
-
- if ( ( vecGoalPos - GetLocalOrigin() ).Length() <= 128 )
- aActivity = ACT_WALK;
-
- if ( GetNavigator()->SetGoal( AI_NavGoal_t( vecGoalPos, aActivity ), AIN_NO_PATH_TASK_FAIL ) == false )
- {
- if ( m_hUnreachableObjects.Find( m_hPhysicsEnt ) == -1 )
- m_hUnreachableObjects.AddToTail( m_hPhysicsEnt );
-
- FindPhysicsObject( NULL, m_hPhysicsEnt );
-
- m_flTimeToCatch = gpGlobals->curtime + 0.1;
- m_flNextRouteTime = gpGlobals->curtime + 0.3;
- m_flNextSwat = gpGlobals->curtime + 0.1;
-
- GetNavigator()->ClearGoal();
- }
- else
- {
- TaskComplete();
- }
- }
- break;
-
- case TASK_DOG_FACE_OBJECT:
- {
- if( m_hPhysicsEnt == NULL )
- {
- // Physics Object is gone! Probably was an explosive
- // or something else broke it.
- TaskFail("Physics ent NULL");
- return;
- }
-
- Vector vecDir;
-
- vecDir = m_hPhysicsEnt->WorldSpaceCenter() - GetLocalOrigin();
- VectorNormalize(vecDir);
-
- GetMotor()->SetIdealYaw( UTIL_VecToYaw( vecDir ) );
- TaskComplete();
- }
- break;
-
- case TASK_DOG_PICKUP_ITEM:
- {
- if( m_hPhysicsEnt == NULL )
- {
- // Physics Object is gone! Probably was an explosive
- // or something else broke it.
- TaskFail("Physics ent NULL");
- return;
- }
- else
- {
- SetIdealActivity( (Activity)ACT_DOG_PICKUP );
- }
- }
-
- break;
-
- case TASK_DOG_LAUNCH_ITEM:
- {
- if( m_hPhysicsEnt == NULL )
- {
- // Physics Object is gone! Probably was an explosive
- // or something else broke it.
- TaskFail("Physics ent NULL");
- return;
- }
- else
- {
- if ( m_hPhysicsEnt == NULL || m_bHasObject == false )
- {
- TaskFail( "Don't have the item!" );
- return;
- }
-
- SetIdealActivity( (Activity)ACT_DOG_THROW );
- }
- }
-
- break;
-
- case TASK_DOG_WAIT_FOR_TARGET_TO_FACE:
- {
- if ( CanTargetSeeMe() )
- TaskComplete();
- }
- break;
-
- case TASK_DOG_WAIT_FOR_OBJECT:
- {
- SetIdealActivity( (Activity)ACT_DOG_WAITING );
- }
- break;
-
- case TASK_DOG_CATCH_OBJECT:
- {
- SetIdealActivity( (Activity)ACT_DOG_CATCH );
- }
- break;
-
- case TASK_DOG_DELAY_SWAT:
- m_flNextSwat = gpGlobals->curtime + pTask->flTaskData;
-
- if ( m_hThrowTarget == NULL )
- m_hThrowTarget = AI_GetSinglePlayer();
-
- TaskComplete();
- break;
-
- default:
- BaseClass::StartTask( pTask );
- }
-}
-
-void CNPC_Dog::InputTurnBoneFollowersOff( inputdata_t &inputdata )
-{
- if ( m_bBoneFollowersActive )
- {
- m_bBoneFollowersActive = false;
- m_BoneFollowerManager.DestroyBoneFollowers();
- }
-
-}
-
-void CNPC_Dog::InputTurnBoneFollowersOn( inputdata_t &inputdata )
-{
- if ( !m_bBoneFollowersActive )
- {
- m_bBoneFollowersActive = true;
- m_BoneFollowerManager.InitBoneFollowers( this, ARRAYSIZE(pFollowerBoneNames), pFollowerBoneNames );
- }
-}
-
-AI_BEGIN_CUSTOM_NPC( npc_dog, CNPC_Dog )
-
- DECLARE_USES_SCHEDULE_PROVIDER( CAI_FollowBehavior )
-
- DECLARE_ACTIVITY( ACT_DOG_THROW )
- DECLARE_ACTIVITY( ACT_DOG_PICKUP )
- DECLARE_ACTIVITY( ACT_DOG_WAITING )
- DECLARE_ACTIVITY( ACT_DOG_CATCH )
-
- DECLARE_CONDITION( COND_DOG_LOST_PHYSICS_ENTITY )
-
- DECLARE_TASK( TASK_DOG_DELAY_SWAT )
- DECLARE_TASK( TASK_DOG_GET_PATH_TO_PHYSOBJ )
- DECLARE_TASK( TASK_DOG_LAUNCH_ITEM )
- DECLARE_TASK( TASK_DOG_PICKUP_ITEM )
- DECLARE_TASK( TASK_DOG_FACE_OBJECT )
- DECLARE_TASK( TASK_DOG_WAIT_FOR_OBJECT )
- DECLARE_TASK( TASK_DOG_CATCH_OBJECT )
-
- DECLARE_TASK( TASK_DOG_WAIT_FOR_TARGET_TO_FACE )
- DECLARE_TASK( TASK_DOG_SETUP_THROW_TARGET )
-
- DECLARE_ANIMEVENT( AE_DOG_THROW )
- DECLARE_ANIMEVENT( AE_DOG_PICKUP )
- DECLARE_ANIMEVENT( AE_DOG_CATCH )
- DECLARE_ANIMEVENT( AE_DOG_PICKUP_NOEFFECT )
-
-
- DEFINE_SCHEDULE
- (
- SCHED_DOG_FIND_OBJECT,
-
- " Tasks"
- " TASK_DOG_DELAY_SWAT 3"
- " TASK_DOG_GET_PATH_TO_PHYSOBJ 0"
- " TASK_RUN_PATH 0"
- " TASK_WAIT_FOR_MOVEMENT 0"
- " TASK_DOG_FACE_OBJECT 0"
- " TASK_FACE_IDEAL 0"
- " TASK_DOG_PICKUP_ITEM 0"
- " TASK_DOG_SETUP_THROW_TARGET 0"
- " TASK_FACE_TARGET 0.5"
- " TASK_DOG_WAIT_FOR_TARGET_TO_FACE 0"
- " TASK_DOG_LAUNCH_ITEM 0"
- ""
- " Interrupts"
- " COND_DOG_LOST_PHYSICS_ENTITY"
- )
-
- DEFINE_SCHEDULE
- (
- SCHED_DOG_WAIT_THROW_OBJECT,
- " Tasks"
- " TASK_DOG_SETUP_THROW_TARGET 0"
- " TASK_FACE_TARGET 0.5"
- " TASK_DOG_WAIT_FOR_TARGET_TO_FACE 0"
- " TASK_DOG_LAUNCH_ITEM 0"
- ""
- " Interrupts"
- " COND_DOG_LOST_PHYSICS_ENTITY"
- )
-
- DEFINE_SCHEDULE
- (
- SCHED_DOG_CATCH_OBJECT,
-
- " Tasks"
- " TASK_DOG_WAIT_FOR_OBJECT 0"
- " TASK_DOG_CATCH_OBJECT 0"
- " TASK_FACE_PLAYER 0.5"
- " TASK_DOG_WAIT_FOR_TARGET_TO_FACE 0"
- " TASK_DOG_LAUNCH_ITEM 0"
- " TASK_SET_FAIL_SCHEDULE SCHEDULE:SCHED_IDLE_STAND"
- ""
- " Interrupts"
- " COND_DOG_LOST_PHYSICS_ENTITY"
- )
-
-AI_END_CUSTOM_NPC()
+//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: Implements d0g, the loving and caring head crushing Alyx companion. +// +//=============================================================================// + +#include "cbase.h" +#include "npcevent.h" +#include "ai_basenpc.h" +#include "ai_network.h" +#include "ai_navigator.h" +#include "ai_motor.h" +#include "ai_hull.h" +#include "beam_shared.h" +#include "ai_baseactor.h" +#include "npc_rollermine.h" +#include "saverestore_utlvector.h" +#include "physics_bone_follower.h" +#include "Sprite.h" +#include "ai_behavior_follow.h" +#include "collisionutils.h" + +// memdbgon must be the last include file in a .cpp file!!! +#include "tier0/memdbgon.h" + +#define EFFECT_COUNT 4 + +extern ConVar ai_debug_avoidancebounds; + +class CNPC_Dog : public CAI_BaseActor +{ +public: + DECLARE_DATADESC(); + DECLARE_CLASS( CNPC_Dog, CAI_BaseActor ); + Class_T Classify ( void ); + void Spawn( void ); + void Precache( void ); + void StartTask( const Task_t *pTask ); + void HandleAnimEvent( animevent_t *pEvent ); + int SelectSchedule( void ); + + bool FindPhysicsObject( const char *pPickupName, CBaseEntity *pIgnore = NULL ); + void RunTask( const Task_t *pTask ); + void CreateBeams( void ); + void ClearBeams( void ); + + void PrescheduleThink( void ); + + bool CanTargetSeeMe( void ); + + Vector FacingPosition( void ) { return WorldSpaceCenter(); } + float GetHeadDebounce( void ) { return 0.8; } // how much of previous head turn to use + + void InputSetPickupTarget( inputdata_t &inputdata ); + void InputStartCatchThrowBehavior( inputdata_t &inputdata ); + void InputStopCatchThrowBehavior( inputdata_t &inputdata ); + void InputPlayerPickupObject( inputdata_t &inputdata ); + + void InputStartWaitAndCatch( inputdata_t &inputdata ); + void InputStopWaitAndCatch( inputdata_t &inputdata ); + void InputSetThrowArcModifier( inputdata_t &inputdata ); + void InputSetThrowTarget( inputdata_t &inputdata ); + + void InputTurnBoneFollowersOff( inputdata_t &inputdata ); + void InputTurnBoneFollowersOn( inputdata_t &inputdata ); + + void CleanCatchAndThrow( bool bClearTimers = true ); + void SetTurnActivity ( void ); + void ThrowObject( const char *pAttachmentName ); + void PickupOrCatchObject( const char *pAttachmentName ); + void PullObject( bool bMantain ); + void SetupThrowTarget( void ); + + void GatherConditions( void ); + + Disposition_t IRelationType( CBaseEntity *pTarget ); + + int OnTakeDamage_Alive( const CTakeDamageInfo &info ); + + void MantainBoneFollowerCollisionGroups( int CollisionGroup ); + virtual void SetPlayerAvoidState( void ); + +protected: + enum + { + COND_DOG_LOST_PHYSICS_ENTITY = BaseClass::NEXT_CONDITION, + + NEXT_CONDITION, + }; + +protected: + float m_flNextSwat; + float m_flTimeToCatch; + float m_flTimeToPull; + EHANDLE m_hPhysicsEnt; + EHANDLE m_hThrowTarget; + + int m_iPhysGunAttachment; + bool m_bDoCatchThrowBehavior; + bool m_bDoWaitforObjectBehavior; + string_t m_sObjectName; + + COutputEvent m_OnThrow; + COutputEvent m_OnCatch; + COutputEvent m_OnPickup; + + float m_flThrowArcModifier; + int m_iContainerMoveType; + float m_flNextRouteTime; + + bool m_bHasObject; + bool m_bBeamEffects; + + CUtlVector< CHandle <CBaseEntity> > m_hUnreachableObjects; + + // Contained Bone Follower manager + CBoneFollowerManager m_BoneFollowerManager; + + bool CreateVPhysics( void ); + void UpdateOnRemove( void ); + void NPCThink( void ); + void Event_Killed( const CTakeDamageInfo &info ); + + void CreateSprites( void ); + void ClearSprites( void ); + CHandle<CSprite> m_hGlowSprites[EFFECT_COUNT]; + CHandle<CBeam> m_hBeams[EFFECT_COUNT]; //This is temp. + + virtual bool CreateBehaviors( void ); + CAI_FollowBehavior m_FollowBehavior; + + bool m_bBoneFollowersActive; + + +protected: + + DEFINE_CUSTOM_AI; +}; + +LINK_ENTITY_TO_CLASS( npc_dog, CNPC_Dog ); + +BEGIN_DATADESC( CNPC_Dog ) + DEFINE_EMBEDDED( m_BoneFollowerManager ), +// m_FollowBehavior + DEFINE_FIELD( m_flNextSwat, FIELD_TIME ), + DEFINE_FIELD( m_flTimeToCatch, FIELD_TIME ), + DEFINE_FIELD( m_flTimeToPull, FIELD_TIME ), + DEFINE_FIELD( m_hPhysicsEnt, FIELD_EHANDLE ), + DEFINE_FIELD( m_hThrowTarget, FIELD_EHANDLE ), + DEFINE_FIELD( m_iPhysGunAttachment, FIELD_INTEGER ), + DEFINE_FIELD( m_bDoCatchThrowBehavior, FIELD_BOOLEAN ), + DEFINE_FIELD( m_bDoWaitforObjectBehavior, FIELD_BOOLEAN ), + DEFINE_FIELD( m_sObjectName, FIELD_STRING ), + DEFINE_FIELD( m_flThrowArcModifier, FIELD_FLOAT ), + DEFINE_FIELD( m_flNextRouteTime, FIELD_TIME ), + DEFINE_FIELD( m_bHasObject, FIELD_BOOLEAN ), + DEFINE_FIELD( m_iContainerMoveType, FIELD_INTEGER ), + DEFINE_FIELD( m_bBeamEffects, FIELD_BOOLEAN ), + DEFINE_FIELD( m_bBoneFollowersActive, FIELD_BOOLEAN ), + DEFINE_UTLVECTOR( m_hUnreachableObjects, FIELD_EHANDLE ), + DEFINE_AUTO_ARRAY( m_hGlowSprites, FIELD_EHANDLE ), + DEFINE_AUTO_ARRAY( m_hBeams, FIELD_EHANDLE ), + DEFINE_INPUTFUNC( FIELD_STRING, "SetPickupTarget", InputSetPickupTarget ), + DEFINE_INPUTFUNC( FIELD_STRING, "StartCatchThrowBehavior", InputStartCatchThrowBehavior ), + DEFINE_INPUTFUNC( FIELD_STRING, "StopCatchThrowBehavior", InputStopCatchThrowBehavior ), + DEFINE_INPUTFUNC( FIELD_VOID, "PlayerPickupObject", InputPlayerPickupObject ), + DEFINE_INPUTFUNC( FIELD_VOID, "StartWaitAndCatch", InputStartWaitAndCatch ), + DEFINE_INPUTFUNC( FIELD_VOID, "StopWaitAndCatch", InputStopWaitAndCatch ), + DEFINE_INPUTFUNC( FIELD_FLOAT, "SetThrowArcModifier", InputSetThrowArcModifier ), + DEFINE_INPUTFUNC( FIELD_STRING, "SetThrowTarget", InputSetThrowTarget ), + DEFINE_INPUTFUNC( FIELD_VOID, "TurnBoneFollowersOff", InputTurnBoneFollowersOff ), + DEFINE_INPUTFUNC( FIELD_VOID, "TurnBoneFollowersOn", InputTurnBoneFollowersOn ), + DEFINE_OUTPUT( m_OnThrow, "OnDogThrow"), + DEFINE_OUTPUT( m_OnCatch, "OnDogCatch"), + DEFINE_OUTPUT( m_OnPickup, "OnDogPickup"), + +END_DATADESC() + +#define DOG_PHYSOBJ_MOVE_TO_DIST 96 +#define DOG_PULL_DISTANCE 200 +#define DOG_CATCH_DISTANCE 48 +#define DOG_PULL_VELOCITY_MOD 0.1f +#define DOG_PULL_ANGULARIMP_MOD 0.8f +#define DOG_PULL_TO_GUN_VEL_MOD 2.0f +#define DOG_MAX_THROW_MASS 250.0f +#define DOG_PHYSGUN_ATTACHMENT_NAME "physgun" + +// These bones have physics shadows +static const char *pFollowerBoneNames[] = +{ + // head + "Dog_Model.Eye", + "Dog_Model.Pelvis", +}; + +enum +{ + SCHED_DOG_FIND_OBJECT = LAST_SHARED_SCHEDULE, + SCHED_DOG_CATCH_OBJECT, + SCHED_DOG_WAIT_THROW_OBJECT, +}; + +//========================================================= +// tasks +//========================================================= +enum +{ + TASK_DOG_DELAY_SWAT = LAST_SHARED_TASK, + TASK_DOG_GET_PATH_TO_PHYSOBJ, + TASK_DOG_PICKUP_ITEM, + TASK_DOG_LAUNCH_ITEM, + TASK_DOG_FACE_OBJECT, + TASK_DOG_WAIT_FOR_OBJECT, + TASK_DOG_CATCH_OBJECT, + TASK_DOG_WAIT_FOR_TARGET_TO_FACE, + TASK_DOG_SETUP_THROW_TARGET, +}; + +int ACT_DOG_THROW; +int ACT_DOG_PICKUP; +int ACT_DOG_WAITING; +int ACT_DOG_CATCH; + +int AE_DOG_THROW; +int AE_DOG_PICKUP; +int AE_DOG_CATCH; +int AE_DOG_PICKUP_NOEFFECT; + +ConVar dog_max_wait_time( "dog_max_wait_time", "7" ); +ConVar dog_debug( "dog_debug", "0" ); + +//----------------------------------------------------------------------------- +// Classify - indicates this NPC's place in the +// relationship table. +//----------------------------------------------------------------------------- +Class_T CNPC_Dog::Classify ( void ) +{ + return CLASS_PLAYER_ALLY_VITAL; +} + +bool CNPC_Dog::CreateBehaviors( void ) +{ + AddBehavior( &m_FollowBehavior ); + + return BaseClass::CreateBehaviors(); +} + +Disposition_t CNPC_Dog::IRelationType( CBaseEntity *pTarget ) +{ + if ( NPC_Rollermine_IsRollermine( pTarget ) ) + { + if ( pTarget->HasSpawnFlags( SF_ROLLERMINE_FRIENDLY ) ) + return D_LI; + } + + return BaseClass::IRelationType( pTarget ); +} + +//--------------------------------------------------------- +//--------------------------------------------------------- +bool CNPC_Dog::CreateVPhysics( void ) +{ + BaseClass::CreateVPhysics(); + + if ( m_bBoneFollowersActive == true && !m_BoneFollowerManager.GetNumBoneFollowers() ) + { + m_BoneFollowerManager.InitBoneFollowers( this, ARRAYSIZE(pFollowerBoneNames), pFollowerBoneNames ); + } + return true; +} + +//--------------------------------------------------------- +//--------------------------------------------------------- +void CNPC_Dog::UpdateOnRemove( void ) +{ + m_BoneFollowerManager.DestroyBoneFollowers(); + BaseClass::UpdateOnRemove(); +} + +void CNPC_Dog::GatherConditions( void ) +{ + if ( IsInAScript() ) + { + ClearSenseConditions(); + return; + } + + BaseClass::GatherConditions(); +} + +int CNPC_Dog::OnTakeDamage_Alive( const CTakeDamageInfo &info ) +{ + if ( IsInAScript() ) + return 0; + + return BaseClass::OnTakeDamage_Alive( info ); +} + +//----------------------------------------------------------------------------- +// This function checks if Dog's collision group doesn't match his bone follower's and fixes them up. +//----------------------------------------------------------------------------- +void CNPC_Dog::MantainBoneFollowerCollisionGroups( int iCollisionGroup ) +{ + if ( m_bBoneFollowersActive == false ) + return; + + physfollower_t* pBone = m_BoneFollowerManager.GetBoneFollower( 0 ); + + if ( pBone && pBone->hFollower && pBone->hFollower->GetCollisionGroup() != iCollisionGroup ) + { + for ( int i = 0; i < m_BoneFollowerManager.GetNumBoneFollowers(); i++ ) + { + pBone = m_BoneFollowerManager.GetBoneFollower( i ); + + if ( pBone && pBone->hFollower ) + { + pBone->hFollower->SetCollisionGroup( iCollisionGroup ); + } + } + } +} + +void CNPC_Dog::SetPlayerAvoidState( void ) +{ + bool bIntersectingBoneFollowers = false; + bool bIntersectingNPCBox = false; + + Vector vNothing; + + GetSequenceLinearMotion( GetSequence(), &vNothing ); + bool bIsMoving = ( IsMoving() || ( vNothing != vec3_origin ) ); + + //If we are coming out of a script, check if we are stuck inside the player. + if ( m_bPerformAvoidance || ( ShouldPlayerAvoid() && bIsMoving ) ) + { + trace_t trace; + Vector vMins, vMaxs; + Vector vWorldMins, vWorldMaxs; + Vector vPlayerMins, vPlayerMaxs; + physfollower_t *pBone; + int i; + + CBasePlayer *pLocalPlayer = AI_GetSinglePlayer(); + + if ( pLocalPlayer ) + { + vWorldMins = WorldAlignMins(); + vWorldMaxs = WorldAlignMaxs(); + + vPlayerMins = pLocalPlayer->GetAbsOrigin() + pLocalPlayer->WorldAlignMins(); + vPlayerMaxs = pLocalPlayer->GetAbsOrigin() + pLocalPlayer->WorldAlignMaxs(); + + // check if the player intersects the bounds of any of the bone followers + for ( i = 0; i < m_BoneFollowerManager.GetNumBoneFollowers(); i++ ) + { + pBone = m_BoneFollowerManager.GetBoneFollower( i ); + if ( pBone && pBone->hFollower ) + { + pBone->hFollower->CollisionProp()->WorldSpaceSurroundingBounds( &vMins, &vMaxs ); + if ( IsBoxIntersectingBox( vMins, vMaxs, vPlayerMins, vPlayerMaxs ) ) + { + bIntersectingBoneFollowers = true; + break; + } + } + } + + bIntersectingNPCBox = IsBoxIntersectingBox( GetAbsOrigin() + vWorldMins, GetAbsOrigin() + vWorldMaxs, vPlayerMins, vPlayerMaxs ); + + if ( ai_debug_avoidancebounds.GetBool() ) + { + int iRed = ( bIntersectingNPCBox == true ) ? 255 : 0; + + NDebugOverlay::Box( GetAbsOrigin(), vWorldMins, vWorldMaxs, iRed, 0, 255, 64, 0.1 ); + + // draw the bounds of the bone followers + for ( i = 0; i < m_BoneFollowerManager.GetNumBoneFollowers(); i++ ) + { + pBone = m_BoneFollowerManager.GetBoneFollower( i ); + if ( pBone && pBone->hFollower ) + { + pBone->hFollower->CollisionProp()->WorldSpaceSurroundingBounds( &vMins, &vMaxs ); + iRed = ( IsBoxIntersectingBox( vMins, vMaxs, vPlayerMins, vPlayerMaxs ) ) ? 255 : 0; + + NDebugOverlay::Box( vec3_origin, vMins, vMaxs, iRed, 0, 255, 64, 0.1 ); + } + } + } + } + } + + m_bPlayerAvoidState = ShouldPlayerAvoid(); + m_bPerformAvoidance = bIntersectingNPCBox || bIntersectingBoneFollowers; + + if ( GetCollisionGroup() == COLLISION_GROUP_NPC || GetCollisionGroup() == COLLISION_GROUP_NPC_ACTOR ) + { + if ( bIntersectingNPCBox == true ) + { + SetCollisionGroup( COLLISION_GROUP_NPC_ACTOR ); + } + else + { + SetCollisionGroup( COLLISION_GROUP_NPC ); + } + + if ( bIntersectingBoneFollowers == true ) + { + MantainBoneFollowerCollisionGroups( COLLISION_GROUP_NPC_ACTOR ); + } + else + { + MantainBoneFollowerCollisionGroups( COLLISION_GROUP_NPC ); + } + } +} +//--------------------------------------------------------- +//--------------------------------------------------------- +void CNPC_Dog::NPCThink( void ) +{ + BaseClass::NPCThink(); + + if ( m_hPhysicsEnt == NULL ) + { + ClearBeams(); + m_bHasObject = false; + } + + if ( m_bHasObject == true ) + { + RelaxAim(); + PullObject( true ); + } + + + // update follower bones + m_BoneFollowerManager.UpdateBoneFollowers(this); +} + +//--------------------------------------------------------- +//--------------------------------------------------------- +void CNPC_Dog::Event_Killed( const CTakeDamageInfo &info ) +{ + m_BoneFollowerManager.DestroyBoneFollowers(); + BaseClass::Event_Killed( info ); +} + +//----------------------------------------------------------------------------- +// Spawn +//----------------------------------------------------------------------------- +void CNPC_Dog::Spawn( void ) +{ + m_bBoneFollowersActive = true; + + Precache(); + + BaseClass::Spawn(); + + SetModel( "models/dog.mdl" ); + + SetHullType( HULL_WIDE_HUMAN ); + SetHullSizeNormal(); + + SetSolid( SOLID_BBOX ); + AddSolidFlags( FSOLID_NOT_STANDABLE ); + SetMoveType( MOVETYPE_STEP ); + SetBloodColor( BLOOD_COLOR_MECH ); + + m_iHealth = 999; + m_flFieldOfView = 0.5;// indicates the width of this NPC's forward view cone ( as a dotproduct result ) + m_NPCState = NPC_STATE_NONE; + + m_takedamage = DAMAGE_NO; + + CapabilitiesAdd( bits_CAP_MOVE_GROUND | bits_CAP_OPEN_DOORS | bits_CAP_TURN_HEAD | bits_CAP_ANIMATEDFACE ); + CapabilitiesAdd( bits_CAP_FRIENDLY_DMG_IMMUNE ); + + NPCInit(); + + m_iPhysGunAttachment = LookupAttachment( DOG_PHYSGUN_ATTACHMENT_NAME ); + + m_bDoCatchThrowBehavior = false; + m_bDoWaitforObjectBehavior = false; + m_bHasObject = false; + m_bBeamEffects = true; + + m_flThrowArcModifier = 1.0f; + + m_flNextSwat = gpGlobals->curtime; + m_flNextRouteTime = gpGlobals->curtime; +} + + +void CNPC_Dog::PrescheduleThink( void ) +{ + BaseClass::PrescheduleThink(); + + if ( m_hPhysicsEnt ) + { + IPhysicsObject *pPhysObj = m_hPhysicsEnt->VPhysicsGetObject(); + + if ( pPhysObj && pPhysObj->GetGameFlags() & FVPHYSICS_PLAYER_HELD ) + { + m_hPhysicsEnt->SetOwnerEntity( NULL ); + } + } + + if ( m_flTimeToCatch < gpGlobals->curtime ) + m_flTimeToCatch = 0.0f; + + + if ( GetIdealActivity() == ACT_IDLE ) + { + if ( m_hPhysicsEnt && m_bHasObject == true ) + { + SetIdealActivity( (Activity)ACT_DOG_WAITING ); + } + } +} + +int CNPC_Dog::SelectSchedule ( void ) +{ + ClearCondition( COND_DOG_LOST_PHYSICS_ENTITY ); + + if ( GetState() == NPC_STATE_SCRIPT || IsInAScript() ) + return BaseClass::SelectSchedule(); + + if ( BehaviorSelectSchedule() ) + return BaseClass::SelectSchedule(); + + if ( m_bDoWaitforObjectBehavior == true ) + { + if ( m_hPhysicsEnt ) + return SCHED_DOG_CATCH_OBJECT; + } + + if ( m_bDoCatchThrowBehavior == true ) + { + if ( m_flTimeToCatch < 0.1 && m_flNextSwat <= gpGlobals->curtime ) + { + return SCHED_DOG_FIND_OBJECT; + } + + if ( m_flTimeToCatch > gpGlobals->curtime && m_hPhysicsEnt ) + return SCHED_DOG_CATCH_OBJECT; + } + else + { + if ( m_hPhysicsEnt ) + { + if ( m_bHasObject == true ) + { + return SCHED_DOG_WAIT_THROW_OBJECT; + } + } + } + + return BaseClass::SelectSchedule(); +} + +void CNPC_Dog::PullObject( bool bMantain ) +{ + if ( m_hPhysicsEnt == NULL ) + { + TaskFail( "Ack! No Phys Object!"); + return; + } + + IPhysicsObject *pPhysObj = m_hPhysicsEnt->VPhysicsGetObject(); + + if ( pPhysObj == NULL ) + { + TaskFail( "Pulling object with no Phys Object?!" ); + return; + } + + if( pPhysObj->GetGameFlags() & FVPHYSICS_PLAYER_HELD ) + { + m_bHasObject = false; + ClearBeams(); + TaskFail("Player Grabbed Ball"); + return; + } + + CreateBeams(); + + Vector vGunPos; + GetAttachment( m_iPhysGunAttachment, vGunPos ); + float flDistance = ( vGunPos - m_hPhysicsEnt->WorldSpaceCenter() ).Length(); + + if ( bMantain == false ) + { + if ( flDistance <= DOG_CATCH_DISTANCE ) + { + m_hPhysicsEnt->SetOwnerEntity( this ); + + GetNavigator()->StopMoving(); + + //Fire Output! + m_OnPickup.FireOutput( this, this ); + + m_bHasObject = true; + ClearBeams(); + TaskComplete(); + return; + } + } + + Vector vDir = ( vGunPos - m_hPhysicsEnt->WorldSpaceCenter() ); + + Vector vCurrentVel; + float flCurrentVel; + AngularImpulse vCurrentAI; + + pPhysObj->GetVelocity( &vCurrentVel, &vCurrentAI ); + flCurrentVel = vCurrentVel.Length(); + + VectorNormalize( vCurrentVel ); + VectorNormalize( vDir ); + + float flVelMod = DOG_PULL_VELOCITY_MOD; + + if ( bMantain == true ) + flVelMod *= 2; + + vCurrentVel = vCurrentVel * flCurrentVel * flVelMod; + + vCurrentAI = vCurrentAI * DOG_PULL_ANGULARIMP_MOD; + pPhysObj->SetVelocity( &vCurrentVel, &vCurrentAI ); + + vDir = vDir * flDistance * (DOG_PULL_TO_GUN_VEL_MOD * 2); + + Vector vAngle( 0, 0, 0 ); + pPhysObj->AddVelocity( &vDir, &vAngle ); +} + +//----------------------------------------------------------------------------- +// Precache - precaches all resources this NPC needs +//----------------------------------------------------------------------------- +void CNPC_Dog::Precache( void ) +{ + PrecacheModel( "models/dog.mdl" ); + + PrecacheScriptSound( "Weapon_PhysCannon.Launch" ); + + PrecacheModel( "sprites/orangelight1.vmt" ); + PrecacheModel( "sprites/physcannon_bluelight2.vmt" ); + PrecacheModel( "sprites/glow04_noz.vmt" ); + + BaseClass::Precache(); +} + +void CNPC_Dog::CleanCatchAndThrow( bool bClearTimers ) +{ + if ( m_hPhysicsEnt ) + { + if ( m_bHasObject == true ) + { + IPhysicsObject *pPhysObj = m_hPhysicsEnt->VPhysicsGetObject(); + + m_hPhysicsEnt->SetParent( NULL ); + m_hPhysicsEnt->SetOwnerEntity( NULL ); + + Vector vGunPos; + QAngle angGunAngles; + GetAttachment( m_iPhysGunAttachment, vGunPos, angGunAngles ); + + if ( pPhysObj ) + { + pPhysObj->Wake(); + pPhysObj->RemoveShadowController(); + pPhysObj->SetPosition( vGunPos, angGunAngles, true ); + } + else + { + Warning( "CleanCatchAndThrow: m_hPhysicsEnt->VPhysicsGetObject == NULL!\n" ); + } + + m_hPhysicsEnt->SetMoveType( (MoveType_t)m_iContainerMoveType ); + + if ( pPhysObj ) + { + pPhysObj->RecheckCollisionFilter(); + } + + ClearBeams(); + } + + m_hPhysicsEnt = NULL; + } + + if ( bClearTimers == true ) + { + m_bDoCatchThrowBehavior = false; + m_bDoWaitforObjectBehavior = false; + m_flTimeToCatch = 0.0f; + m_flNextSwat = 0.0f; + + SetCondition( COND_DOG_LOST_PHYSICS_ENTITY ); + } +} + +void CNPC_Dog::InputPlayerPickupObject ( inputdata_t &inputdata ) +{ + if ( m_bDoWaitforObjectBehavior == true ) + { + if ( m_hPhysicsEnt != inputdata.pCaller ) + { + if ( m_hPhysicsEnt != NULL ) + CleanCatchAndThrow( false ); + + //Reset this cause CleanCatchAndThrow clears it. + m_bDoWaitforObjectBehavior = true; + m_hPhysicsEnt = inputdata.pCaller; + } + } + else if ( m_bDoCatchThrowBehavior == true ) + { + if ( m_sObjectName != NULL_STRING ) + { + if ( m_hPhysicsEnt != inputdata.pCaller ) + { + if ( m_hPhysicsEnt != NULL ) + CleanCatchAndThrow( false ); + + //Reset this cause CleanCatchAndThrow clears it. + m_bDoCatchThrowBehavior = true; + m_hPhysicsEnt = inputdata.pCaller; + } + } + } +} + +void CNPC_Dog::InputSetThrowArcModifier( inputdata_t &inputdata ) +{ + m_flThrowArcModifier = inputdata.value.Float(); +} + +void CNPC_Dog::InputSetPickupTarget( inputdata_t &inputdata ) +{ + CleanCatchAndThrow( false ); + FindPhysicsObject( inputdata.value.String() ); +} + +void CNPC_Dog::InputStartWaitAndCatch( inputdata_t &inputdata ) +{ + CleanCatchAndThrow(); + m_bDoWaitforObjectBehavior = true; +} + +void CNPC_Dog::InputStopWaitAndCatch( inputdata_t &inputdata ) +{ + CleanCatchAndThrow(); +} + +void CNPC_Dog::InputStartCatchThrowBehavior( inputdata_t &inputdata ) +{ + CleanCatchAndThrow(); + + m_sObjectName = MAKE_STRING( inputdata.value.String() ); + m_bDoCatchThrowBehavior = true; + + m_flTimeToCatch = 0.0f; + m_flNextSwat = 0.0f; + + FindPhysicsObject( inputdata.value.String() ); +} + +void CNPC_Dog::InputStopCatchThrowBehavior( inputdata_t &inputdata ) +{ + m_bDoCatchThrowBehavior = false; + + m_flTimeToCatch = 0.0f; + m_flNextSwat = 0.0f; + m_sObjectName = NULL_STRING; + + CleanCatchAndThrow(); +} + +void CNPC_Dog::InputSetThrowTarget( inputdata_t &inputdata ) +{ + m_hThrowTarget = gEntList.FindEntityByName( NULL, inputdata.value.String(), NULL, inputdata.pActivator, inputdata.pCaller ); +} + +void CNPC_Dog::SetTurnActivity( void ) +{ + BaseClass::SetTurnActivity(); + + if ( GetIdealActivity() == ACT_IDLE ) + { + if ( m_hPhysicsEnt && m_bHasObject == true ) + SetIdealActivity( (Activity)ACT_DOG_WAITING ); + } +} + +void CNPC_Dog::ThrowObject( const char *pAttachmentName ) +{ + if ( m_hPhysicsEnt ) + { + m_bHasObject = false; + + IPhysicsObject *pPhysObj = m_hPhysicsEnt->VPhysicsGetObject(); + + if ( pPhysObj ) + { + Vector vGunPos; + QAngle angGunAngles; + + AngularImpulse angVelocity = RandomAngularImpulse( -250 , -250 ) / pPhysObj->GetMass(); + + InvalidateBoneCache(); + + int iAttachment = LookupAttachment( pAttachmentName ); + + if ( iAttachment == 0 ) + iAttachment = m_iPhysGunAttachment; + + GetAttachment( iAttachment, vGunPos, angGunAngles ); + + pPhysObj->Wake(); + + if ( pPhysObj->GetShadowController() ) + { + m_hPhysicsEnt->SetParent( NULL ); + m_hPhysicsEnt->SetMoveType( (MoveType_t)m_iContainerMoveType ); + m_hPhysicsEnt->SetOwnerEntity( this ); + + pPhysObj->RemoveShadowController(); + pPhysObj->SetPosition( m_hPhysicsEnt->GetLocalOrigin(), m_hPhysicsEnt->GetLocalAngles(), true ); + + pPhysObj->RecheckCollisionFilter(); + pPhysObj->RecheckContactPoints(); + } + + if ( m_hThrowTarget == NULL ) + m_hThrowTarget = AI_GetSinglePlayer(); + + Vector vThrowDirection; + + if ( m_hThrowTarget ) + { + Vector vThrowOrigin = m_hThrowTarget->GetAbsOrigin(); + + if ( m_hThrowTarget->IsPlayer() ) + vThrowOrigin = vThrowOrigin + Vector( random->RandomFloat( -128, 128 ), random->RandomFloat( -128, 128 ), 0 ); + + Vector vecToss = VecCheckToss( this, vGunPos, vThrowOrigin, m_flThrowArcModifier, 1.0f, true ); + + if( vecToss == vec3_origin ) + { + // Fix up an impossible throw so dog will at least toss the box in the target's general direction instead of dropping it. + // Also toss it up in the air so it will fall down and break. (Just throw the box up at a 45 degree angle) + Vector forward, up; + GetVectors( &forward, NULL, &up ); + + vecToss = forward + up; + VectorNormalize( vecToss ); + + vecToss *= pPhysObj->GetMass() * 30.0f; + } + + vThrowDirection = vecToss + ( m_hThrowTarget->GetSmoothedVelocity() / 2 ); + + Vector vLinearDrag; + + Vector unitVel = vThrowDirection; + VectorNormalize( unitVel ); + + float flTest = 1000 / vThrowDirection.Length(); + + float flDrag = pPhysObj->CalculateLinearDrag( vThrowDirection ); + vThrowDirection = vThrowDirection + ( unitVel * ( flDrag * flDrag ) ) / flTest; + + pPhysObj->SetVelocity( &vThrowDirection, &angVelocity ); + + m_flTimeToCatch = gpGlobals->curtime + dog_max_wait_time.GetFloat(); + + //Don't start pulling until the object is away from me. + //We base the time on the throw velocity. + m_flTimeToPull = gpGlobals->curtime + ( 1000 / vThrowDirection.Length() ); + } + + //Fire Output! + m_OnThrow.FireOutput( this, this ); + + ClearBeams(); + + if ( m_bBeamEffects == true ) + { + EmitSound( "Weapon_PhysCannon.Launch" ); + + CBeam *pBeam = CBeam::BeamCreate( "sprites/orangelight1.vmt", 1.8 ); + + if ( pBeam != NULL ) + { + pBeam->PointEntInit( m_hPhysicsEnt->WorldSpaceCenter(), this ); + pBeam->SetEndAttachment( m_iPhysGunAttachment ); + pBeam->SetWidth( 6.4 ); + pBeam->SetEndWidth( 12.8 ); + pBeam->SetBrightness( 255 ); + pBeam->SetColor( 255, 255, 255 ); + pBeam->LiveForTime( 0.2f ); + pBeam->RelinkBeam(); + pBeam->SetNoise( 2 ); + } + + Vector shotDir = ( m_hPhysicsEnt->WorldSpaceCenter() - vGunPos ); + VectorNormalize( shotDir ); + + CPVSFilter filter( m_hPhysicsEnt->WorldSpaceCenter() ); + te->GaussExplosion( filter, 0.0f, m_hPhysicsEnt->WorldSpaceCenter() - ( shotDir * 4.0f ), RandomVector(-1.0f, 1.0f), 0 ); + } + } + } +} + +void CNPC_Dog::PickupOrCatchObject( const char *pAttachmentName ) +{ + if ( m_hPhysicsEnt ) + { + InvalidateBoneCache(); + + int iAttachment = LookupAttachment( pAttachmentName ); + + if ( iAttachment == 0 ) + iAttachment = m_iPhysGunAttachment; + + // Move physobject to shadow + IPhysicsObject *pPhysicsObject = m_hPhysicsEnt->VPhysicsGetObject(); + if ( pPhysicsObject ) + { + pPhysicsObject->SetShadow( 1e4, 1e4, false, false ); + pPhysicsObject->UpdateShadow( GetAbsOrigin(), GetAbsAngles(), false, 0 ); + } + + m_iContainerMoveType = m_hPhysicsEnt->GetMoveType(); + m_hPhysicsEnt->SetMoveType( MOVETYPE_NONE ); + + m_hPhysicsEnt->SetParent( this, iAttachment ); + + m_hPhysicsEnt->SetLocalOrigin( vec3_origin ); + m_hPhysicsEnt->SetLocalAngles( vec3_angle ); + + m_hPhysicsEnt->SetGroundEntity( NULL ); + + + if ( m_hPhysicsEnt->GetOwnerEntity() == NULL ) + m_hPhysicsEnt->SetOwnerEntity( this ); + + if ( pPhysicsObject ) + pPhysicsObject->RecheckCollisionFilter(); + + m_bHasObject = true; + + //Fire Output! + m_OnPickup.FireOutput( this, this ); + } +} + +//----------------------------------------------------------------------------- +// HandleAnimEvent - catches the NPC-specific messages +// that occur when tagged animation frames are played. +//----------------------------------------------------------------------------- +void CNPC_Dog::HandleAnimEvent( animevent_t *pEvent ) +{ + if ( pEvent->event == AE_DOG_THROW ) + { + ThrowObject( pEvent->options ); + return; + } + + if ( pEvent->event == AE_DOG_PICKUP || pEvent->event == AE_DOG_CATCH || pEvent->event == AE_DOG_PICKUP_NOEFFECT ) + { + if ( pEvent->event == AE_DOG_PICKUP_NOEFFECT ) + m_bBeamEffects = false; + else + m_bBeamEffects = true; + + PickupOrCatchObject( pEvent->options ); + return; + } + + BaseClass::HandleAnimEvent( pEvent ); +} + +void CNPC_Dog::ClearBeams( void ) +{ + ClearSprites(); + + // Turn off sprites + for ( int i = 0; i < EFFECT_COUNT; i++ ) + { + if ( m_hBeams[i] != NULL ) + { + UTIL_Remove( m_hBeams[i] ); + m_hBeams[i] = NULL; + } + } +} + +void CNPC_Dog::ClearSprites( void ) +{ + // Turn off sprites + for ( int i = 0; i < EFFECT_COUNT; i++ ) + { + if ( m_hGlowSprites[i] != NULL ) + { + UTIL_Remove( m_hGlowSprites[i] ); + m_hGlowSprites[i] = NULL; + } + } +} + +void CNPC_Dog::CreateSprites( void ) +{ + //Create the glow sprites + for ( int i = 0; i < EFFECT_COUNT; i++ ) + { + if ( m_hGlowSprites[i] ) + continue; + + const char *attachNames[] = + { + "physgun", + "thumb", + "pinky", + "index", + }; + + m_hGlowSprites[i] = CSprite::SpriteCreate( "sprites/glow04_noz.vmt", GetAbsOrigin(), false ); + + m_hGlowSprites[i]->SetAttachment( this, LookupAttachment( attachNames[i] ) ); + m_hGlowSprites[i]->SetTransparency( kRenderGlow, 255, 128, 0, 64, kRenderFxNoDissipation ); + m_hGlowSprites[i]->SetBrightness( 255, 0.2f ); + m_hGlowSprites[i]->SetScale( 0.55f, 0.2f ); + } +} + +void CNPC_Dog::CreateBeams( void ) +{ + if ( m_bBeamEffects == false ) + { + ClearBeams(); + return; + } + + CreateSprites(); + + for ( int i = 0; i < EFFECT_COUNT; i++ ) + { + if ( m_hBeams[i] ) + continue; + + const char *attachNames[] = + { + "physgun", + "thumb", + "pinky", + "index", + }; + + m_hBeams[i] = CBeam::BeamCreate( "sprites/physcannon_bluelight2.vmt", 5.0 ); + + m_hBeams[i]->EntsInit( m_hPhysicsEnt, this ); + m_hBeams[i]->SetEndAttachment( LookupAttachment( attachNames[i] ) ); + m_hBeams[i]->SetBrightness( 255 ); + m_hBeams[i]->SetColor( 255, 255, 255 ); + m_hBeams[i]->SetNoise( 5.5 ); + m_hBeams[i]->SetRenderMode( kRenderTransAdd ); + } + +} + +bool CNPC_Dog::FindPhysicsObject( const char *pPickupName, CBaseEntity *pIgnore ) +{ + CBaseEntity *pEnt = NULL; + CBaseEntity *pNearest = NULL; + float flDist; + IPhysicsObject *pPhysObj = NULL; + float flNearestDist = 99999; + + if ( pPickupName != NULL && strlen( pPickupName ) > 0 ) + { + pEnt = gEntList.FindEntityByName( NULL, pPickupName ); + + if ( m_hUnreachableObjects.Find( pEnt ) == -1 ) + { + m_bHasObject = false; + m_hPhysicsEnt = pEnt; + return true; + } + } + + while ( ( pEnt = gEntList.FindEntityByClassname( pEnt, "prop_physics" ) ) != NULL ) + { + //We don't want this one. + if ( pEnt == pIgnore ) + continue; + + if ( m_hUnreachableObjects.Find( pEnt ) != -1 ) + continue; + + pPhysObj = pEnt->VPhysicsGetObject(); + + if( pPhysObj == NULL ) + continue; + + if ( pPhysObj->GetMass() > DOG_MAX_THROW_MASS ) + continue; + + Vector center = pEnt->WorldSpaceCenter(); + flDist = UTIL_DistApprox2D( GetAbsOrigin(), center ); + + vcollide_t *pCollide = modelinfo->GetVCollide( pEnt->GetModelIndex() ); + + if ( pCollide == NULL ) + continue; + + if ( pPhysObj->GetGameFlags() & FVPHYSICS_PLAYER_HELD ) + continue; + + if ( pPhysObj->IsMoveable() == false ) + continue; + + if ( pEnt->GetCollisionGroup() == COLLISION_GROUP_DEBRIS || + pEnt->GetCollisionGroup() == COLLISION_GROUP_INTERACTIVE_DEBRIS ) + continue; + + if ( center.z > EyePosition().z ) + continue; + + if ( flDist >= flNearestDist ) + continue; + + if ( FVisible( pEnt ) == false ) + continue; + + pNearest = pEnt; + flNearestDist = flDist; + } + + m_bHasObject = false; + m_hPhysicsEnt = pNearest; + + if ( dog_debug.GetBool() == true ) + { + if ( pNearest ) + NDebugOverlay::Box( pNearest->WorldSpaceCenter(), pNearest->CollisionProp()->OBBMins(), pNearest->CollisionProp()->OBBMaxs(), 255, 0, 255, true, 3 ); + } + + if( m_hPhysicsEnt == NULL ) + { + return false; + } + else + { + return true; + } +} + +//----------------------------------------------------------------------------- +// Can me enemy see me? +//----------------------------------------------------------------------------- +bool CNPC_Dog::CanTargetSeeMe( void ) +{ + CBaseEntity *pEntity = m_hThrowTarget; + + if ( pEntity ) + { + if ( pEntity->IsPlayer() == false ) + return true; + + CBasePlayer *pPlayer = dynamic_cast<CBasePlayer*>( pEntity ); + + if ( pPlayer ) + { + if ( m_hPhysicsEnt ) + { + if ( pPlayer->FVisible( m_hPhysicsEnt ) == false ) + return false; + } + + if ( pPlayer->FInViewCone( this ) ) + { + return true; + } + } + } + + return false; +} + + +//--------------------------------------------------------- +//--------------------------------------------------------- +void CNPC_Dog::RunTask( const Task_t *pTask ) +{ + switch( pTask->iTask ) + { + + case TASK_DOG_PICKUP_ITEM: + { + PullObject( false ); + } + break; + + case TASK_DOG_GET_PATH_TO_PHYSOBJ: + { + //Check this cause our object might have been deleted. + if ( m_hPhysicsEnt == NULL ) + FindPhysicsObject( NULL ); + + //And if we still can't find anything, then just go away. + if ( m_hPhysicsEnt == NULL ) + { + TaskFail( "Can't find an object I like!" ); + return; + } + + IPhysicsObject *pPhysicsObject = m_hPhysicsEnt->VPhysicsGetObject(); + + Vector vecGoalPos; + Vector vecDir; + + vecDir = GetLocalOrigin() - m_hPhysicsEnt->WorldSpaceCenter(); + VectorNormalize(vecDir); + vecDir.z = 0; + + if ( m_hPhysicsEnt->GetOwnerEntity() == NULL ) + m_hPhysicsEnt->SetOwnerEntity( this ); + + if ( pPhysicsObject ) + pPhysicsObject->RecheckCollisionFilter(); + + vecGoalPos = m_hPhysicsEnt->WorldSpaceCenter() + (vecDir * DOG_PHYSOBJ_MOVE_TO_DIST ); + + bool bBuiltRoute = false; + + //If I'm near my goal, then just walk to it. + Activity aActivity = ACT_RUN; + + if ( ( vecGoalPos - GetLocalOrigin() ).Length() <= 128 ) + aActivity = ACT_WALK; + + bBuiltRoute = GetNavigator()->SetGoal( AI_NavGoal_t( vecGoalPos, aActivity ), AIN_NO_PATH_TASK_FAIL ); + + if ( bBuiltRoute == true ) + TaskComplete(); + else + { + m_flTimeToCatch = gpGlobals->curtime + 0.1; + m_flNextRouteTime = gpGlobals->curtime + 0.3; + m_flNextSwat = gpGlobals->curtime + 0.1; + + if ( m_hUnreachableObjects.Find( m_hPhysicsEnt ) == -1 ) + m_hUnreachableObjects.AddToTail( m_hPhysicsEnt ); + + m_hPhysicsEnt = NULL; + + GetNavigator()->ClearGoal(); + } + } + break; + + case TASK_WAIT: + { + if ( IsWaitFinished() ) + { + TaskComplete(); + } + + if ( m_hPhysicsEnt ) + { + if ( m_bHasObject == false ) + { + GetMotor()->SetIdealYawToTarget( m_hPhysicsEnt->GetAbsOrigin() ); + GetMotor()->UpdateYaw(); + } + } + + break; + } + + case TASK_DOG_LAUNCH_ITEM: + if( IsActivityFinished() ) + { + if ( m_hPhysicsEnt ) + { + m_hPhysicsEnt->SetOwnerEntity( NULL ); + } + + TaskComplete(); + } + break; + + case TASK_DOG_WAIT_FOR_TARGET_TO_FACE: + { + if ( CanTargetSeeMe() ) + TaskComplete(); + } + break; + + case TASK_WAIT_FOR_MOVEMENT: + { + if ( GetState() == NPC_STATE_SCRIPT || IsInAScript() ) + { + BaseClass::RunTask( pTask ); + return; + } + + if ( m_hPhysicsEnt != NULL ) + { + IPhysicsObject *pPhysObj = m_hPhysicsEnt->VPhysicsGetObject(); + + if ( !pPhysObj ) + { + Warning( "npc_dog TASK_WAIT_FOR_MOVEMENT with NULL m_hPhysicsEnt->VPhysicsGetObject\n" ); + } + + if ( pPhysObj && pPhysObj->GetGameFlags() & FVPHYSICS_PLAYER_HELD ) + TaskFail( "Player picked it up!" ); + + //If the object is moving then my old goal might not be valid + //cancel the schedule and make it restart again in a bit. + if ( pPhysObj && pPhysObj->IsAsleep() == false && GetNavigator()->IsGoalActive() == false ) + { + Vector vecGoalPos; + Vector vecDir; + + vecDir = GetLocalOrigin() - m_hPhysicsEnt->WorldSpaceCenter(); + VectorNormalize(vecDir); + vecDir.z = 0; + + vecGoalPos = m_hPhysicsEnt->WorldSpaceCenter() + (vecDir * DOG_PHYSOBJ_MOVE_TO_DIST ); + + GetNavigator()->ClearGoal(); + + float flDistance = (vecGoalPos - GetLocalOrigin()).Length(); + + //If I'm near my goal, then just walk to it. + Activity aActivity = ACT_RUN; + + if ( ( vecGoalPos - GetLocalOrigin() ).Length() <= 128 ) + aActivity = ACT_WALK; + + GetNavigator()->SetGoal( AI_NavGoal_t( vecGoalPos, aActivity ), AIN_NO_PATH_TASK_FAIL ); + + if ( flDistance <= DOG_PHYSOBJ_MOVE_TO_DIST ) + { + TaskComplete(); + GetNavigator()->StopMoving(); + } + } + } + + BaseClass::RunTask( pTask ); + } + break; + + case TASK_DOG_WAIT_FOR_OBJECT: + { + if ( m_hPhysicsEnt != NULL ) + { + if ( FVisible( m_hPhysicsEnt ) == false ) + { + m_flTimeToCatch = 0.0f; + ClearBeams(); + TaskFail( "Lost sight of the object!" ); + m_hPhysicsEnt->SetOwnerEntity( NULL ); + return; + } + + m_hPhysicsEnt->SetOwnerEntity( this ); + + Vector vForward; + AngleVectors( GetAbsAngles(), &vForward ); + + + Vector vGunPos; + GetAttachment( m_iPhysGunAttachment, vGunPos ); + + Vector vToObject = m_hPhysicsEnt->WorldSpaceCenter() - vGunPos; + float flDistance = vToObject.Length(); + + VectorNormalize( vToObject ); + + SetAim( m_hPhysicsEnt->WorldSpaceCenter() - GetAbsOrigin() ); + + CBasePlayer *pPlayer = AI_GetSinglePlayer(); + + float flDistanceToPlayer = flDistance; + + if ( pPlayer ) + { + flDistanceToPlayer = (pPlayer->GetAbsOrigin() - m_hPhysicsEnt->WorldSpaceCenter()).Length(); + } + + IPhysicsObject *pPhysObj = m_hPhysicsEnt->VPhysicsGetObject(); + if ( !pPhysObj ) + { + Warning( "npc_dog: TASK_DOG_WAIT_FOR_OBJECT with m_hPhysicsEnt->VPhysicsGetObject == NULL\n" ); + } + + if ( pPhysObj && !( pPhysObj->GetGameFlags() & FVPHYSICS_PLAYER_HELD ) && flDistanceToPlayer > ( flDistance * 2 ) ) + { + if ( m_flTimeToPull <= gpGlobals->curtime ) + { + Vector vCurrentVel; + float flCurrentVel; + AngularImpulse vCurrentAI; + + pPhysObj->GetVelocity( &vCurrentVel, &vCurrentAI ); + + flCurrentVel = vCurrentVel.Length(); + VectorNormalize( vCurrentVel ); + + if ( pPhysObj && flDistance <= DOG_PULL_DISTANCE ) + { + Vector vDir = ( vGunPos - m_hPhysicsEnt->WorldSpaceCenter() ); + + VectorNormalize( vDir ); + + vCurrentVel = vCurrentVel * ( flCurrentVel * DOG_PULL_VELOCITY_MOD ); + + vCurrentAI = vCurrentAI * DOG_PULL_ANGULARIMP_MOD; + pPhysObj->SetVelocity( &vCurrentVel, &vCurrentAI ); + + vDir = vDir * flDistance * DOG_PULL_TO_GUN_VEL_MOD; + + Vector vAngle( 0, 0, 0 ); + pPhysObj->AddVelocity( &vDir, &vAngle ); + + CreateBeams(); + } + + float flDot = DotProduct( vCurrentVel, vForward ); + + if ( flDistance >= DOG_PULL_DISTANCE && flDistance <= ( DOG_PULL_DISTANCE * 2 ) && flDot > -0.3 ) + { + if ( pPhysObj->IsAsleep() == false && !( pPhysObj->GetGameFlags() & FVPHYSICS_PLAYER_HELD ) ) + { + Vector vecGoalPos; + Vector vecDir; + + vecDir = GetLocalOrigin() - m_hPhysicsEnt->WorldSpaceCenter(); + VectorNormalize(vecDir); + vecDir.z = 0; + + vecGoalPos = m_hPhysicsEnt->WorldSpaceCenter() + (vecDir * DOG_PHYSOBJ_MOVE_TO_DIST ); + + GetNavigator()->ClearGoal(); + + //If I'm near my goal, then just walk to it. + Activity aActivity = ACT_RUN; + + if ( ( vecGoalPos - GetLocalOrigin() ).Length() <= 128 ) + aActivity = ACT_WALK; + + GetNavigator()->SetGoal( AI_NavGoal_t( vecGoalPos, aActivity ), AIN_NO_PATH_TASK_FAIL ); + } + } + } + } + + + float flDirDot = DotProduct( vToObject, vForward ); + + if ( flDirDot < 0.2 ) + { + GetMotor()->SetIdealYawToTarget( m_hPhysicsEnt->GetAbsOrigin() ); + GetMotor()->UpdateYaw(); + } + + if ( m_flTimeToCatch < gpGlobals->curtime && m_bDoWaitforObjectBehavior == false ) + { + m_hPhysicsEnt->SetOwnerEntity( NULL ); + m_flTimeToCatch = 0.0f; + ClearBeams(); + TaskFail( "Done waiting!" ); + } + else if ( pPhysObj && ( flDistance <= DOG_CATCH_DISTANCE && !( pPhysObj->GetGameFlags() & FVPHYSICS_PLAYER_HELD ) ) ) + { + AngularImpulse vZero( 0, 0, 0 ); + pPhysObj->SetVelocity( &vec3_origin, &vZero ); + + GetNavigator()->StopMoving(); + + //Fire Output! + m_OnCatch.FireOutput( this, this ); + m_bHasObject = true; + ClearBeams(); + TaskComplete(); + } + } + else + { + GetNavigator()->StopMoving(); + + ClearBeams(); + TaskFail("No Physics Object!"); + } + + } + break; + + case TASK_DOG_CATCH_OBJECT: + if( IsActivityFinished() ) + { + m_flTimeToCatch = 0.0f; + TaskComplete(); + } + break; + default: + BaseClass::RunTask( pTask ); + break; + } +} + +void CNPC_Dog::SetupThrowTarget( void ) +{ + if ( m_hThrowTarget == NULL ) + { + m_hThrowTarget = AI_GetSinglePlayer(); + } + + SetTarget( m_hThrowTarget ); +} + +//--------------------------------------------------------- +//--------------------------------------------------------- +void CNPC_Dog::StartTask( const Task_t *pTask ) +{ + switch( pTask->iTask ) + { + + case TASK_DOG_SETUP_THROW_TARGET: + { + SetupThrowTarget(); + TaskComplete(); + } + break; + case TASK_DOG_GET_PATH_TO_PHYSOBJ: + { + FindPhysicsObject( STRING( m_sObjectName ) ); + + if ( m_hPhysicsEnt == NULL ) + { + FindPhysicsObject( NULL ); + return; + } + + IPhysicsObject *pPhysicsObject = m_hPhysicsEnt->VPhysicsGetObject(); + + Vector vecGoalPos; + Vector vecDir; + + vecDir = GetLocalOrigin() - m_hPhysicsEnt->WorldSpaceCenter(); + VectorNormalize(vecDir); + vecDir.z = 0; + + if ( m_hPhysicsEnt->GetOwnerEntity() == NULL ) + m_hPhysicsEnt->SetOwnerEntity( this ); + + if ( pPhysicsObject ) + pPhysicsObject->RecheckCollisionFilter(); + + vecGoalPos = m_hPhysicsEnt->WorldSpaceCenter() + (vecDir * DOG_PHYSOBJ_MOVE_TO_DIST ); + + //If I'm near my goal, then just walk to it. + Activity aActivity = ACT_RUN; + + if ( ( vecGoalPos - GetLocalOrigin() ).Length() <= 128 ) + aActivity = ACT_WALK; + + if ( GetNavigator()->SetGoal( AI_NavGoal_t( vecGoalPos, aActivity ), AIN_NO_PATH_TASK_FAIL ) == false ) + { + if ( m_hUnreachableObjects.Find( m_hPhysicsEnt ) == -1 ) + m_hUnreachableObjects.AddToTail( m_hPhysicsEnt ); + + FindPhysicsObject( NULL, m_hPhysicsEnt ); + + m_flTimeToCatch = gpGlobals->curtime + 0.1; + m_flNextRouteTime = gpGlobals->curtime + 0.3; + m_flNextSwat = gpGlobals->curtime + 0.1; + + GetNavigator()->ClearGoal(); + } + else + { + TaskComplete(); + } + } + break; + + case TASK_DOG_FACE_OBJECT: + { + if( m_hPhysicsEnt == NULL ) + { + // Physics Object is gone! Probably was an explosive + // or something else broke it. + TaskFail("Physics ent NULL"); + return; + } + + Vector vecDir; + + vecDir = m_hPhysicsEnt->WorldSpaceCenter() - GetLocalOrigin(); + VectorNormalize(vecDir); + + GetMotor()->SetIdealYaw( UTIL_VecToYaw( vecDir ) ); + TaskComplete(); + } + break; + + case TASK_DOG_PICKUP_ITEM: + { + if( m_hPhysicsEnt == NULL ) + { + // Physics Object is gone! Probably was an explosive + // or something else broke it. + TaskFail("Physics ent NULL"); + return; + } + else + { + SetIdealActivity( (Activity)ACT_DOG_PICKUP ); + } + } + + break; + + case TASK_DOG_LAUNCH_ITEM: + { + if( m_hPhysicsEnt == NULL ) + { + // Physics Object is gone! Probably was an explosive + // or something else broke it. + TaskFail("Physics ent NULL"); + return; + } + else + { + if ( m_hPhysicsEnt == NULL || m_bHasObject == false ) + { + TaskFail( "Don't have the item!" ); + return; + } + + SetIdealActivity( (Activity)ACT_DOG_THROW ); + } + } + + break; + + case TASK_DOG_WAIT_FOR_TARGET_TO_FACE: + { + if ( CanTargetSeeMe() ) + TaskComplete(); + } + break; + + case TASK_DOG_WAIT_FOR_OBJECT: + { + SetIdealActivity( (Activity)ACT_DOG_WAITING ); + } + break; + + case TASK_DOG_CATCH_OBJECT: + { + SetIdealActivity( (Activity)ACT_DOG_CATCH ); + } + break; + + case TASK_DOG_DELAY_SWAT: + m_flNextSwat = gpGlobals->curtime + pTask->flTaskData; + + if ( m_hThrowTarget == NULL ) + m_hThrowTarget = AI_GetSinglePlayer(); + + TaskComplete(); + break; + + default: + BaseClass::StartTask( pTask ); + } +} + +void CNPC_Dog::InputTurnBoneFollowersOff( inputdata_t &inputdata ) +{ + if ( m_bBoneFollowersActive ) + { + m_bBoneFollowersActive = false; + m_BoneFollowerManager.DestroyBoneFollowers(); + } + +} + +void CNPC_Dog::InputTurnBoneFollowersOn( inputdata_t &inputdata ) +{ + if ( !m_bBoneFollowersActive ) + { + m_bBoneFollowersActive = true; + m_BoneFollowerManager.InitBoneFollowers( this, ARRAYSIZE(pFollowerBoneNames), pFollowerBoneNames ); + } +} + +AI_BEGIN_CUSTOM_NPC( npc_dog, CNPC_Dog ) + + DECLARE_USES_SCHEDULE_PROVIDER( CAI_FollowBehavior ) + + DECLARE_ACTIVITY( ACT_DOG_THROW ) + DECLARE_ACTIVITY( ACT_DOG_PICKUP ) + DECLARE_ACTIVITY( ACT_DOG_WAITING ) + DECLARE_ACTIVITY( ACT_DOG_CATCH ) + + DECLARE_CONDITION( COND_DOG_LOST_PHYSICS_ENTITY ) + + DECLARE_TASK( TASK_DOG_DELAY_SWAT ) + DECLARE_TASK( TASK_DOG_GET_PATH_TO_PHYSOBJ ) + DECLARE_TASK( TASK_DOG_LAUNCH_ITEM ) + DECLARE_TASK( TASK_DOG_PICKUP_ITEM ) + DECLARE_TASK( TASK_DOG_FACE_OBJECT ) + DECLARE_TASK( TASK_DOG_WAIT_FOR_OBJECT ) + DECLARE_TASK( TASK_DOG_CATCH_OBJECT ) + + DECLARE_TASK( TASK_DOG_WAIT_FOR_TARGET_TO_FACE ) + DECLARE_TASK( TASK_DOG_SETUP_THROW_TARGET ) + + DECLARE_ANIMEVENT( AE_DOG_THROW ) + DECLARE_ANIMEVENT( AE_DOG_PICKUP ) + DECLARE_ANIMEVENT( AE_DOG_CATCH ) + DECLARE_ANIMEVENT( AE_DOG_PICKUP_NOEFFECT ) + + + DEFINE_SCHEDULE + ( + SCHED_DOG_FIND_OBJECT, + + " Tasks" + " TASK_DOG_DELAY_SWAT 3" + " TASK_DOG_GET_PATH_TO_PHYSOBJ 0" + " TASK_RUN_PATH 0" + " TASK_WAIT_FOR_MOVEMENT 0" + " TASK_DOG_FACE_OBJECT 0" + " TASK_FACE_IDEAL 0" + " TASK_DOG_PICKUP_ITEM 0" + " TASK_DOG_SETUP_THROW_TARGET 0" + " TASK_FACE_TARGET 0.5" + " TASK_DOG_WAIT_FOR_TARGET_TO_FACE 0" + " TASK_DOG_LAUNCH_ITEM 0" + "" + " Interrupts" + " COND_DOG_LOST_PHYSICS_ENTITY" + ) + + DEFINE_SCHEDULE + ( + SCHED_DOG_WAIT_THROW_OBJECT, + " Tasks" + " TASK_DOG_SETUP_THROW_TARGET 0" + " TASK_FACE_TARGET 0.5" + " TASK_DOG_WAIT_FOR_TARGET_TO_FACE 0" + " TASK_DOG_LAUNCH_ITEM 0" + "" + " Interrupts" + " COND_DOG_LOST_PHYSICS_ENTITY" + ) + + DEFINE_SCHEDULE + ( + SCHED_DOG_CATCH_OBJECT, + + " Tasks" + " TASK_DOG_WAIT_FOR_OBJECT 0" + " TASK_DOG_CATCH_OBJECT 0" + " TASK_FACE_PLAYER 0.5" + " TASK_DOG_WAIT_FOR_TARGET_TO_FACE 0" + " TASK_DOG_LAUNCH_ITEM 0" + " TASK_SET_FAIL_SCHEDULE SCHEDULE:SCHED_IDLE_STAND" + "" + " Interrupts" + " COND_DOG_LOST_PHYSICS_ENTITY" + ) + +AI_END_CUSTOM_NPC() |