📄 npc_barnacle.cpp
字号:
float flDistanceToGo = GetAbsOrigin().z - vecSwallowPos.z;
if ( flDistanceToGo <= 0 )
{
// He's dead jim
m_bSwallowingPrey = false;
m_hTongueTip->SetAbsVelocity( vec3_origin );
m_flDigestFinish = gpGlobals->curtime + 10.0;
}
}
//-----------------------------------------------------------------------------
// Purpose: Remove the fake ragdoll and bring the actual enemy back in view
//-----------------------------------------------------------------------------
void CNPC_Barnacle::RemoveRagdoll( bool bDestroyRagdoll )
{
// Destroy the tongue tip constraint
if ( m_pConstraint )
{
physenv->DestroyConstraint( m_pConstraint );
m_pConstraint = NULL;
}
// Remove the ragdoll
if ( m_hRagdoll )
{
// Only destroy the ragdoll if told to. We might be just dropping
// the ragdoll because the target was killed on the way up.
m_hRagdoll->SetDamageEntity( NULL );
DetachAttachedRagdoll( m_hRagdoll );
if ( bDestroyRagdoll )
{
UTIL_Remove( m_hRagdoll );
}
m_hRagdoll = NULL;
// Reduce the spring constant while we lower
m_hTongueTip->m_pSpring->SetSpringConstant( BARNACLE_TONGUE_SPRING_CONSTANT_LOWERING );
// Unhide the enemy
if ( GetEnemy() )
{
GetEnemy()->m_fEffects &= ~EF_NODRAW;
GetEnemy()->RemoveSolidFlags( FSOLID_NOT_SOLID );
GetEnemy()->Relink();
}
}
}
//-----------------------------------------------------------------------------
// Purpose: For some reason (he was killed, etc) we lost the prey we were dragging towards our mouth.
//-----------------------------------------------------------------------------
void CNPC_Barnacle::LostPrey( bool bRemoveRagdoll )
{
if ( GetEnemy() )
{
CBaseCombatCharacter *pVictim = GetEnemyCombatCharacterPointer();
if ( pVictim )
{
pVictim->HandleInteraction( g_interactionBarnacleVictimReleased, NULL, this );
pVictim->RemoveFlag( FL_ONGROUND );
}
}
RemoveRagdoll( bRemoveRagdoll );
m_bLiftingPrey = false;
m_bSwallowingPrey = false;
SetEnemy( NULL );
// Remove our tongue's shadow object, in case we just finished swallowing something
IPhysicsObject *pPhysicsObject = m_hTongueTip->VPhysicsGetObject();
if ( pPhysicsObject && pPhysicsObject->GetShadowController() )
{
Vector vecCenter = WorldSpaceCenter();
m_hTongueTip->Teleport( &vecCenter, NULL, &vec3_origin );
// Reduce the spring constant while we lower
m_hTongueTip->m_pSpring->SetSpringConstant( BARNACLE_TONGUE_SPRING_CONSTANT_LOWERING );
// Start colliding with the world again
pPhysicsObject->RemoveShadowController();
m_hTongueTip->SetMoveType( MOVETYPE_VPHYSICS );
pPhysicsObject->EnableMotion( true );
pPhysicsObject->EnableGravity( true );
pPhysicsObject->RecheckCollisionFilter();
}
}
//-----------------------------------------------------------------------------
// Purpose: Update the positions of the tongue points
//-----------------------------------------------------------------------------
void CNPC_Barnacle::UpdateTongue( void )
{
// Set the spring's length to that of the tongue's extension
m_hTongueTip->m_pSpring->SetSpringLength( m_flAltitude );
// Update the tip's position
m_vecTip = m_hTongueTip->GetAbsOrigin();
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CNPC_Barnacle::Event_Killed( const CTakeDamageInfo &info )
{
AddSolidFlags( FSOLID_NOT_SOLID );
m_takedamage = DAMAGE_NO;
m_lifeState = LIFE_DYING;
Relink();
// Are we lifting prey?
if ( GetEnemy() )
{
// Cleanup
LostPrey( true );
}
else if ( m_bSwallowingPrey && m_hRagdoll )
{
// We're swallowing a body. Make it stick inside us.
m_hTongueTip->SetAbsVelocity( vec3_origin );
m_hRagdoll->StopFollowingEntity();
m_hRagdoll->SetMoveType( MOVETYPE_VPHYSICS );
m_hRagdoll->SetAbsOrigin( m_hTongueTip->GetAbsOrigin() );
m_hRagdoll->RemoveSolidFlags( FSOLID_NOT_SOLID );
m_hRagdoll->SetCollisionGroup( COLLISION_GROUP_DEBRIS );
m_hRagdoll->RecheckCollisionFilter();
m_hRagdoll->Relink();
}
else
{
// Destroy the ragdoll->tongue tip constraint
if ( m_pConstraint )
{
physenv->DestroyConstraint( m_pConstraint );
m_pConstraint = NULL;
}
// Remove our tongue pieces
UTIL_Remove( m_hTongueTip );
LostPrey( true );
}
UTIL_Remove( m_hTongueRoot );
CGib::SpawnRandomGibs( this, 4, GIB_HUMAN );
EmitSound( "NPC_Barnacle.Die" );
SetActivity( ACT_DIESIMPLE );
StudioFrameAdvance();
SetNextThink( gpGlobals->curtime + 0.1f );
SetThink ( WaitTillDead );
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CNPC_Barnacle::WaitTillDead ( void )
{
SetNextThink( gpGlobals->curtime + 0.1f );
StudioFrameAdvance();
DispatchAnimEvents ( this );
if ( IsActivityFinished() )
{
// death anim finished.
StopAnimation();
SetThink ( NULL );
m_lifeState = LIFE_DEAD;
}
}
//=========================================================
// Precache - precaches all resources this monster needs
//=========================================================
void CNPC_Barnacle::Precache()
{
engine->PrecacheModel("models/barnacle.mdl");
BaseClass::Precache();
}
//=========================================================
// TongueTouchEnt - does a trace along the barnacle's tongue
// to see if any entity is touching it. Also stores the length
// of the trace in the int pointer provided.
//=========================================================
#define BARNACLE_CHECK_SPACING 8
CBaseEntity *CNPC_Barnacle::TongueTouchEnt ( float *pflLength )
{
trace_t tr;
float length;
// trace once to hit architecture and see if the tongue needs to change position.
AI_TraceLine ( GetAbsOrigin(), GetAbsOrigin() - Vector ( 0 , 0 , 2048 ),
MASK_SOLID_BRUSHONLY, this, COLLISION_GROUP_NONE, &tr );
length = fabs( GetAbsOrigin().z - tr.endpos.z );
// Pull it up a tad
length = max(8, length - 16);
if ( pflLength )
{
*pflLength = length;
}
Vector delta = Vector( BARNACLE_CHECK_SPACING, BARNACLE_CHECK_SPACING, 0 );
Vector mins = GetAbsOrigin() - delta;
Vector maxs = GetAbsOrigin() + delta;
maxs.z = GetAbsOrigin().z;
mins.z -= length;
CBaseEntity *pList[10];
int count = UTIL_EntitiesInBox( pList, 10, mins, maxs, (FL_CLIENT|FL_NPC) );
if ( count )
{
for ( int i = 0; i < count; i++ )
{
CBaseCombatCharacter *pVictim = ToBaseCombatCharacter( pList[ i ] );
// only clients and monsters
if ( pList[i] != this &&
IRelationType( pList[i] ) == D_HT &&
pVictim->m_lifeState != LIFE_DEAD &&
pVictim->m_lifeState != LIFE_DYING &&
!( pVictim->GetFlags() & FL_NOTARGET ) )
{
return pList[i];
}
}
}
return NULL;
}
//===============================================================================================================================
// BARNACLE TONGUE TIP
//===============================================================================================================================
// Crane tip
LINK_ENTITY_TO_CLASS( npc_barnacle_tongue_tip, CBarnacleTongueTip );
BEGIN_DATADESC( CBarnacleTongueTip )
DEFINE_PHYSPTR( CBarnacleTongueTip, m_pSpring ),
END_DATADESC()
//-----------------------------------------------------------------------------
// Purpose: To by usable by vphysics, this needs to have a phys model.
//-----------------------------------------------------------------------------
void CBarnacleTongueTip::Spawn( void )
{
Precache();
SetModel( "models/props_junk/rock001a.mdl" );
m_fEffects |= EF_NODRAW;
// We don't want this to be solid, because we don't want it to collide with the barnacle.
SetSolid( SOLID_VPHYSICS );
AddSolidFlags( FSOLID_NOT_SOLID );
BaseClass::Spawn();
m_pSpring = NULL;
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CBarnacleTongueTip::Precache( void )
{
PrecacheModel( "models/props_junk/rock001a.mdl" );
BaseClass::Precache();
}
//-----------------------------------------------------------------------------
// Purpose: Activate/create the spring
//-----------------------------------------------------------------------------
bool CBarnacleTongueTip::CreateSpring( CBaseAnimating *pTongueRoot )
{
IPhysicsObject *pPhysObject = VPhysicsGetObject();
IPhysicsObject *pRootPhysObject = pTongueRoot->VPhysicsGetObject();
Assert( pRootPhysObject );
Assert( pPhysObject );
// Root has huge mass, tip has little
pRootPhysObject->SetMass( 1e6 );
pPhysObject->SetMass( 100 );
float damping = 3;
pPhysObject->SetDamping( &damping, &damping );
springparams_t spring;
spring.constant = BARNACLE_TONGUE_SPRING_CONSTANT_HANGING;
spring.damping = BARNACLE_TONGUE_SPRING_DAMPING;
spring.naturalLength = (GetAbsOrigin() - pTongueRoot->GetAbsOrigin()).Length();
spring.relativeDamping = 10;
spring.startPosition = GetAbsOrigin();
spring.endPosition = pTongueRoot->GetAbsOrigin();
spring.useLocalPositions = false;
m_pSpring = physenv->CreateSpring( pPhysObject, pRootPhysObject, &spring );
return true;
}
//-----------------------------------------------------------------------------
// Purpose: Create a barnacle tongue tip at the bottom of the tongue
//-----------------------------------------------------------------------------
CBarnacleTongueTip *CBarnacleTongueTip::CreateTongueTip( CBaseAnimating *pTongueRoot, const Vector &vecOrigin, const QAngle &vecAngles )
{
CBarnacleTongueTip *pTip = (CBarnacleTongueTip *)CBaseEntity::Create( "npc_barnacle_tongue_tip", vecOrigin, vecAngles );
if ( !pTip )
return NULL;
pTip->VPhysicsInitNormal( pTip->GetSolid(), pTip->GetSolidFlags(), false );
if ( !pTip->CreateSpring( pTongueRoot ) )
return NULL;
// Don't collide with the world
IPhysicsObject *pTipPhys = pTip->VPhysicsGetObject();
// turn off all floating / fluid simulation
pTipPhys->SetCallbackFlags( pTipPhys->GetCallbackFlags() & (~CALLBACK_DO_FLUID_SIMULATION) );
return pTip;
}
//-----------------------------------------------------------------------------
// Purpose: Create a barnacle tongue tip at the root (i.e. inside the barnacle)
//-----------------------------------------------------------------------------
CBarnacleTongueTip *CBarnacleTongueTip::CreateTongueRoot( const Vector &vecOrigin, const QAngle &vecAngles )
{
CBarnacleTongueTip *pTip = (CBarnacleTongueTip *)CBaseEntity::Create( "npc_barnacle_tongue_tip", vecOrigin, vecAngles );
if ( !pTip )
return NULL;
pTip->AddSolidFlags( FSOLID_NOT_SOLID );
// Disable movement on the root, we'll move this thing manually.
pTip->VPhysicsInitShadow( false, false );
pTip->SetMoveType( MOVETYPE_NONE );
return pTip;
}
//-----------------------------------------------------------------------------
//
// Schedules
//
//-----------------------------------------------------------------------------
AI_BEGIN_CUSTOM_NPC( npc_barnacle, CNPC_Barnacle )
// Register our interactions
DECLARE_INTERACTION( g_interactionBarnacleVictimDangle )
DECLARE_INTERACTION( g_interactionBarnacleVictimReleased )
DECLARE_INTERACTION( g_interactionBarnacleVictimGrab )
// Conditions
// Tasks
// Activities
DECLARE_ACTIVITY( ACT_BARNACLE_SLURP ) // Pulling the tongue up with prey on the end
DECLARE_ACTIVITY( ACT_BARNACLE_BITE_HUMAN ) // Biting the head of a humanoid
DECLARE_ACTIVITY( ACT_BARNACLE_CHEW_HUMAN ) // Slowly swallowing the humanoid
DECLARE_ACTIVITY( ACT_BARNACLE_BARF_HUMAN ) // Spitting out human legs & gibs
DECLARE_ACTIVITY( ACT_BARNACLE_TONGUE_WRAP ) // Wrapping the tongue around a target
// Schedules
AI_END_CUSTOM_NPC()
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -