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

📄 npc_hydra.cpp

📁 hl2 source code. Do not use it illegal.
💻 CPP
📖 第 1 页 / 共 4 页
字号:

			// curve neck into spiral
			float distBackFromHead = m_body[i].flActualLength;
			Vector right, up;
			VectorVectors( m_vecHeadDir, right, up );

#if 1
			for (i = i - 1; i > 1 && distBackFromHead < distToTarget; i--)
			{
				Vector p0 = m_vecHeadGoal - m_vecHeadDir * distBackFromHead * 1.0; 

				m_body[i].vecGoalPos = p0;

				if ((m_vecTarget - m_body[i].vecPos).Length() > distToTarget + distBackFromHead)
				{
					m_body[i].flGoalInfluence = 1.0 - (distBackFromHead / distToTarget);
				}
				else
				{
					m_body[i].vecGoalPos = EyePosition( ) - m_vecHeadDir * distBackFromHead;
					m_body[i].flGoalInfluence = 1.0 - (distBackFromHead / distToTarget);
				}

				distBackFromHead += m_body[i].flActualLength;
			}
#endif
		}
		return;

	case TASK_HYDRA_PULLBACK:
		{
			if (m_body.Count() < 2)
			{
				TaskFail( "hydra is too short to begin stab" );
				return;
			}
			CBaseEntity *pEnemy = (CBaseEntity *)UTIL_PlayerByIndex( 1 );
			if (GetEnemy() != NULL)
			{
				pEnemy = GetEnemy();
			}

			AimHeadInTravelDirection( 0.2 );

			// float dist = (EyePosition() - m_vecHeadGoal).Length();

			if (m_flCurrentLength < m_idealLength + m_idealSegmentLength)
			{
				TaskComplete();
			}
		}
		break;

	default:
		BaseClass::RunTask( pTask );
		break;
	}

}

//-------------------------------------

Vector CNPC_Hydra::EyePosition( ) 
{
	int i = m_body.Count() - 1;

	if (i >= 0)
	{
		return m_body[i].vecPos;
	}
	return GetAbsOrigin(); 
}

const QAngle &CNPC_Hydra::EyeAngles()
{
	return GetAbsAngles();
}


Vector CNPC_Hydra::BodyTarget( const Vector &posSrc, bool bNoisy)
{
	int i;

	if (m_body.Count() < 2)
	{
		return GetAbsOrigin();
	}

	int iShortest = 1;
	float flShortestDist = (posSrc - m_body[iShortest].vecPos).LengthSqr();
	for (i = 2; i < m_body.Count(); i++)
	{
		float flDist = (posSrc - m_body[i].vecPos).LengthSqr();
		if (flDist < flShortestDist)
		{
			iShortest = i;
			flShortestDist = flDist;
		}
	}

	// NDebugOverlay::Box(m_body[iShortest].vecPos, Vector( -2, -2, -2 ), Vector( 2, 2, 2 ), 0, 0, 255, 20, .1);

	return m_body[iShortest].vecPos;
}


void CNPC_Hydra::AimHeadInTravelDirection( float flInfluence )
{

	// aim in the direction of movement enemy
	Vector delta = m_body[m_body.Count()-1].vecDelta;
	VectorNormalize( delta );
	if (DotProduct( delta, m_vecHeadDir ) < 0)
	{
		delta = -delta;
	}

	m_vecHeadDir = m_vecHeadDir * (1 - flInfluence) + delta * flInfluence;
	VectorNormalize( m_vecHeadDir.GetForModify() );
}

//-------------------------------------

//-----------------------------------------------------------------------------
// Purpose: Hydra impaling is done by creating an entity, forming a constraint
//			between that entity and the target ragdoll, and then updating then
//			entity to follow the hydra.
//-----------------------------------------------------------------------------

//-----------------------------------------------------------------------------
// Purpose: This is the entity we create to follow the hydra
//-----------------------------------------------------------------------------
class CHydraImpale : public CBaseAnimating
{
	DECLARE_CLASS( CHydraImpale, CBaseAnimating );
public:
	DECLARE_DATADESC();

	void	Spawn( void );
	void	Precache( void );
	void	ImpaleThink( void );

	IPhysicsConstraint *CreateConstraint( CNPC_Hydra *pHydra, IPhysicsObject *pTargetPhys, IPhysicsConstraintGroup *pGroup );
	static CHydraImpale *Create( CNPC_Hydra *pHydra, CBaseEntity *pObject2 );

public:
	IPhysicsConstraint		*m_pConstraint;
	CHandle<CNPC_Hydra>		m_hHydra;
};

BEGIN_DATADESC( CHydraImpale )
	DEFINE_PHYSPTR( CHydraImpale, m_pConstraint ),
	DEFINE_FIELD( CHydraImpale,		m_hHydra,			FIELD_EHANDLE ),

	DEFINE_THINKFUNC( CHydraImpale, ImpaleThink ),
END_DATADESC()

LINK_ENTITY_TO_CLASS( hydra_impale, CHydraImpale );

//-----------------------------------------------------------------------------
// Purpose: To by usable by the constraint system, this needs to have a phys model.
//-----------------------------------------------------------------------------
void CHydraImpale::Spawn( void )
{
	Precache();
	SetModel( "models/props_junk/cardboard_box001a.mdl" );
	m_fEffects |= EF_NODRAW;

	// We don't want this to be solid, because we don't want it to collide with the hydra.
	SetSolid( SOLID_VPHYSICS );
	AddSolidFlags( FSOLID_NOT_SOLID );
	VPhysicsInitShadow( false, false );

	// Disable movement on this sucker, we're going to move him manually
	SetMoveType( MOVETYPE_FLY );
	
	BaseClass::Spawn();

	m_pConstraint = NULL;
}

//-----------------------------------------------------------------------------
// Purpose: 
//-----------------------------------------------------------------------------
void CHydraImpale::Precache( void )
{
	PrecacheModel( "models/props_junk/cardboard_box001a.mdl" );
	BaseClass::Precache();
}

//-----------------------------------------------------------------------------
// Purpose: Update the impale entity's position to the hydra's desired
//-----------------------------------------------------------------------------
void CHydraImpale::ImpaleThink( void )
{
	if ( !m_hHydra )
	{
		// Remove ourselves.
		m_pConstraint->Deactivate();
		UTIL_Remove( this );
		return;
	}

	// Ask the Hydra where he'd like the ragdoll, and move ourselves there
	Vector vecOrigin;
	QAngle vecAngles;
	m_hHydra->GetDesiredImpaledPosition( &vecOrigin, &vecAngles );
	SetAbsOrigin( vecOrigin );
	SetAbsAngles( vecAngles );

	//NDebugOverlay::Cross3D( vecOrigin, Vector( -5, -5, -5 ), Vector( 5, 5, 5 ), 255, 0, 0, 20, .1);

	SetNextThink( gpGlobals->curtime + 0.1f );
}

//-----------------------------------------------------------------------------
// Purpose: Activate/create the constraint
//-----------------------------------------------------------------------------
IPhysicsConstraint *CHydraImpale::CreateConstraint( CNPC_Hydra *pHydra, IPhysicsObject *pTargetPhys, IPhysicsConstraintGroup *pGroup )
{
	m_hHydra = pHydra;
	
	IPhysicsObject *pImpalePhysObject = VPhysicsGetObject();
	Assert( pImpalePhysObject );

	constraint_fixedparams_t fixed;
	fixed.Defaults();
	fixed.InitWithCurrentObjectState( pImpalePhysObject, pTargetPhys );
	fixed.constraint.Defaults();

	m_pConstraint = physenv->CreateFixedConstraint( pImpalePhysObject, pTargetPhys, pGroup, fixed );
	if ( m_pConstraint )
	{
		m_pConstraint->SetGameData( (void *)this );
	}

	SetThink( ImpaleThink );
	SetNextThink( gpGlobals->curtime );
	return m_pConstraint;
}

//-----------------------------------------------------------------------------
// Purpose: Create a Hydra Impale between the hydra and the entity passed in
//-----------------------------------------------------------------------------
CHydraImpale *CHydraImpale::Create( CNPC_Hydra *pHydra, CBaseEntity *pTarget )
{
	Vector vecOrigin;
	QAngle vecAngles;
	pHydra->GetDesiredImpaledPosition( &vecOrigin, &vecAngles );
	pTarget->Teleport( &vecOrigin, &vecAngles, &vec3_origin );

	CHydraImpale *pImpale = (CHydraImpale *)CBaseEntity::Create( "hydra_impale", vecOrigin, vecAngles );
	if ( !pImpale )
		return NULL;

	IPhysicsObject *pTargetPhysObject = pTarget->VPhysicsGetObject();
	if ( !pTargetPhysObject )
	{
		Msg(" Error: Tried to hydra_impale an entity without a physics model.\n" );
		return NULL;
	}

	IPhysicsConstraintGroup *pGroup = NULL;
	// Ragdoll? If so, use it's constraint group
	CRagdollProp *pRagdoll = dynamic_cast<CRagdollProp*>(pTarget);
	if ( pRagdoll )
	{
		pGroup = pRagdoll->GetRagdoll()->pGroup;
	}

	if ( !pImpale->CreateConstraint( pHydra, pTargetPhysObject, pGroup ) )
		return NULL;

	return pImpale;
}

void CNPC_Hydra::AttachStabbedEntity( CBaseAnimating *pAnimating, Vector vecForce, trace_t &tr )
{
	CTakeDamageInfo info( this, this, pAnimating->m_iHealth+25, DMG_SLASH );
	info.SetDamageForce( vecForce );
	info.SetDamagePosition( tr.endpos );

	CBaseEntity *pRagdoll = CreateServerRagdoll( pAnimating, 0, info, COLLISION_GROUP_INTERACTIVE_DEBRIS );

	// Create our impale entity
	CHydraImpale::Create( this, pRagdoll );

	m_bStabbedEntity = true;

	UTIL_Remove( pAnimating );
}

void CNPC_Hydra::UpdateStabbedEntity( void )
{
	/*
	CBaseEntity *pEntity = m_grabController.GetAttached();
	if ( !pEntity )
	{
		DetachStabbedEntity( false );
		return;
	}

	QAngle vecAngles(0,0,1);
	Vector vecOrigin = m_body[m_body.Count()-2].vecPos;

	//NDebugOverlay::Cross3D( vecOrigin, Vector( -5, -5, -5 ), Vector( 5, 5, 5 ), 255, 0, 0, 20, .1);

	m_grabController.SetTargetPosition( vecOrigin, vecAngles );
	*/
}

void CNPC_Hydra::DetachStabbedEntity( bool playSound )
{
	/*
	CBaseEntity *pObject = m_grabController.GetAttached();
	if ( pObject != NULL )
	{
		IPhysicsObject *pPhysics = pObject->VPhysicsGetObject();

		// Enable collision with this object again
		if ( pPhysics != NULL )
		{
			physenv->EnableCollisions( pPhysics, VPhysicsGetObject() );
			pPhysics->RecheckCollisionFilter();
		}
	}

	m_grabController.DetachEntity();
	*/

	if ( playSound )
	{
		//Play the detach sound
	}

	m_bStabbedEntity = false;
}

void CNPC_Hydra::GetDesiredImpaledPosition( Vector *vecOrigin, QAngle *vecAngles )
{
	*vecOrigin = m_body[m_body.Count()-2].vecPos;
	*vecAngles = QAngle(0,0,0);
}

//-----------------------------------------------------------------------------
//
// CNPC_Hydra Schedules
//
//-------------------------------------


AI_BEGIN_CUSTOM_NPC( npc_hydra, CNPC_Hydra )

	//Register our interactions

	//Conditions
	DECLARE_CONDITION( COND_HYDRA_SNAGGED )
	DECLARE_CONDITION( COND_HYDRA_STUCK )
	DECLARE_CONDITION( COND_HYDRA_OVERSHOOT )
	DECLARE_CONDITION( COND_HYDRA_OVERSTRETCH )
	DECLARE_CONDITION( COND_HYDRA_STRIKE )
	DECLARE_CONDITION( COND_HYDRA_NOSTUCK )

	//Squad slots

	//Tasks
	DECLARE_TASK( TASK_HYDRA_RETRACT )
	DECLARE_TASK( TASK_HYDRA_DEPLOY )
	DECLARE_TASK( TASK_HYDRA_GET_OBJECT )
	DECLARE_TASK( TASK_HYDRA_THROW_OBJECT )
	DECLARE_TASK( TASK_HYDRA_PREP_STAB )
	DECLARE_TASK( TASK_HYDRA_STAB )
	DECLARE_TASK( TASK_HYDRA_PULLBACK )

	//Activities
	DECLARE_ACTIVITY( ACT_HYDRA_COWER )
	DECLARE_ACTIVITY( ACT_HYDRA_STAB )

	//=========================================================
	// > SCHED_HYDRA_STAND_LOOK
	//=========================================================
	DEFINE_SCHEDULE 
	(
		SCHED_HYDRA_DEPLOY,

		"	Tasks"
		"		TASK_HYDRA_DEPLOY			0"
		"		TASK_WAIT					0.5"
		""
		"	Interrupts"
		"		COND_NEW_ENEMY"
	)

	//=========================================================
	// > SCHED_HYDRA_COWER
	//=========================================================
	DEFINE_SCHEDULE 
	(
		SCHED_HYDRA_RETRACT,

		"	Tasks"
		"		TASK_STOP_MOVING			0"
		"		TASK_SET_ACTIVITY			ACTIVITY:ACT_HYDRA_COWER"
		"		TASK_WAIT					0.5"
		""
		"	Interrupts"
	)

	DEFINE_SCHEDULE 
	(
		SCHED_HYDRA_IDLE,

		"	Tasks"
		"		TASK_STOP_MOVING				0"
		"		TASK_WAIT_INDEFINITE			0"
		""
		"	Interrupts "
		"		COND_NEW_ENEMY"
	)

	DEFINE_SCHEDULE 
	(
		SCHED_HYDRA_STAB,

		"	Tasks"
		"		TASK_SET_FAIL_SCHEDULE			SCHEDULE:SCHED_HYDRA_DEPLOY"
		"		TASK_HYDRA_PREP_STAB			4.0"
		"		TASK_HYDRA_STAB					0"
		"		TASK_WAIT						0.5"
		// "		TASK_HYDRA_PULLBACK				100"
		""
		"	Interrupts "
		"		COND_NEW_ENEMY"
		"		COND_HYDRA_OVERSTRETCH"
	)

	DEFINE_SCHEDULE 
	(
		SCHED_HYDRA_PULLBACK,

		"	Tasks"
		"		TASK_STOP_MOVING				0"
		"		TASK_WAIT						0.4"
		"		TASK_HYDRA_PULLBACK				100"
		""
		"	Interrupts "
		"		COND_NEW_ENEMY"
	)

	DEFINE_SCHEDULE 
	(
		SCHED_HYDRA_THROW,

		"	Tasks"
		"		TASK_STOP_MOVING					0"
		"		TASK_HYDRA_GET_OBJECT				0"
		"		TASK_WAIT_FOR_MOVEMENT				0"
		"		TASK_HYDRA_THROW_OBJECT				0"
		"		TASK_WAIT							1"
		""
		"	Interrupts"
	)

	DEFINE_SCHEDULE
	(
		SCHED_HYDRA_RANGE_ATTACK,

		"	Tasks"
		"		TASK_STOP_MOVING		0"
		"		TASK_ANNOUNCE_ATTACK	1"	// 1 = primary attack
		"		TASK_FACE_ENEMY			0"
		"		TASK_RANGE_ATTACK1		0"
		""
		"	Interrupts"
		"		COND_NEW_ENEMY"
		"		COND_ENEMY_DEAD"
		"		COND_LIGHT_DAMAGE"
		"		COND_HEAVY_DAMAGE"
		"		COND_ENEMY_OCCLUDED"
		"		COND_NO_PRIMARY_AMMO"
		"		COND_HEAR_DANGER"
	)

AI_END_CUSTOM_NPC()


⌨️ 快捷键说明

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