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

📄 hl1_npc_leech.cpp

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

#if DEBUG_BEAMS
	NDebugOverlay::Line( GetLocalOrigin(), GetLocalOrigin() + Vector( 0, 0, m_bottom ), 0, 255, 0, false, 0.1f );
	NDebugOverlay::Line( GetLocalOrigin(), GetLocalOrigin() + Vector( 0, 0, m_top ), 0, 255, 255, false, 0.1f );
#endif

	// Chop off 20% of the outside range
	float newBottom = m_bottom * 0.8 + m_top * 0.2;
	m_top = m_bottom * 0.2 + m_top * 0.8;
	m_bottom = newBottom;
	m_height = random->RandomFloat( m_bottom, m_top );
	m_waterTime = gpGlobals->curtime + random->RandomFloat( 5, 7 );
}

void CNPC_Leech::SwimThink( void )
{
	trace_t			tr;
	float			flLeftSide;
	float			flRightSide;
	float			targetSpeed;
	float			targetYaw = 0;
	CBaseEntity		*pTarget;

	/*if ( !UTIL_FindClientInPVS( edict() ) )
	{
		m_flNextThink = gpGlobals->curtime + random->RandomFloat( 1.0f, 1.5f );
		SetAbsVelocity( vec3_origin );
		return;
	}
	else*/
		SetNextThink( gpGlobals->curtime + 0.1 );

	targetSpeed = LEECH_SWIM_SPEED;

	if ( m_waterTime < gpGlobals->curtime )
		RecalculateWaterlevel();

	if ( m_stateTime < gpGlobals->curtime )
		SwitchLeechState();

	ClearCondition( COND_CAN_MELEE_ATTACK1 );

	switch( m_NPCState )
	{
	case NPC_STATE_COMBAT:
		pTarget = GetEnemy();
		if ( !pTarget )
			SwitchLeechState();
		else
		{
			// Chase the enemy's eyes
			m_height = pTarget->GetLocalOrigin().z + pTarget->GetViewOffset().z - 5;
			// Clip to viable water area
			if ( m_height < m_bottom )
				m_height = m_bottom;
			else if ( m_height > m_top )
				m_height = m_top;
			Vector location = pTarget->GetLocalOrigin() - GetLocalOrigin();
			location.z += (pTarget->GetViewOffset().z);
			if ( location.Length() < 40 )
				SetCondition( COND_CAN_MELEE_ATTACK1 );
			// Turn towards target ent
			targetYaw = UTIL_VecToYaw( location );

			QAngle vTestAngle = GetAbsAngles();
			
			targetYaw = UTIL_AngleDiff( targetYaw, UTIL_AngleMod( GetAbsAngles().y ) );

			if ( targetYaw < (-LEECH_TURN_RATE*0.75) )
				targetYaw = (-LEECH_TURN_RATE*0.75);
			else if ( targetYaw > (LEECH_TURN_RATE*0.75) )
				targetYaw = (LEECH_TURN_RATE*0.75);
			else
				targetSpeed *= 2;
		}

		break;

	default:
		if ( m_zTime < gpGlobals->curtime )
		{
			float newHeight = random->RandomFloat( m_bottom, m_top );
			m_height = 0.5 * m_height + 0.5 * newHeight;
			m_zTime = gpGlobals->curtime + random->RandomFloat( 1, 4 );
		}
		if ( random->RandomInt( 0, 100 ) < 10 )
			targetYaw = random->RandomInt( -30, 30 );
		pTarget = NULL;
		// oldorigin test
		if ( ( GetLocalOrigin() - m_oldOrigin ).Length() < 1 )
		{
			// If leech didn't move, there must be something blocking it, so try to turn
			m_sideTime = 0;
		}

		break;
	}

	m_obstacle = ObstacleDistance( pTarget );
	m_oldOrigin = GetLocalOrigin();
	if ( m_obstacle < 0.1 )
		m_obstacle = 0.1;

	Vector vForward, vRight;

	AngleVectors( GetAbsAngles(), &vForward, &vRight, NULL );

	// is the way ahead clear?
	if ( m_obstacle == 1.0 )
	{
		// if the leech is turning, stop the trend.
		if ( m_flTurning != 0 )
		{
			m_flTurning = 0;
		}

		m_fPathBlocked = FALSE;
		m_flSpeed = UTIL_Approach( targetSpeed, m_flSpeed, LEECH_SWIM_ACCEL * LEECH_FRAMETIME );
		SetAbsVelocity( vForward * m_flSpeed );

	}
	else
	{
		m_obstacle = 1.0 / m_obstacle;
		// IF we get this far in the function, the leader's path is blocked!
		m_fPathBlocked = TRUE;

		if ( m_flTurning == 0 )// something in the way and leech is not already turning to avoid
		{
			Vector vecTest;
			// measure clearance on left and right to pick the best dir to turn
			vecTest = GetLocalOrigin() + ( vRight * LEECH_SIZEX) + ( vForward * LEECH_CHECK_DIST);
			UTIL_TraceLine( GetLocalOrigin(), vecTest, MASK_SOLID, this, COLLISION_GROUP_NONE, &tr);
			flRightSide = tr.fraction;

			vecTest = GetLocalOrigin() + ( vRight * -LEECH_SIZEX) + ( vForward * LEECH_CHECK_DIST);
			UTIL_TraceLine( GetLocalOrigin(), vecTest, MASK_SOLID, this, COLLISION_GROUP_NONE, &tr);
			
			flLeftSide = tr.fraction;

			// turn left, right or random depending on clearance ratio
			float delta = (flRightSide - flLeftSide);
			if ( delta > 0.1 || (delta > -0.1 && random->RandomInt( 0,100 ) < 50 ) )
				m_flTurning = -LEECH_TURN_RATE;
			else
				m_flTurning = LEECH_TURN_RATE;
		}

		m_flSpeed = UTIL_Approach( -(LEECH_SWIM_SPEED*0.5), m_flSpeed, LEECH_SWIM_DECEL * LEECH_FRAMETIME * m_obstacle );
		SetAbsVelocity( vForward * m_flSpeed );
	}
	
	GetMotor()->SetIdealYaw( m_flTurning );
	UpdateMotion();
}

//
// ObstacleDistance - returns normalized distance to obstacle
//
float CNPC_Leech::ObstacleDistance( CBaseEntity *pTarget )
{
	trace_t			tr;
	Vector			vecTest;
	Vector			vForward, vRight;

	// use VELOCITY, not angles, not all boids point the direction they are flying
	//Vector vecDir = UTIL_VecToAngles( pev->velocity );
	QAngle tmp = GetAbsAngles();
	tmp.x = -tmp.x;
	AngleVectors ( tmp, &vForward, &vRight, NULL );

	// check for obstacle ahead
	vecTest = GetLocalOrigin() + vForward * LEECH_CHECK_DIST;
	UTIL_TraceLine( GetLocalOrigin(), vecTest, MASK_SOLID, this, COLLISION_GROUP_NONE, &tr);

	if ( tr.startsolid )
	{
		m_flSpeed = -LEECH_SWIM_SPEED * 0.5;
	}

	if ( tr.fraction != 1.0 )
	{
		if ( (pTarget == NULL || tr.m_pEnt != pTarget ) )
		{
			return tr.fraction;
		}
		else
		{
			if ( fabs( m_height - GetLocalOrigin().z ) > 10 )
				return tr.fraction;
		}
	}

	if ( m_sideTime < gpGlobals->curtime )
	{
		// extra wide checks
		vecTest = GetLocalOrigin() + vRight * LEECH_SIZEX * 2 + vForward * LEECH_CHECK_DIST;
		UTIL_TraceLine( GetLocalOrigin(), vecTest, MASK_SOLID, this, COLLISION_GROUP_NONE, &tr);

		if (tr.fraction != 1.0)
			return tr.fraction;

		vecTest = GetLocalOrigin() - vRight * LEECH_SIZEX * 2 + vForward * LEECH_CHECK_DIST;
		UTIL_TraceLine( GetLocalOrigin(), vecTest, MASK_SOLID, this, COLLISION_GROUP_NONE, &tr);
		if (tr.fraction != 1.0)
			return tr.fraction;

		// Didn't hit either side, so stop testing for another 0.5 - 1 seconds
		m_sideTime = gpGlobals->curtime + random->RandomFloat(0.5,1);
	}

	return 1.0;
}

void CNPC_Leech::UpdateMotion( void )
{
	float flapspeed = ( m_flSpeed - m_flAccelerate) / LEECH_ACCELERATE;
	m_flAccelerate = m_flAccelerate * 0.8 + m_flSpeed * 0.2;

	if (flapspeed < 0) 
		flapspeed = -flapspeed;
	flapspeed += 1.0;
	if (flapspeed < 0.5) 
		flapspeed = 0.5;
	if (flapspeed > 1.9) 
		flapspeed = 1.9;

	m_flPlaybackRate = flapspeed;

	QAngle vAngularVelocity = GetLocalAngularVelocity();
	QAngle vAngles = GetLocalAngles();

	if ( !m_fPathBlocked )
		vAngularVelocity.y = GetMotor()->GetIdealYaw();
	else
		vAngularVelocity.y = GetMotor()->GetIdealYaw() * m_obstacle;

	if ( vAngularVelocity.y > 150 )
		SetIdealActivity( ACT_TURN_LEFT );
	else if ( vAngularVelocity.y < -150 )
		SetIdealActivity( ACT_TURN_RIGHT );
	else
		SetIdealActivity( ACT_SWIM );

	// lean
	float targetPitch, delta;
	delta = m_height - GetLocalOrigin().z;

/*	if ( delta < -10 )
		targetPitch = -30;
	else if ( delta > 10 )
		targetPitch = 30;
	else*/
		targetPitch = 0;

	vAngles.x = UTIL_Approach( targetPitch, vAngles.x, 60 * LEECH_FRAMETIME );

	// bank
	vAngularVelocity.z = - ( vAngles.z + (vAngularVelocity.y * 0.25));

	if ( m_NPCState == NPC_STATE_COMBAT && HasCondition( COND_CAN_MELEE_ATTACK1 ) )
		SetIdealActivity( ACT_MELEE_ATTACK1 );

	// Out of water check
	if ( !GetWaterLevel() )
	{
		SetMoveType( MOVETYPE_FLYGRAVITY );
		SetIdealActivity( ACT_HOP );
		SetAbsVelocity( vec3_origin );

		// Animation will intersect the floor if either of these is non-zero
		vAngles.z = 0;
		vAngles.x = 0;

		if ( m_flPlaybackRate < 1.0 )
			 m_flPlaybackRate = 1.0;
	}
	else if ( GetMoveType() == MOVETYPE_FLYGRAVITY )
	{
		SetMoveType( MOVETYPE_FLY );
		RemoveFlag( FL_ONGROUND );

	//  TODO
		RecalculateWaterlevel();
		m_waterTime = gpGlobals->curtime + 2;	// Recalc again soon, water may be rising
	}

	if ( GetActivity() != GetIdealActivity() )
	{
		SetActivity ( GetIdealActivity() );
	}
	StudioFrameAdvance();
	
	DispatchAnimEvents ( this );

	SetLocalAngles( vAngles );
	SetLocalAngularVelocity( vAngularVelocity );

	Vector vForward, vRight;

	AngleVectors( vAngles, &vForward, &vRight, NULL );

#if DEBUG_BEAMS
	if ( m_fPathBlocked )
	{
		float color = m_obstacle * 30;
		if ( m_obstacle == 1.0 )
			color = 0;
		if ( color > 255 )
			color = 255;
		 NDebugOverlay::Line( GetLocalOrigin(), GetLocalOrigin() + vForward * LEECH_CHECK_DIST, 255, color, color, false, 0.1f );
	}
	else
		 NDebugOverlay::Line( GetLocalOrigin(), GetLocalOrigin() + vForward * LEECH_CHECK_DIST, 255, 255, 0, false, 0.1f );
		 
	NDebugOverlay::Line( GetLocalOrigin(), GetLocalOrigin() + vRight * (vAngularVelocity.y*0.25), 0, 0, 255, false, 0.1f );
#endif

}

void CNPC_Leech::Event_Killed( const CTakeDamageInfo &info )
{
	Vector			vecSplatDir;
	trace_t			tr;

	//ALERT(at_aiconsole, "Leech: killed\n");
	// tell owner ( if any ) that we're dead.This is mostly for MonsterMaker functionality.
	CBaseEntity *pOwner = GetOwnerEntity();
	if (pOwner)
		pOwner->DeathNotice( this );

	// When we hit the ground, play the "death_end" activity
	if ( GetWaterLevel() )
	{
		QAngle qAngles = GetAbsAngles();
		QAngle qAngularVel = GetLocalAngularVelocity();
		Vector  vOrigin = GetLocalOrigin();

		qAngles.z = 0;
		qAngles.x = 0;

		vOrigin.z += 1;

		SetAbsVelocity( vec3_origin );

		if ( random->RandomInt( 0, 99 ) < 70 )
			 qAngularVel.y = random->RandomInt( -720, 720 );

		SetAbsAngles( qAngles );
		SetLocalAngularVelocity( qAngularVel );
		SetAbsOrigin( vOrigin );

		
		SetGravity ( 0.02 );
		RemoveFlag( FL_ONGROUND );
		SetActivity( ACT_DIESIMPLE );
	}
	else
		SetActivity( ACT_DIEFORWARD );
	
	SetMoveType( MOVETYPE_FLYGRAVITY );
	m_takedamage = DAMAGE_NO;
	
	SetThink( &CNPC_Leech::DeadThink );
}

⌨️ 快捷键说明

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