📄 npc_barnacle.cpp
字号:
// 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 + -