⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 npc_barnacle.cpp

📁 hl2 source code. Do not use it illegal.
💻 CPP
📖 第 1 页 / 共 3 页
字号:
	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 + -