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

📄 npc_hydra.cpp

📁 hl2 source code. Do not use it illegal.
💻 CPP
📖 第 1 页 / 共 4 页
字号:
//========= Copyright (c) 1996-2002, Valve LLC, All rights reserved. ==========
//
// Purpose:
//
// $NoKeywords: $
//=============================================================================

#include "cbase.h"

#include "npc_hydra.h"

#include "ai_hull.h"
#include "saverestore_utlvector.h"
#include "physics_saverestore.h"
#include "vphysics/constraints.h"
#include "vcollide_parse.h"
#include "ragdoll_shared.h"
#include "physics_prop_ragdoll.h"

//-----------------------------------------------------------------------------
//
// CNPC_Hydra
//

#define HYDRA_MAX_LENGTH	500

LINK_ENTITY_TO_CLASS( npc_hydra, CNPC_Hydra );

//=========================================================
// Hydra activities
//=========================================================
int ACT_HYDRA_COWER;
int ACT_HYDRA_STAB;

//=========================================================
// Private conditions
//=========================================================

//==================================================
// AntlionConditions
//==================================================

enum
{
	COND_HYDRA_SNAGGED = LAST_SHARED_CONDITION,
	COND_HYDRA_STUCK,
	COND_HYDRA_OVERSHOOT,
	COND_HYDRA_OVERSTRETCH, // longer than max distance
	COND_HYDRA_STRIKE,		// head hit something
	COND_HYDRA_NOSTUCK		// no segments are stuck
};

//=========================================================
// Hydra schedules
//=========================================================
enum
{
	SCHED_HYDRA_DEPLOY = LAST_SHARED_SCHEDULE,
	SCHED_HYDRA_RETRACT,
	SCHED_HYDRA_IDLE,
	SCHED_HYDRA_STAB,		// shoot out head and try to hit object
	SCHED_HYDRA_PULLBACK,	// 
	SCHED_HYDRA_TIGHTEN_SLACK,	// snagged on something, tighten slack up to obstacle and try again from there
	SCHED_HYDRA_RETREAT,		
	SCHED_HYDRA_THROW,
	SCHED_HYDRA_RANGE_ATTACK
};

//=========================================================
// Hydra tasks
//=========================================================
enum 
{
	TASK_HYDRA_RETRACT = LAST_SHARED_TASK,
	TASK_HYDRA_DEPLOY,
	TASK_HYDRA_GET_OBJECT,
	TASK_HYDRA_THROW_OBJECT,
	TASK_HYDRA_PREP_STAB,
	TASK_HYDRA_STAB,
	TASK_HYDRA_PULLBACK,
	TASK_HYDRA_SET_MAX_TENSION,
	TASK_HYDRA_SET_BLEND_TENSION
};


//---------------------------------------------------------
// Custom Client entity
//---------------------------------------------------------
IMPLEMENT_SERVERCLASS_ST(CNPC_Hydra, DT_NPC_Hydra)
	SendPropVector( SENDINFO_NETWORKARRAYELEM( m_vecChain, 0 ), -1, SPROP_COORD ),
	SendPropVector( SENDINFO_NETWORKARRAYELEM( m_vecChain, 1 ), -1, SPROP_COORD ),
	SendPropVector( SENDINFO_NETWORKARRAYELEM( m_vecChain, 2 ), -1, SPROP_COORD ),
	SendPropVector( SENDINFO_NETWORKARRAYELEM( m_vecChain, 3 ), -1, SPROP_COORD ),
	SendPropVector( SENDINFO_NETWORKARRAYELEM( m_vecChain, 4 ), -1, SPROP_COORD ),
	SendPropVector( SENDINFO_NETWORKARRAYELEM( m_vecChain, 5 ), -1, SPROP_COORD ),
	SendPropVector( SENDINFO_NETWORKARRAYELEM( m_vecChain, 6 ), -1, SPROP_COORD ),
	SendPropVector( SENDINFO_NETWORKARRAYELEM( m_vecChain, 7 ), -1, SPROP_COORD ),
	SendPropVector( SENDINFO_NETWORKARRAYELEM( m_vecChain, 8 ), -1, SPROP_COORD ),
	SendPropVector( SENDINFO_NETWORKARRAYELEM( m_vecChain, 9 ), -1, SPROP_COORD ),
	SendPropVector( SENDINFO_NETWORKARRAYELEM( m_vecChain, 10 ), -1, SPROP_COORD ),
	SendPropVector( SENDINFO_NETWORKARRAYELEM( m_vecChain, 11 ), -1, SPROP_COORD ),
	SendPropVector( SENDINFO_NETWORKARRAYELEM( m_vecChain, 12 ), -1, SPROP_COORD ),
	SendPropVector( SENDINFO_NETWORKARRAYELEM( m_vecChain, 13 ), -1, SPROP_COORD ),
	SendPropVector( SENDINFO_NETWORKARRAYELEM( m_vecChain, 14 ), -1, SPROP_COORD ),
	SendPropVector( SENDINFO_NETWORKARRAYELEM( m_vecChain, 15 ), -1, SPROP_COORD ),
	SendPropVector( SENDINFO_NETWORKARRAYELEM( m_vecChain, 16 ), -1, SPROP_COORD ),
	SendPropVector( SENDINFO_NETWORKARRAYELEM( m_vecChain, 17 ), -1, SPROP_COORD ),
	SendPropVector( SENDINFO_NETWORKARRAYELEM( m_vecChain, 18 ), -1, SPROP_COORD ),
	SendPropVector( SENDINFO_NETWORKARRAYELEM( m_vecChain, 19 ), -1, SPROP_COORD ),
	SendPropVector( SENDINFO_NETWORKARRAYELEM( m_vecChain, 20 ), -1, SPROP_COORD ),
	SendPropVector( SENDINFO_NETWORKARRAYELEM( m_vecChain, 21 ), -1, SPROP_COORD ),
	SendPropVector( SENDINFO_NETWORKARRAYELEM( m_vecChain, 22 ), -1, SPROP_COORD ),
	SendPropVector( SENDINFO_NETWORKARRAYELEM( m_vecChain, 23 ), -1, SPROP_COORD ),
	SendPropVector( SENDINFO_NETWORKARRAYELEM( m_vecChain, 24 ), -1, SPROP_COORD ),
	SendPropVector( SENDINFO_NETWORKARRAYELEM( m_vecChain, 25 ), -1, SPROP_COORD ),
	SendPropVector( SENDINFO_NETWORKARRAYELEM( m_vecChain, 26 ), -1, SPROP_COORD ),
	SendPropVector( SENDINFO_NETWORKARRAYELEM( m_vecChain, 27 ), -1, SPROP_COORD ),
	SendPropVector( SENDINFO_NETWORKARRAYELEM( m_vecChain, 28 ), -1, SPROP_COORD ),
	SendPropVector( SENDINFO_NETWORKARRAYELEM( m_vecChain, 29 ), -1, SPROP_COORD ),
	SendPropVector( SENDINFO_NETWORKARRAYELEM( m_vecChain, 30 ), -1, SPROP_COORD ),
	SendPropVector( SENDINFO_NETWORKARRAYELEM( m_vecChain, 31 ), -1, SPROP_COORD ),
	SendPropVector( SENDINFO( m_vecHeadDir ), -1, SPROP_NORMAL ),
	SendPropFloat( SENDINFO( m_flRelaxedLength ), 12, 0, 0.0, HYDRA_MAX_LENGTH * 1.5 ),
END_SEND_TABLE()


//---------------------------------------------------------
// Save/Restore
//---------------------------------------------------------
BEGIN_DATADESC( CNPC_Hydra )

	DEFINE_AUTO_ARRAY( CNPC_Hydra,	m_vecChain,				FIELD_POSITION_VECTOR ),
	DEFINE_FIELD( CNPC_Hydra,		m_activeChain,			FIELD_INTEGER ),
	DEFINE_FIELD( CNPC_Hydra,		m_bHasStuckSegments,	FIELD_BOOLEAN ),
	DEFINE_FIELD( CNPC_Hydra,		m_flCurrentLength,		FIELD_FLOAT ),
	DEFINE_FIELD( CNPC_Hydra,		m_vecHeadGoal,			FIELD_POSITION_VECTOR ),
	DEFINE_FIELD( CNPC_Hydra,		m_flHeadGoalInfluence,	FIELD_FLOAT ),
	DEFINE_FIELD( CNPC_Hydra,		m_vecHeadDir,			FIELD_VECTOR ),
	DEFINE_FIELD( CNPC_Hydra,		m_flRelaxedLength,		FIELD_FLOAT ),
	DEFINE_FIELD( CNPC_Hydra,		m_vecOutward,			FIELD_VECTOR ),
	DEFINE_UTLVECTOR( CNPC_Hydra,	m_body,					FIELD_EMBEDDED ), 
	DEFINE_FIELD( CNPC_Hydra,		m_idealLength,			FIELD_FLOAT ),
	DEFINE_FIELD( CNPC_Hydra,		m_idealSegmentLength,	FIELD_FLOAT ),
	DEFINE_FIELD( CNPC_Hydra,		m_bExtendSoundActive,	FIELD_BOOLEAN ),
	DEFINE_SOUNDPATCH( CNPC_Hydra,  m_pExtendTentacleSound ),
	DEFINE_FIELD( CNPC_Hydra,		m_seed,					FIELD_FLOAT ),
	DEFINE_FIELD( CNPC_Hydra,		m_vecTarget,			FIELD_POSITION_VECTOR ),
	DEFINE_FIELD( CNPC_Hydra,		m_vecTargetDir,			FIELD_VECTOR ),
	DEFINE_FIELD( CNPC_Hydra,		m_flLastAdjustmentTime, FIELD_TIME ),
	DEFINE_FIELD( CNPC_Hydra,		m_flTaskStartTime,		FIELD_TIME ),
	DEFINE_FIELD( CNPC_Hydra,		m_flTaskEndTime,		FIELD_TIME ),
	DEFINE_FIELD( CNPC_Hydra,		m_flLengthTime,			FIELD_TIME ),
	DEFINE_FIELD( CNPC_Hydra,		m_bStabbedEntity,		FIELD_BOOLEAN ),

END_DATADESC()


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

BEGIN_SIMPLE_DATADESC( HydraBone )
	DEFINE_FIELD( HydraBone,		vecPos,			FIELD_POSITION_VECTOR ),
	DEFINE_FIELD( HydraBone,		vecDelta,		FIELD_VECTOR ),
	DEFINE_FIELD( HydraBone,		flIdealLength,	FIELD_FLOAT ),
	DEFINE_FIELD( HydraBone,		flActualLength,	FIELD_FLOAT ),
	DEFINE_FIELD( HydraBone,		bStuck,			FIELD_BOOLEAN ),
	DEFINE_FIELD( HydraBone,		bOnFire,		FIELD_BOOLEAN ),
	DEFINE_FIELD( HydraBone,		vecGoalPos,		FIELD_POSITION_VECTOR ),
	DEFINE_FIELD( HydraBone,		flGoalInfluence,FIELD_FLOAT ),
END_DATADESC()

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

//static ConVar	sv_hydraMinTension( "hydra_min_tension", "1", FCVAR_ARCHIVE | FCVAR_SERVER, "Hydra Slack" );
//static ConVar	sv_hydraLengthTension( "hydra_length_tension", "1", FCVAR_ARCHIVE | FCVAR_SERVER, "Hydra Slack" );

static ConVar	sv_hydraLength( "hydra_length", "100", FCVAR_ARCHIVE | FCVAR_SERVER, "Hydra Length" );
static ConVar	sv_hydraSlack( "hydra_slack", "200", FCVAR_ARCHIVE | FCVAR_SERVER, "Hydra Slack" );

static ConVar	sv_hydraSegmentLength( "hydra_segment_length", "30", FCVAR_ARCHIVE | FCVAR_SERVER, "Hydra Slack" );

static ConVar	sv_hydraTest( "hydra_test", "1", FCVAR_ARCHIVE | FCVAR_SERVER, "Hydra Slack" );

static ConVar	sv_hydraBendTension( "hydra_bend_tension", "0.4", FCVAR_ARCHIVE | FCVAR_SERVER, "Hydra Slack" );
static ConVar	sv_hydraBendDelta( "hydra_bend_delta", "50", FCVAR_ARCHIVE | FCVAR_SERVER, "Hydra Slack" );

static ConVar	sv_hydraGoalTension( "hydra_goal_tension", "0.5", FCVAR_ARCHIVE | FCVAR_SERVER, "Hydra Slack" );
static ConVar	sv_hydraGoalDelta( "hydra_goal_delta", "400", FCVAR_ARCHIVE | FCVAR_SERVER, "Hydra Slack" );

static ConVar	sv_hydraMomentum( "hydra_momentum", "0.5", FCVAR_ARCHIVE | FCVAR_SERVER, "Hydra Slack" );

static ConVar	sv_hydraTestSpike( "sv_hydraTestSpike", "1", FCVAR_SERVER, "Hydra Test impaling code" );

//-------------------------------------
// Purpose: Initialize the custom schedules
//-------------------------------------


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

void CNPC_Hydra::Precache()
{
	engine->PrecacheModel( "models/Hydra.mdl" );
	UTIL_PrecacheOther( "hydra_impale" );

	BaseClass::Precache();
}
 

void CNPC_Hydra::Activate( void )
{
	CPASAttenuationFilter filter( this );
	CSoundEnvelopeController &controller = CSoundEnvelopeController::GetController();
	m_pExtendTentacleSound = controller.SoundCreate( filter, entindex(), "NPC_Hydra.ExtendTentacle" );
	
	controller.Play( m_pExtendTentacleSound, 1.0, 100 );

	BaseClass::Activate();
}


//-----------------------------------------------------------------------------
// Purpose: Returns this monster's place in the relationship table.
//-----------------------------------------------------------------------------
Class_T	CNPC_Hydra::Classify( void )
{
	return CLASS_BARNACLE; 
}

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

#define HYDRA_OUTWARD_BIAS	16
#define HYDRA_INWARD_BIAS	30

void CNPC_Hydra::Spawn()
{
	Precache();

	BaseClass::Spawn();

	SetModel( "models/Hydra.mdl" );

	SetHullType(HULL_HUMAN);
	SetHullSizeNormal();

	SetSolid( SOLID_BBOX );
	AddSolidFlags( FSOLID_NOT_STANDABLE );
	SetMoveType( MOVETYPE_STEP );
	SetBloodColor( BLOOD_COLOR_RED );
	m_fEffects			= 0;
	m_iHealth			= 20;
	m_flFieldOfView		= -1.0;// indicates the width of this NPC's forward view cone ( as a dotproduct result )
	m_NPCState			= NPC_STATE_NONE;
	// CapabilitiesAdd( bits_CAP_TURN_HEAD | bits_CAP_DOORS_GROUP | bits_CAP_MOVE_GROUND | bits_CAP_MOVE_CLIMB );
	// CapabilitiesAdd( bits_CAP_USE_WEAPONS );
	// CapabilitiesAdd( bits_CAP_ANIMATEDFACE );

	GetVectors( NULL, NULL, &m_vecOutward );

	SetAbsAngles( QAngle( 0, 0, 0 ) );

	m_vecChain.Set( 0, GetAbsOrigin( ) - m_vecOutward * 32 );
	m_vecChain.Set( 1, GetAbsOrigin( ) + m_vecOutward * 16 );

	m_vecHeadGoal = m_vecChain[1] + m_vecOutward * HYDRA_OUTWARD_BIAS;
	m_vecHeadDir = Vector( 0, 0, 1 );

	// init bones
	HydraBone bone;
	bone.vecPos = GetAbsOrigin( ) - m_vecOutward * HYDRA_INWARD_BIAS;
	m_body.AddToTail( bone );
	bone.vecPos = m_vecChain[1];
	m_body.AddToTail( bone );
	bone.vecPos = m_vecHeadGoal;
	m_body.AddToTail( bone );
	bone.vecPos = m_vecHeadGoal + m_vecHeadDir;
	m_body.AddToTail( bone );

	m_idealSegmentLength = sv_hydraSegmentLength.GetFloat();

	for (int i = 2; i < CHAIN_LINKS; i++)
	{
		m_vecChain.Set( i, m_vecChain[i-1] );
	}

	m_seed = random->RandomFloat( 0.0, 2000.0 );

	NPCInit();

	m_takedamage = DAMAGE_NO;
}


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


void CNPC_Hydra::RunAI( void )
{
	CheckLength( );

	AdjustLength( );

	BaseClass::RunAI();

	CalcGoalForces( );
	MoveBody( );

	int i;
	for (i = 1; i < CHAIN_LINKS && i < m_body.Count(); i++)
	{
		m_vecChain.Set( i, m_body[i].vecPos );

#if 0
		if (m_body[i].bStuck)
		{
			NDebugOverlay::Box(m_body[i].vecPos, Vector( -2, -2, -2 ), Vector( 2, 2, 2 ), 255, 0, 0, 20, .1);
		}
		else
		{
			NDebugOverlay::Box(m_body[i].vecPos, Vector( -2, -2, -2 ), Vector( 2, 2, 2 ), 0, 255, 0, 20, .1);
		}
		NDebugOverlay::Line( m_body[i].vecPos, m_body[i].vecPos + m_body[i].vecDelta, 0, 255, 0, true, .1);
		NDebugOverlay::Line( m_body[i-1].vecPos, m_body[i].vecPos, 255, 255, 255, true, .1);
#endif

#if 0
		char text[128];
		Q_snprintf( text, sizeof( text ), "%d", i );
		NDebugOverlay::Text( m_body[i].vecPos, text, false, 0.1 );
#endif

#if 0
		char text[128];
		Q_snprintf( text, sizeof( text ), "%4.0f", (m_body[i].vecPos - m_body[i-1].vecPos).Length() * 100 / m_idealSegmentLength - 100);
		NDebugOverlay::Text( 0.5*(m_body[i-1].vecPos + m_body[i].vecPos), text, false, 0.1 );
#endif
	}
	//NDebugOverlay::Box(m_body[i].vecPos, Vector( -2, -2, -2 ), Vector( 2, 2, 2 ), 0, 255, 0, 20, .1);
	//NDebugOverlay::Box( m_vecHeadGoal, Vector( -2, -2, -2 ), Vector( 2, 2, 2 ), 255, 255, 0, 20, .1);
	for (; i < CHAIN_LINKS; i++)
	{
		m_vecChain.Set( i, m_vecChain[i-1] );
	}
}




Vector CNPC_Hydra::TestPosition( float t )
{
	// return GetAbsOrigin( ) + Vector( sin( (m_seed + t) * 2.3 ) * 15, cos( (m_seed + t) * 2.4 ) * 150, sin( ( m_seed + t ) * 1.8 ) * 50 ) + m_vecOutward * sv_hydraLength.GetFloat();;
	t = (int)(t * 0.2);
#if 1
	Vector tmp = Vector( sin( (m_seed + t) * 0.8 ) * 15, cos( (m_seed + t) * 0.9 ) * 150, sin( ( m_seed + t ) * 0.4 ) * 50 );
	tmp += 	Vector( sin( (m_seed + t) * 1.0 ) * 4, cos( (m_seed + t) * 0.9 ) * 4, sin( ( m_seed + t ) * 1.1 ) * 6 );
	tmp += 	GetAbsOrigin( ) + m_vecOutward * sv_hydraLength.GetFloat();
	return tmp;
#else
	
	Vector tmp;
	tmp.Init;
	CBaseEntity *pPlayer = (CBaseEntity *)UTIL_PlayerByIndex( 1 );
	if ( pPlayer )
	{
		tmp = pPlayer->EyePosition( );

		Vector delta = (tmp - GetAbsOrigin( ));
		
		if (delta.Length() > 200)
		{
			tmp = GetAbsOrigin( ) + Vector( 0, 0, 200 );
		}
		m_vecHeadDir = (pPlayer->EyePosition( ) - m_body[m_body.Count()-2].vecPos);
		VectorNormalize( m_vecHeadDir );
	}

	return tmp;
#endif
		// m_vecHeadGoal = GetAbsOrigin( ) + Vector( sin( gpGlobals->curtime * 0.3 ) * 15, cos( gpGlobals->curtime * 0.4 ) * 150, sin( gpGlobals->curtime * 0.2 ) * 50 + dt );
}




//-----------------------------------------------------------------------------
// Purpose: Calculate the bone forces based on goal positions, bending rules, stretching rules, etc.
// Input  :
// Output :
//-----------------------------------------------------------------------------

void CNPC_Hydra::CalcGoalForces( )
{
	int i;

	int iFirst = 2;
	int iLast = m_body.Count() - 1;

	// keep head segment straight
	m_body[iLast].vecGoalPos = m_vecHeadGoal; // + m_vecHeadDir * m_body[iLast-1].flActualLength;
	m_body[iLast].flGoalInfluence = m_flHeadGoalInfluence;

	m_body[iLast-1].vecGoalPos = m_vecHeadGoal - m_vecHeadDir * m_idealSegmentLength;
	m_body[iLast-1].flGoalInfluence = 1.0; // m_flHeadGoalInfluence;


	// momentum?
	for (i = iFirst; i <= iLast; i++)
	{
		m_body[i].vecDelta = m_body[i].vecDelta * sv_hydraMomentum.GetFloat();
	}

	//Vector right, up;
	//VectorVectors( m_vecHeadDir, right, up );

	float flGoalSegmentLength = m_idealSegmentLength * ( m_idealLength / m_flCurrentLength);

	// goal forces
#if 1
	for (i = iFirst; i <= iLast; i++)
	{
		// Msg("(%d) %.2f\n", i, t );

		float flInfluence = m_body[i].flGoalInfluence;
		if (flInfluence > 0)
		{
			m_body[i].flGoalInfluence = 0.0;

			Vector v0 = (m_body[i].vecGoalPos - m_body[i].vecPos);
			float length = v0.Length();
			if (length > sv_hydraGoalDelta.GetFloat())
			{
				v0 = v0 * sv_hydraGoalDelta.GetFloat() / length;
			}
			m_body[i].vecDelta += v0 * flInfluence * sv_hydraGoalTension.GetFloat(); 
			// NDebugOverlay::Box(m_body[i].vecGoalPos, Vector( -2, -2, -2 ), Vector( 2, 2, 2 ), 255, 255, 0, flInfluence * 255, .1);
		}
	}
#endif

	// bending forces
	for (i = iFirst-1; i <= iLast - 1; i++)
	{
		// Msg("(%d) %.2f\n", i, t );
		Vector v3 = m_body[i+1].vecPos - m_body[i-1].vecPos;
		VectorNormalize( v3 );

		Vector delta;
		float length;

		//NDebugOverlay::Line( m_body[i].vecPos + v3 * flGoalSegmentLength, m_body[i].vecPos - v3 * flGoalSegmentLength, 255, 0, 0, true, .1);

		if (i+1 <= iLast)
		{
			// towards head
			delta = (m_body[i].vecPos + v3 * flGoalSegmentLength - m_body[i+1].vecPos) * sv_hydraBendTension.GetFloat();
			length = delta.Length();
			if (length > sv_hydraBendDelta.GetFloat())
			{
				delta = delta * (sv_hydraBendDelta.GetFloat() / length);
			}
			m_body[i+1].vecDelta += delta;
			//NDebugOverlay::Line( m_body[i+1].vecPos, m_body[i+1].vecPos + delta, 255, 0, 0, true, .1);
		}

		if (i-1 >= iFirst)
		{
			// towards tail
			delta = (m_body[i].vecPos - v3 * flGoalSegmentLength - m_body[i-1].vecPos) * sv_hydraBendTension.GetFloat();
			length = delta.Length();
			if (length > sv_hydraBendDelta.GetFloat())
			{
				delta = delta * (sv_hydraBendDelta.GetFloat() / length);
			}
			m_body[i-1].vecDelta += delta * 0.8;
			//NDebugOverlay::Line( m_body[i-1].vecPos, m_body[i-1].vecPos + delta, 255, 0, 0, true, .1);
		}
	}

	m_body[0].vecDelta = Vector( 0, 0, 0 );
	m_body[1].vecDelta = Vector( 0, 0, 0 );

	// normal gravity forces
	for (i = iFirst; i <= iLast; i++)
	{
		if (!m_body[i].bStuck)
		{
			m_body[i].vecDelta.z -= 3.84 * 0.2;
		}
	}

⌨️ 快捷键说明

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