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

📄 hl1_npc_tentacle.cpp

📁 hl2 source code. Do not use it illegal.
💻 CPP
📖 第 1 页 / 共 2 页
字号:
	GetMotor()->UpdateYaw( MaxYawSpeed() );
	
	CSound *pSound = NULL;

	GetSenses()->Listen();
	m_BoneFollowerManager.UpdateBoneFollowers();

	// Listen will set this if there's something in my sound list
	if ( HeardAnything() )
		 pSound = GetSenses()->GetClosestSound( false );
	else
		 pSound = NULL;

	if ( pSound )
	{
		Vector vecDir;
		if ( gpGlobals->curtime - m_flPrevSoundTime < 0.5 )
		{
			float dt = gpGlobals->curtime - m_flPrevSoundTime;
			vecDir = pSound->GetSoundOrigin() + (pSound->GetSoundOrigin() - m_vecPrevSound) / dt - GetAbsOrigin();
		}
		else
		{
			vecDir = pSound->GetSoundOrigin() - GetAbsOrigin();
		}

		m_flPrevSoundTime = gpGlobals->curtime;
		m_vecPrevSound = pSound->GetSoundOrigin();

		m_flSoundYaw = VecToYaw ( vecDir ) - m_flInitialYaw;

		m_iSoundLevel = Level( vecDir.z );

		if (m_flSoundYaw < -180)
			m_flSoundYaw += 360;
		if (m_flSoundYaw > 180)
			m_flSoundYaw -= 360;

		// ALERT( at_console, "sound %d %.0f\n", m_iSoundLevel, m_flSoundYaw );
		if (m_flSoundTime < gpGlobals->curtime)
		{
			// play "I hear new something" sound
			char *sound = NULL;	

			switch( random->RandomInt( 0, 1 ) )
			{
				case 0: sound = "tentacle/te_alert1.wav"; break;
				case 1: sound = "tentacle/te_alert2.wav"; break;
			}

			 UTIL_EmitAmbientSound( this, GetAbsOrigin() + Vector( 0, 0, MyHeight()), sound, 1.0, SNDLVL_GUNFIRE, 0, 100);
		}
		m_flSoundTime = gpGlobals->curtime + random->RandomFloat( 5.0, 10.0 );
	}

	// clip ideal_yaw
	float dy = m_flSoundYaw;
	switch( GetSequence() )
	{
	case TENTACLE_ANIM_Floor_Rear:
	case TENTACLE_ANIM_Floor_Rear_Idle:
	case TENTACLE_ANIM_Lev1_Rear:
	case TENTACLE_ANIM_Lev1_Rear_Idle:
	case TENTACLE_ANIM_Lev2_Rear:
	case TENTACLE_ANIM_Lev2_Rear_Idle:
	case TENTACLE_ANIM_Lev3_Rear:
	case TENTACLE_ANIM_Lev3_Rear_Idle:
		if (dy < 0 && dy > -m_flMaxYaw)
			dy = -m_flMaxYaw;
		if (dy > 0 && dy < m_flMaxYaw)
			dy = m_flMaxYaw;
		break;
	default:
		if (dy < -m_flMaxYaw)
			dy = -m_flMaxYaw;
		if (dy > m_flMaxYaw)
			dy = m_flMaxYaw;
	}
	GetMotor()->SetIdealYaw( m_flInitialYaw + dy );

	if ( IsSequenceFinished() )
	{
		// ALERT( at_console, "%s done %d %d\n", STRING( pev->targetname ), pev->sequence, m_iGoalAnim );
		if ( m_iHealth <= 1)
		{
			m_iGoalAnim = TENTACLE_ANIM_Pit_Idle;

			if ( GetSequence() == TENTACLE_ANIM_Pit_Idle)
			{
				m_iHealth = 75;
			}
		}
		else if ( m_flSoundTime > gpGlobals->curtime )
		{
			if (m_flSoundYaw >= -(m_flMaxYaw + 30) && m_flSoundYaw <= (m_flMaxYaw + 30))
			{
				// strike
				switch ( m_iSoundLevel )
				{
					case 0:
						m_iGoalAnim = SelectWeightedSequence ( ACT_1030 );
						break;
					case 1:
						m_iGoalAnim = SelectWeightedSequence ( ACT_1031 );
						break;
					case 2:
						m_iGoalAnim = SelectWeightedSequence ( ACT_1032 );
						break;
					case 3:
						m_iGoalAnim = SelectWeightedSequence ( ACT_1033 );
						break;
				}
			}
			else if (m_flSoundYaw >= -m_flMaxYaw * 2 && m_flSoundYaw <= m_flMaxYaw * 2) 
			{
				// tap
				switch ( m_iSoundLevel )
				{
					case 0:
						m_iGoalAnim = SelectWeightedSequence ( ACT_1020 );
						break;
					case 1:
						m_iGoalAnim = SelectWeightedSequence ( ACT_1021 );
						break;
					case 2:
						m_iGoalAnim = SelectWeightedSequence ( ACT_1022 );
						break;
					case 3:
						m_iGoalAnim = SelectWeightedSequence ( ACT_1023 );
						break;
				}
			}
			else
			{
				// go into rear idle
				switch ( m_iSoundLevel )
				{
					case 0:
						m_iGoalAnim = SelectWeightedSequence ( ACT_1040 );
						break;
					case 1:
						m_iGoalAnim = SelectWeightedSequence ( ACT_1041 );
						break;
					case 2:
						m_iGoalAnim = SelectWeightedSequence ( ACT_1042 );
						break;
					case 3:
						m_iGoalAnim = SelectWeightedSequence ( ACT_1043 );
						break;
					case 4:
						m_iGoalAnim = SelectWeightedSequence ( ACT_1044 );
						break;
				}
			}
		}
		else if ( GetSequence() == TENTACLE_ANIM_Pit_Idle)
		{
			// stay in pit until hear noise
			m_iGoalAnim = TENTACLE_ANIM_Pit_Idle;
		}
		else if ( GetSequence() == m_iGoalAnim)
		{
			if ( MyLevel() >= 0 && gpGlobals->curtime < m_flSoundTime)
			{
				if ( random->RandomInt(0,9) < m_flSoundTime - gpGlobals->curtime )
				{
					// continue stike
					switch ( m_iSoundLevel )
					{
						case 0:
							m_iGoalAnim = SelectWeightedSequence ( ACT_1030 );
							break;
						case 1:
							m_iGoalAnim = SelectWeightedSequence ( ACT_1031 );
							break;
						case 2:
							m_iGoalAnim = SelectWeightedSequence ( ACT_1032 );
							break;
						case 3:
							m_iGoalAnim = SelectWeightedSequence ( ACT_1033 );
							break;
					}
				}
				else
				{
					// tap
					switch ( m_iSoundLevel )
					{
						case 0:
							m_iGoalAnim = SelectWeightedSequence ( ACT_1020 );
							break;
						case 1:
							m_iGoalAnim = SelectWeightedSequence ( ACT_1021 );
							break;
						case 2:
							m_iGoalAnim = SelectWeightedSequence ( ACT_1022 );
							break;
						case 3:
							m_iGoalAnim = SelectWeightedSequence ( ACT_1023 );
							break;
					}
				}
			}
			else if ( MyLevel( ) < 0 )
			{
				m_iGoalAnim = SelectWeightedSequence( ACT_1010 );
			}
			else
			{
				if (m_flNextSong < gpGlobals->curtime)
				{
					// play "I hear new something" sound
					char *sound = NULL;	

					switch( random->RandomInt( 0,1 ) )
					{
					case 0: sound = "tentacle/te_sing1.wav"; break;
					case 1: sound = "tentacle/te_sing2.wav"; break;
					}
	

					CPASAttenuationFilter filter( this );
					enginesound->EmitSound( filter, entindex(), CHAN_VOICE, sound, 1.0, SNDLVL_GUNFIRE);

					m_flNextSong = gpGlobals->curtime + random->RandomFloat( 10, 20 );
				}

				if (random->RandomInt(0,15) == 0)
				{
					// idle on new level
					switch ( random->RandomInt( 0, 3 ) )
					{
						case 0:
							m_iGoalAnim = SelectWeightedSequence ( ACT_1010 );
							break;
						case 1:
							m_iGoalAnim = SelectWeightedSequence ( ACT_1011 );
							break;
						case 2:
							m_iGoalAnim = SelectWeightedSequence ( ACT_1012 );
							break;
						case 3:
							m_iGoalAnim = SelectWeightedSequence ( ACT_1013 );
							break;
					}
				}
				else if ( random->RandomInt( 0, 3 ) == 0 )
				{
					// tap
					switch ( MyLevel() )
					{
						case 0:
							m_iGoalAnim = SelectWeightedSequence ( ACT_1020 );
							break;
						case 1:
							m_iGoalAnim = SelectWeightedSequence ( ACT_1021 );
							break;
						case 2:
							m_iGoalAnim = SelectWeightedSequence ( ACT_1022 );
							break;
						case 3:
							m_iGoalAnim = SelectWeightedSequence ( ACT_1023 );
							break;
					}
				}
				else
				{
					// idle
					switch ( MyLevel() )
					{
						case 0:
							m_iGoalAnim = SelectWeightedSequence ( ACT_1010 );
							break;
						case 1:
							m_iGoalAnim = SelectWeightedSequence ( ACT_1011 );
							break;
						case 2:
							m_iGoalAnim = SelectWeightedSequence ( ACT_1012 );
							break;
						case 3:
							m_iGoalAnim = SelectWeightedSequence ( ACT_1013 );
							break;
					}
				}
			}
			if (m_flSoundYaw < 0)
				m_flSoundYaw += random->RandomFloat( 2, 8 );
			else
				m_flSoundYaw -= random->RandomFloat( 2, 8 );
		}

		SetSequence( FindTransitionSequence( GetSequence(), m_iGoalAnim, &m_iDir ) );
		

		if (m_iDir > 0)
		{
			m_flCycle = 0;
		}
		else
		{
			m_iDir = -1; // just to safe
			m_flCycle = 1.0f;
		}

		ResetSequenceInfo( );

		m_flFramerateAdj = random->RandomFloat( -0.2, 0.2 );
		m_flPlaybackRate = m_iDir * 1.0 + m_flFramerateAdj;

		switch( GetSequence() )
		{
		case TENTACLE_ANIM_Floor_Tap:
		case TENTACLE_ANIM_Lev1_Tap:
		case TENTACLE_ANIM_Lev2_Tap:
		case TENTACLE_ANIM_Lev3_Tap:
			{
				Vector vecSrc, v_forward;
				AngleVectors( GetAbsAngles(), &v_forward );

				trace_t tr1, tr2;

				vecSrc = GetAbsOrigin() + Vector( 0, 0, MyHeight() - 4);
				UTIL_TraceLine( vecSrc, vecSrc + v_forward * 512, MASK_NPCSOLID_BRUSHONLY, this, COLLISION_GROUP_NONE, &tr1 );

				vecSrc = GetAbsOrigin() + Vector( 0, 0, MyHeight() + 8);
				UTIL_TraceLine( vecSrc, vecSrc + v_forward * 512, MASK_NPCSOLID_BRUSHONLY, this, COLLISION_GROUP_NONE, &tr2 );

				// ALERT( at_console, "%f %f\n", tr1.flFraction * 512, tr2.flFraction * 512 );

				m_flTapRadius = SetPoseParameter( 0, random->RandomFloat( tr1.fraction * 512, tr2.fraction * 512 ) );
			}
			break;
		default:
			m_flTapRadius = 336; // 400 - 64
			break;
		}
		SetViewOffset( Vector( 0, 0, MyHeight() ) );
		// ALERT( at_console, "seq %d\n", pev->sequence );
	}

	if (m_flPrevSoundTime + 2.0 > gpGlobals->curtime)
	{
		// 1.5 normal speed if hears sounds
		m_flPlaybackRate = m_iDir * 1.5 + m_flFramerateAdj;
	}
	else if (m_flPrevSoundTime + 5.0 > gpGlobals->curtime)
	{
		// slowdown to normal
		m_flPlaybackRate = m_iDir + m_iDir * (5 - (gpGlobals->curtime - m_flPrevSoundTime)) / 2 + m_flFramerateAdj;
	}
}

void CNPC_Tentacle::HandleAnimEvent( animevent_t *pEvent )
{
	char *sound = NULL;

	switch( pEvent->event )
	{
	case 1:	// bang 
		{
			Vector vecSrc;
			QAngle angAngles;
			GetAttachment( "0", vecSrc, angAngles );

			// Vector vecSrc = GetAbsOrigin() + m_flTapRadius * Vector( cos( GetAbsAngles().y * (3.14192653 / 180.0) ), sin( GetAbsAngles().y * (M_PI / 180.0) ), 0.0 );

			// vecSrc.z += MyHeight( );

			switch( m_iTapSound )
			{
			case TE_SILO:
				UTIL_EmitAmbientSound( this, vecSrc, RANDOM_SOUND_ARRAY( pHitSilo ), 1.0, SNDLVL_GUNFIRE, 0, 100);
				break;
			case TE_NONE:
				break;
			case TE_DIRT:
				UTIL_EmitAmbientSound( this, vecSrc, RANDOM_SOUND_ARRAY( pHitDirt ), 1.0, SNDLVL_GUNFIRE, 0, 100);
				break;
			case TE_WATER:
				UTIL_EmitAmbientSound( this, vecSrc, RANDOM_SOUND_ARRAY( pHitWater ), 1.0, SNDLVL_GUNFIRE, 0, 100);
				break;
			}
		}
		break;

	case 3: // start killing swing
		m_iHitDmg = 200;
		// UTIL_EmitAmbientSound(this, GetAbsOrigin() + Vector( 0, 0, MyHeight()), "tentacle/te_swing1.wav", 1.0, SNDLVL_NORM, 0, 100);
		break;

	case 4: // end killing swing
		m_iHitDmg = 25;
		break;

	case 5: // just "whoosh" sound
		// UTIL_EmitAmbientSound(this, GetAbsOrigin() + Vector( 0, 0, MyHeight()), "tentacle/te_swing2.wav", 1.0, SNDLVL_NORM, 0, 100);
		break;

	case 2:	// tap scrape
	case 6: // light tap
		{
			Vector vecSrc = GetAbsOrigin() + m_flTapRadius * Vector( cos( GetAbsAngles().y * (M_PI / 180.0) ), sin( GetAbsAngles().y * (M_PI / 180.0) ), 0.0 );

			vecSrc.z += MyHeight( );

			float flVol = random->RandomFloat( 0.3, 0.5 );

			switch( m_iTapSound )
			{
			case TE_SILO:
				UTIL_EmitAmbientSound( this, vecSrc, RANDOM_SOUND_ARRAY( pHitSilo ), flVol, SNDLVL_GUNFIRE, 0, 100);
				break;
			case TE_NONE:
				break;
			case TE_DIRT:
				UTIL_EmitAmbientSound( this, vecSrc, RANDOM_SOUND_ARRAY( pHitDirt ), flVol, SNDLVL_GUNFIRE, 0, 100);
				break;
			case TE_WATER:
				UTIL_EmitAmbientSound( this, vecSrc, RANDOM_SOUND_ARRAY( pHitWater ), flVol, SNDLVL_GUNFIRE, 0, 100);
				break;
			}
		}
		break;


	case 7: // roar
		switch( random->RandomInt(0,1) )
		{
		case 0: sound = "tentacle/te_roar1.wav"; break;
		case 1: sound = "tentacle/te_roar2.wav"; break;
		}

		UTIL_EmitAmbientSound( this, GetAbsOrigin() + Vector( 0, 0, MyHeight()), sound, 1.0, SNDLVL_GUNFIRE, 0, 100);
		break;

	case 8: // search
		switch( random->RandomInt(0,1) )
		{
		case 0: sound = "tentacle/te_search1.wav"; break;
		case 1: sound = "tentacle/te_search2.wav"; break;
		}

		UTIL_EmitAmbientSound( this, GetAbsOrigin() + Vector( 0, 0, MyHeight()), sound, 1.0, SNDLVL_GUNFIRE, 0, 100);
		break;

	case 9: // swing
		switch( random->RandomInt(0,1) )
		{
		case 0: sound = "tentacle/te_move1.wav"; break;
		case 1: sound = "tentacle/te_move2.wav"; break;
		}

		UTIL_EmitAmbientSound( this, GetAbsOrigin() + Vector( 0, 0, MyHeight()), sound, 1.0, SNDLVL_GUNFIRE, 0, 100);
		break;

	default:
		BaseClass::HandleAnimEvent( pEvent );
	}
}

void CNPC_Tentacle::HitTouch( CBaseEntity *pOther )
{
	trace_t tr = CBaseEntity::GetTouchTrace( );

	if (m_flHitTime > gpGlobals->curtime)
		return;

	// only look at the ones where the player hit me
	if( pOther == NULL || pOther->GetModelIndex() == GetModelIndex() || (pOther->GetSolidFlags() & FSOLID_TRIGGER) )
		 return;

	//Right now the BoneFollower will always be hit in box 0, and 
	//will pass that to us. Make *any* touch by the physics objects a kill
	//as the ragdoll only covers the top portion of the tentacle.
	CTakeDamageInfo info( this, this, m_iHitDmg, DMG_CLUB );
	CalculateMeleeDamageForce( &info, (pOther->GetAbsOrigin() - GetAbsOrigin()), pOther->GetAbsOrigin() );
	pOther->TakeDamage( info );

	m_flHitTime = gpGlobals->curtime + 0.5;
}

int CNPC_Tentacle::OnTakeDamage( const CTakeDamageInfo &info )
{
	CTakeDamageInfo i = info;

	//Don't allow the tentacle to die. Instead set health to 1, so we can do our own death and rebirth
	if( i.GetDamage() > m_iHealth )
	{
		i.SetDamage( 0.0f );
		m_iHealth = 1;
	}

	return BaseClass::OnTakeDamage( i );
}

bool CNPC_Tentacle::CreateVPhysics( void )
{
	BaseClass::CreateVPhysics();

	IPhysicsObject *pPhysics = VPhysicsGetObject();
	if( pPhysics )
	{
		unsigned short flags = pPhysics->GetCallbackFlags();

		flags |= CALLBACK_GLOBAL_TOUCH;

		pPhysics->SetCallbackFlags( flags );
	}
	m_BoneFollowerManager.InitBoneFollowers( this, ARRAYSIZE(pTentacleFollowerBoneNames), pTentacleFollowerBoneNames );

	return true;
}

//------------------------------------------------------------------------------
//
// Schedules
//
//------------------------------------------------------------------------------

AI_BEGIN_CUSTOM_NPC( monster_tentacle, CNPC_Tentacle )

	DECLARE_ACTIVITY( ACT_1010 )
	DECLARE_ACTIVITY( ACT_1011 )
	DECLARE_ACTIVITY( ACT_1012 )
	DECLARE_ACTIVITY( ACT_1013 )

	DECLARE_ACTIVITY( ACT_1020 )
	DECLARE_ACTIVITY( ACT_1021 )
	DECLARE_ACTIVITY( ACT_1022 )
	DECLARE_ACTIVITY( ACT_1023 )

	DECLARE_ACTIVITY( ACT_1030 )
	DECLARE_ACTIVITY( ACT_1031 )
	DECLARE_ACTIVITY( ACT_1032 )
	DECLARE_ACTIVITY( ACT_1033 )

	DECLARE_ACTIVITY( ACT_1040 )
	DECLARE_ACTIVITY( ACT_1041 )
	DECLARE_ACTIVITY( ACT_1042 )
	DECLARE_ACTIVITY( ACT_1043 )
	DECLARE_ACTIVITY( ACT_1044 )

AI_END_CUSTOM_NPC()

⌨️ 快捷键说明

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