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

📄 npc_barnacle.cpp

📁 hl2 source code. Do not use it illegal.
💻 CPP
📖 第 1 页 / 共 3 页
字号:
	// NDebugOverlay::Box( GetAbsOrigin() - Vector( 0, 0, m_flAltitude ), Vector( -2, -2, -2 ), Vector( 2, 2, 2 ), 255,255,255, 0, 0.1 );

	StudioFrameAdvance();
	DispatchAnimEvents( this );
}

//-----------------------------------------------------------------------------
// Purpose: Lift the prety stuck to our tongue up towards our mouth
//-----------------------------------------------------------------------------
void CNPC_Barnacle::LiftPrey( void )
{
	CBaseCombatCharacter *pVictim = GetEnemyCombatCharacterPointer();
	Assert( pVictim );

	// Drop the prey if it's been obscured by something
	trace_t tr;
	AI_TraceLine( GetAbsOrigin(), pVictim->GetAbsOrigin(), MASK_SOLID, this, COLLISION_GROUP_NONE, &tr );
	if ( tr.fraction < 1.0 && tr.m_pEnt != pVictim && tr.m_pEnt != m_hRagdoll )
	{
		LostPrey( true );
		return;
	}

	// We're still pulling the prey into position. Get the current position of the victim.
	Vector vecVictimPos = pVictim->GetAbsOrigin();
	Vector vecCheckPos = vecVictimPos;
	if ( pVictim->IsPlayer() )
	{
		// Use different detection for the player, so it bites his head nicely
		vecCheckPos.z = pVictim->EyePosition().z;
	}
	else if ( m_hRagdoll )
	{
		// Get the distance to the bone we've grabbed
		if ( m_hRagdoll )
		{
			QAngle vecBoneAngles;
			m_hRagdoll->GetBonePosition( m_iGrabbedBoneIndex, vecCheckPos, vecBoneAngles );
		}
		else
		{
			vecCheckPos.z = pVictim->GetAbsOrigin().z;
		}
	}

	//NDebugOverlay::Box( vecCheckPos, -Vector(10,10,10), Vector(10,10,10), 255,255,255, 0, 0.1 );

	// Height from the barnacle's origin to the point at which it bites
	float flBiteZOffset = 60.0;

	// Play a scream when we're almost within bite range
	if ( !m_bPlayedPullSound && m_flAltitude < (flBiteZOffset + 100) )
	{
		EmitSound( "NPC_Barnacle.Scream" );
		m_bPlayedPullSound = true;
	}

	// Figure out when the prey has reached our bite range
	if ( m_flAltitude < flBiteZOffset )
	{
		// If we've got a ragdoll, wait until the bone is down below the mouth.
		if ( m_hRagdoll )
		{
			// Stop sucking while we wait for the ragdoll to settle
			SetActivity( ACT_IDLE );

			Vector vecVelocity;
			AngularImpulse angVel;
			float flDelta = 4.0;

			// Only bite if the target bone is in the right position.
			Vector vecBitePoint = GetAbsOrigin();
			vecBitePoint.z -= flBiteZOffset;
			//NDebugOverlay::Box( vecBitePoint, -Vector(10,10,10), Vector(10,10,10), 0,255,0, 0, 0.1 );
			if ( (vecBitePoint.x - vecCheckPos.x) > flDelta || (vecBitePoint.y - vecCheckPos.y) > flDelta )
				return;
			// Right height?
			if ( (vecBitePoint.z - vecCheckPos.z) > flDelta )
			{
				// Slowly raise / lower the target into the right position
				if ( vecBitePoint.z > vecCheckPos.z )
				{
					// Pull the victim towards the mouth
					m_flAltitude -= 1;
					vecVictimPos.z += 1;
				}
				else
				{
					// We pulled 'em up too far, so lower them a little
					m_flAltitude += 1;
					vecVictimPos.z -= 1;
				}
				UTIL_SetOrigin ( GetEnemy(), vecVictimPos );
				return;
			}

			// Get the velocity of the bone we've grabbed, and only bite when it's not moving much
			studiohdr_t *pStudioHdr = m_hRagdoll->GetModelPtr();
			mstudiobone_t *pBone = pStudioHdr->pBone( m_iGrabbedBoneIndex );
			int iBoneIndex = pBone->physicsbone;
			ragdoll_t *pRagdoll = m_hRagdoll->GetRagdoll();
			IPhysicsObject *pRagdollPhys = pRagdoll->list[iBoneIndex].pObject;
			pRagdollPhys->GetVelocity( &vecVelocity, &angVel );
			if ( vecVelocity.Length() > 5 )
				return;
		}

		m_bLiftingPrey = false;

		// Start the bite animation. The anim event in it will finish the job.
		SetActivity( (Activity)ACT_BARNACLE_BITE_HUMAN );
	}
	else
	{
		// Pull the victim towards the mouth
		float flPull = fabs(sin( gpGlobals->curtime * 5 ));
		flPull *= BARNACLE_PULL_SPEED;
		m_flAltitude -= flPull;
		vecVictimPos.z += flPull;

		UTIL_SetOrigin ( GetEnemy(), vecVictimPos );

		// Apply forces to the attached ragdoll based upon the animations of the enemy, if the enemy is still alive.
		if ( m_hRagdoll && GetEnemy() && GetEnemy()->IsAlive() )
		{
			CBaseAnimating *pAnimating = dynamic_cast<CBaseAnimating*>( GetEnemy() );

			// Get the current bone matrix
			/*
			Vector pos[MAXSTUDIOBONES];
			Quaternion q[MAXSTUDIOBONES];
			matrix3x4_t pBoneToWorld[MAXSTUDIOBONES];
			CalcPoseSingle( pStudioHdr, pos, q, pAnimating->GetSequence(), pAnimating->m_flCycle, pAnimating->GetPoseParameterArray(), BONE_USED_BY_ANYTHING );
			Studio_BuildMatrices( pStudioHdr, vec3_angle, vec3_origin, pos, q, -1, pBoneToWorld, BONE_USED_BY_ANYTHING );


			// Apply the forces to the ragdoll
			RagdollApplyAnimationAsVelocity( *(m_hRagdoll->GetRagdoll()), pBoneToWorld );
			*/

			// Get the current bone matrix
			matrix3x4_t pBoneToWorld[MAXSTUDIOBONES];
			pAnimating->SetupBones( pBoneToWorld, BONE_USED_BY_ANYTHING );

			// Apply the forces to the ragdoll
			RagdollApplyAnimationAsVelocity( *(m_hRagdoll->GetRagdoll()), m_pRagdollBones, pBoneToWorld, 0.2 );

			// Store off the current bone matrix for next time
			pAnimating->SetupBones( m_pRagdollBones, BONE_USED_BY_ANYTHING );
		}
	}
}

//-----------------------------------------------------------------------------
// Purpose: Grab the specified target with our tongue
//-----------------------------------------------------------------------------
void CNPC_Barnacle::AttachTongueToTarget( CBaseEntity *pTouchEnt, Vector vecGrabPos )
{
	if ( RandomFloat(0,1) > 0.5 )
	{
		EmitSound( "NPC_Barnacle.PullPant" );
	}
	else
	{
		EmitSound( "NPC_Barnacle.TongueStretch" );
	}

	SetActivity( (Activity)ACT_BARNACLE_SLURP );

	SetEnemy( pTouchEnt );

	Vector origin = GetAbsOrigin();
	origin.z = pTouchEnt->GetAbsOrigin().z;
	pTouchEnt->SetLocalOrigin( origin );

	m_bLiftingPrey = true;// indicate that we should be lifting prey.
	m_flAltitude = (GetAbsOrigin().z - vecGrabPos.z);
	m_bPlayedPullSound  = false;

	CBaseAnimating *pAnimating = dynamic_cast<CBaseAnimating*>(pTouchEnt);
	if ( pAnimating )
	{
		if ( pTouchEnt->IsPlayer() )
		{
			// The player doesn't ragdoll, so just grab him and pull him up manually
			IPhysicsObject *pPlayerPhys = pTouchEnt->VPhysicsGetObject();
			IPhysicsObject *pTonguePhys = m_hTongueTip->VPhysicsGetObject();

			Vector vecGrabPos = pTouchEnt->EyePosition();
			m_hTongueTip->Teleport( &vecGrabPos, NULL, NULL );

			constraint_fixedparams_t fixed;
			fixed.Defaults();
			fixed.InitWithCurrentObjectState( pTonguePhys, pPlayerPhys );
			fixed.constraint.Defaults();
			m_pConstraint = physenv->CreateFixedConstraint( pTonguePhys, pPlayerPhys, NULL, fixed );

			// Increase the tongue's spring constant while lifting 
			m_hTongueTip->m_pSpring->SetSpringConstant( BARNACLE_TONGUE_SPRING_CONSTANT_LIFTING );
			UpdateTongue();
		}
		else
		{
			// Make a ragdoll for the guy, and hide him.
			pTouchEnt->AddSolidFlags( FSOLID_NOT_SOLID );
			pTouchEnt->Relink();

			// Find his head bone
			m_iGrabbedBoneIndex = -1;
			Vector vecNeckOffset = (pTouchEnt->EyePosition() - m_hTongueTip->GetAbsOrigin());
			studiohdr_t *pHdr = pAnimating->GetModelPtr();
			if ( pHdr )
			{
				int set = pAnimating->GetHitboxSet();
				for( int i = 0; i < pHdr->iHitboxCount(set); i++ )
				{
					mstudiobbox_t *pBox = pHdr->pHitbox( i, set );
					if ( !pBox )
						continue;
					
					if ( pBox->group == HITGROUP_HEAD )
					{
						m_iGrabbedBoneIndex = pBox->bone;
						break;
					}
				}
			}
			
			// HACK: Until we have correctly assigned hitgroups on our models, lookup the bones
			//		 for the models that we know are in the barnacle maps.
			//m_iGrabbedBoneIndex = pAnimating->LookupBone( "Bip01 L Foot" );
			if ( m_iGrabbedBoneIndex == -1 )
			{
				// Citizens, Conscripts
				m_iGrabbedBoneIndex = pAnimating->LookupBone( "Bip01 Head" );
			}
			if ( m_iGrabbedBoneIndex == -1 )
			{
				// Metrocops, Combine soldiers
				m_iGrabbedBoneIndex = pAnimating->LookupBone( "ValveBiped.Bip01_Head1" );
			}
			if ( m_iGrabbedBoneIndex == -1 )
			{
				// Vortigaunts
				m_iGrabbedBoneIndex = pAnimating->LookupBone( "ValveBiped.head" );
			}
			if ( m_iGrabbedBoneIndex == -1 )
			{
				// Bullsquids
				m_iGrabbedBoneIndex = pAnimating->LookupBone( "Bullsquid.Head_Bone1" );
			}

			if ( m_iGrabbedBoneIndex == -1 )
			{
				Warning("Couldn't find a bone to grab in the barnacle's target.\n" );

				// Just use the first bone
				m_iGrabbedBoneIndex = 0;
			}

			// Move the tip to the bone
			Vector vecBonePos;
			QAngle vecBoneAngles;
			pAnimating->GetBonePosition( m_iGrabbedBoneIndex, vecBonePos, vecBoneAngles );
			m_hTongueTip->Teleport( &vecBonePos, NULL, NULL );

			//NDebugOverlay::Box( vecBonePos, -Vector(5,5,5), Vector(5,5,5), 255,255,255, 0, 10.0 );

			// Create the ragdoll attached to tongue
			IPhysicsObject *pTonguePhysObject = m_hTongueTip->VPhysicsGetObject();
			m_hRagdoll = CreateServerRagdollAttached( pAnimating, vec3_origin, -1, COLLISION_GROUP_NONE, pTonguePhysObject, m_hTongueTip, 0, vecBonePos, m_iGrabbedBoneIndex, vec3_origin );
			m_hRagdoll->RemoveSolidFlags( FSOLID_NOT_SOLID );
			m_hRagdoll->Relink();
			m_hRagdoll->SetThink( NULL );
			m_hRagdoll->SetDamageEntity( pAnimating );
			m_hRagdoll->RecheckCollisionFilter();

			// Apply the target's current velocity to each of the ragdoll's bones
			Vector vecVelocity = pAnimating->GetGroundSpeedVelocity() * 0.5;
			ragdoll_t *pRagdoll = m_hRagdoll->GetRagdoll();
			for ( int i = 0; i < pRagdoll->listCount; i++ )
			{
				pRagdoll->list[i].pObject->AddVelocity( &vecVelocity, NULL );
			}

			// Now hide the actual enemy
			pTouchEnt->m_fEffects |= EF_NODRAW;

			// Increase the tongue's spring constant while lifting 
			m_hTongueTip->m_pSpring->SetSpringConstant( BARNACLE_TONGUE_SPRING_CONSTANT_LIFTING );
			UpdateTongue();

			// Store off the current bone matrix so we have it next frame
			pAnimating->SetupBones( m_pRagdollBones, BONE_USED_BY_ANYTHING );
		}
	}
}

//-----------------------------------------------------------------------------
// Purpose: Prey is in position, bite them and start swallowing them
//-----------------------------------------------------------------------------
void CNPC_Barnacle::BitePrey( void )
{
	CBaseCombatCharacter *pVictim = GetEnemyCombatCharacterPointer();
	Assert( pVictim );

	EmitSound( "NPC_Barnacle.FinalBite" );

	m_flVictimHeight = GetEnemy()->WorldAlignSize().z;

	// Kill the victim instantly
	int iDamageType = DMG_SLASH | DMG_ALWAYSGIB; 
	if ( m_hRagdoll )
	{
		// We've got a ragdoll, so prevent this creating another one
		iDamageType |= DMG_REMOVENORAGDOLL;
		m_hRagdoll->SetDamageEntity( NULL );
	}
	// DMG_CRUSH because we don't wan't to impart physics forces
	pVictim->TakeDamage( CTakeDamageInfo( this, this, pVictim->m_iHealth, iDamageType | DMG_CRUSH ) );
	m_cGibs = 3;

	// Players are never swallowed, nor is anything we don't have a ragdoll for
	if ( !m_hRagdoll || pVictim->IsPlayer() )
	{
		LostPrey( false );
		return;
	}

	// Stop the ragdoll moving and start to pull the sucker up into our mouth
	m_bSwallowingPrey = true;
	IPhysicsObject *pTonguePhys = m_hTongueTip->VPhysicsGetObject();

	// Make it nonsolid to the world so we can pull it through the roof
	m_hRagdoll->DisableCollisions( g_PhysWorldObject );

	// Stop the tongue's spring getting in the way of swallowing
	m_hTongueTip->m_pSpring->SetSpringConstant( 0 );

	// Switch the tongue tip to shadow and drag it up
	pTonguePhys->SetShadow( Vector(1e4,1e4,1e4), AngularImpulse(1e4,1e4,1e4), false, false );
	pTonguePhys->UpdateShadow( m_hTongueTip->GetAbsOrigin(), m_hTongueTip->GetAbsAngles(), false, 0 );
	m_hTongueTip->SetMoveType( MOVETYPE_NOCLIP );
	m_hTongueTip->SetAbsVelocity( Vector(0,0,32) );
	m_hTongueTip->Relink();

	m_flAltitude = (GetAbsOrigin().z - m_hTongueTip->GetAbsOrigin().z);
}

//-----------------------------------------------------------------------------
// Purpose: Slowly swallow the prey whole. Only used on humanoids.
//-----------------------------------------------------------------------------
void CNPC_Barnacle::SwallowPrey( void )
{
	if ( IsActivityFinished() )
	{
		SetActivity( (Activity)ACT_BARNACLE_CHEW_HUMAN );
	}

	// Move the body up slowly
	Vector vecSwallowPos = m_hTongueTip->GetAbsOrigin();
	vecSwallowPos.z -= m_flVictimHeight;
	//NDebugOverlay::Box( vecSwallowPos, -Vector(5,5,5), Vector(5,5,5), 255,255,255, 0, 0.1 );

	// bite prey every once in a while
	if ( random->RandomInt(0,49) == 0 )
	{
		EmitSound( "NPC_Barnacle.Digest" );
	}

	// Fully swallowed it?

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -