|
|
//========= 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()
|