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

📄 hl1_npc_bigmomma.cpp

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

	SetNavType( NAV_GROUND );
	SetSolid( SOLID_BBOX );
	AddSolidFlags( FSOLID_NOT_STANDABLE );
	SetMoveType( MOVETYPE_STEP );
	
	m_bloodColor = BLOOD_COLOR_GREEN;
	m_iHealth = 150 * sk_bigmomma_health_factor.GetFloat();

	SetHullType( HULL_WIDE_HUMAN );
	SetHullSizeNormal();

	CapabilitiesAdd( bits_CAP_MOVE_GROUND );
	CapabilitiesAdd( bits_CAP_INNATE_RANGE_ATTACK1 | bits_CAP_INNATE_MELEE_ATTACK1 | bits_CAP_INNATE_MELEE_ATTACK2 );

//	pev->view_ofs		= Vector ( 0, 0, 128 );// position of the eyes relative to monster's origin.
	m_flFieldOfView	= 0.3;// indicates the width of this monster's forward view cone ( as a dotproduct result )
	m_NPCState = NPC_STATE_NONE;

	SetRenderColor( 255, 255, 255, 255 );

	m_bDoneWithPath = false;

	m_nodeTime = 0.0f;

	m_iszTarget = m_iszNetName;

	NPCInit();

	BaseClass::Spawn();
}

//=========================================================
// Precache - precaches all resources this monster needs
//=========================================================
void CNPC_BigMomma::Precache()
{
	engine->PrecacheModel("models/big_mom.mdl");

	PRECACHE_SOUND_ARRAY( pChildDieSounds );
	PRECACHE_SOUND_ARRAY( pSackSounds );
	PRECACHE_SOUND_ARRAY( pDeathSounds );
	PRECACHE_SOUND_ARRAY( pAttackSounds );
	PRECACHE_SOUND_ARRAY( pAttackHitSounds );
	PRECACHE_SOUND_ARRAY( pBirthSounds );
	PRECACHE_SOUND_ARRAY( pAlertSounds );
	PRECACHE_SOUND_ARRAY( pPainSounds );
	PRECACHE_SOUND_ARRAY( pFootSounds );

	UTIL_PrecacheOther( BIG_CHILDCLASS );

	// TEMP: Squid
	engine->PrecacheModel("sprites/mommaspit.vmt");// spit projectile.
	gSpitSprite = engine->PrecacheModel("sprites/mommaspout.vmt");// client side spittle.
	gSpitDebrisSprite = engine->PrecacheModel("sprites/mommablob.vmt" );

	enginesound->PrecacheSound( "bullchicken/bc_acid1.wav" );
	enginesound->PrecacheSound( "bullchicken/bc_spithit1.wav" );
	enginesound->PrecacheSound( "bullchicken/bc_spithit2.wav" );
}

//=========================================================
// SetYawSpeed - allows each sequence to have a different
// turn rate associated with it.
//=========================================================
float CNPC_BigMomma::MaxYawSpeed ( void )
{
	float ys = 90.0f;

	switch ( GetActivity() )
	{
	case ACT_IDLE:
		ys = 100.0f;
		break;
	default:
		ys = 90.0f;
	}
	
	return ys;
}

void CNPC_BigMomma::Activate( void )
{
	if ( GetTarget() == NULL )
		 Remember( bits_MEMORY_ADVANCE_NODE );	// Start 'er up

	BaseClass::Activate();
}

void CNPC_BigMomma::NodeStart( string_t iszNextNode )
{
	m_iszTarget = iszNextNode;

	const char *pTargetName = STRING( m_iszTarget );

	CBaseEntity *pTarget = NULL;

	if ( pTargetName )
		 pTarget = gEntList.FindEntityByName( NULL, pTargetName, NULL );

	if ( pTarget == NULL )
	{
		//Msg( "BM: Finished the path!!\n" );
		m_bDoneWithPath = true;
		return;
	}

	SetTarget( pTarget );
}


void CNPC_BigMomma::NodeReach( void )
{
	CInfoBM *pTarget = (CInfoBM*)GetTarget();

	Forget( bits_MEMORY_ADVANCE_NODE );

	if ( !pTarget )
		return;

	if ( pTarget->m_iHealth >= 1 )
		 m_iMaxHealth = m_iHealth = pTarget->m_iHealth * sk_bigmomma_health_factor.GetFloat();

	if ( !HasMemory( bits_MEMORY_FIRED_NODE ) )
	{
		if ( pTarget )
		{
			 pTarget->m_OnAnimationEvent.FireOutput( this, this );
		}
	}

	Forget( bits_MEMORY_FIRED_NODE );

	m_iszTarget = pTarget->m_target;
	
	if ( pTarget->m_iHealth == 0 )
		 Remember( bits_MEMORY_ADVANCE_NODE );	// Move on if no health at this node
	else
	{
		 GetNavigator()->ClearGoal();
	}
}


void CNPC_BigMomma::TraceAttack( const CTakeDamageInfo &info, const Vector &vecDir, trace_t *ptr )
{
	CTakeDamageInfo dmgInfo = info;
	float flDamage = dmgInfo.GetDamage();

	if ( ptr->hitbox <= 9  )
	{
		// didn't hit the sack?
		if ( m_flDmgTime != gpGlobals->curtime || (RandomInt( 0, 10 ) < 1) )
		{
			CEffectData data;
			
			data.m_vOrigin = ptr->endpos;
			data.m_vAngles = GetAbsAngles();
			
			data.m_vNormal = ( vecDir  ) * -1;

			DispatchEffect( "ManhackSparks", data );


			m_flDmgTime = gpGlobals->curtime;
		}

		flDamage = 0.1;// don't hurt the monster much, but allow bits_COND_LIGHT_DAMAGE to be generated
	}
	else 
	{
		SpawnBlood( ptr->endpos + ptr->plane.normal * 15, m_bloodColor, 100 );

		if ( gpGlobals->curtime > m_painSoundTime )
		{
			m_painSoundTime = gpGlobals->curtime + RandomInt(1, 3);
						
			CPASAttenuationFilter filter( this );
			EmitSound( filter, entindex(), CHAN_VOICE, RANDOM_SOUND_ARRAY( pPainSounds ), 1.0f, ATTN_NORM, 0, 100 );
			
			enginesound->EmitSound( filter, entindex(), CHAN_VOICE, pPainSounds[ random->RandomInt(0,ARRAYSIZE(pPainSounds)-1) ], 1.0, ATTN_NORM, 0, 100 );
		}
	}

	BaseClass::TraceAttack( info, vecDir, ptr );
}


int CNPC_BigMomma::OnTakeDamage( const CTakeDamageInfo &info )
{
	float flDamage = info.GetDamage();

	// Don't take any acid damage -- BigMomma's mortar is acid
	if ( info.GetDamageType() & DMG_ACID )
	{
		CTakeDamageInfo subInfo = info;
		subInfo.SetDamage( 0 );
		return BaseClass::OnTakeDamage( subInfo ); 
	}
	
	//Hacky McHack
	if ( GetTask()->iTask == TASK_PLAY_NODE_PRESEQUENCE || GetTask()->iTask == TASK_PLAY_NODE_SEQUENCE )
		 return 0;

	if ( m_bDoneWithPath == false )
	{
		if ( m_iHealth <= flDamage )
		{
			m_iHealth = flDamage + 1;
			Remember( bits_MEMORY_ADVANCE_NODE );
			//Msg( "BM: Finished node health!!!\n" );
		}
	}

	return BaseClass::OnTakeDamage( info );
}

bool CNPC_BigMomma::ShouldGoToNode( void )
{
	if ( HasMemory( bits_MEMORY_ADVANCE_NODE ) )
	{
		if ( m_nodeTime < gpGlobals->curtime )
			 return true;
	}
	return false;
}


int CNPC_BigMomma::SelectSchedule( void )
{
	if ( ShouldGoToNode() )
	{
		return SCHED_BIG_NODE;
	}

	return BaseClass::SelectSchedule();
}


void CNPC_BigMomma::StartTask( const Task_t *pTask )
{
	switch ( pTask->iTask )
	{
	case TASK_CHECK_NODE_PROXIMITY:
		{

		}

		break;
	case TASK_FIND_NODE:
		{
			CBaseEntity *pTarget = GetTarget();

			if ( !HasMemory( bits_MEMORY_ADVANCE_NODE ) )
			{
				if ( pTarget )
					 m_iszTarget = pTarget->m_target;
			}

			NodeStart( m_iszTarget );
			TaskComplete();
			//Msg( "BM: Found node %s\n", STRING( m_iszTarget ) );
		}
		break;

	case TASK_NODE_DELAY:
		m_nodeTime = gpGlobals->curtime + pTask->flTaskData;
		TaskComplete();
		//Msg( "BM: FAIL! Delay %.2f\n", pTask->flTaskData );
		break;

	case TASK_PROCESS_NODE:
		//Msg( "BM: Reached node %s\n", STRING( m_iszTarget ) );
		NodeReach();
		TaskComplete();
		break;

	case TASK_PLAY_NODE_PRESEQUENCE:
	case TASK_PLAY_NODE_SEQUENCE:
		{
			const char *pSequence = NULL;
			int	iSequence;

			if ( pTask->iTask == TASK_PLAY_NODE_SEQUENCE )
				pSequence = GetNodeSequence();
			else
				pSequence = GetNodePresequence();

			//Msg( "BM: Playing node sequence %s\n", pSequence );

			if ( pSequence ) //ugh
			{
				iSequence = LookupSequence( pSequence );

				if ( iSequence != -1 )
				{
					SetIdealActivity( ACT_DO_NOT_DISTURB );
					SetSequence( iSequence );
					m_flCycle = 0.0f;

					ResetSequenceInfo();
					//Msg( "BM: Sequence %s %f\n", GetNodeSequence(), gpGlobals->curtime );
					return;
				}
			}
			TaskComplete();
		}
		break;

	case TASK_NODE_YAW:
		GetMotor()->SetIdealYaw( GetNodeYaw() );
		TaskComplete();
		break;

	case TASK_WAIT_NODE:
		m_flWait = gpGlobals->curtime + GetNodeDelay();

		/*if ( GetTarget() && GetTarget()->GetSpawnFlags() & SF_INFOBM_WAIT )
			Msg( "BM: Wait at node %s forever\n", STRING( m_iszTarget) );
		else
			Msg( "BM: Wait at node %s for %.2f\n", STRING( m_iszTarget ), GetNodeDelay() );*/
		break;


	case TASK_MOVE_TO_NODE_RANGE:
		{
			CBaseEntity *pTarget = GetTarget();

			if ( !pTarget )
				TaskFail( FAIL_NO_TARGET );
			else
			{
				if ( ( pTarget->GetAbsOrigin() - GetAbsOrigin() ).Length() < GetNodeRange() )
					TaskComplete();
				else
				{
					Activity act = ACT_WALK;
					if ( pTarget->GetSpawnFlags() & SF_INFOBM_RUN )
						 act = ACT_RUN;

					AI_NavGoal_t goal( GOALTYPE_TARGETENT, vec3_origin, act );

					if ( !GetNavigator()->SetGoal( goal ) )
					{
						TaskFail( NO_TASK_FAILURE );
					}
				}
			}
		}
		//Msg( "BM: Moving to node %s\n", STRING( m_iszTarget ) );

		break;

	case TASK_MELEE_ATTACK1:
		{

		// Play an attack sound here

		CPASAttenuationFilter filter( this );
		EmitSound( filter, entindex(), CHAN_VOICE, RANDOM_SOUND_ARRAY( pAttackSounds ), 1.0f, ATTN_NORM, 0, PITCH_NORM );

		BaseClass::StartTask( pTask );
		}
		
		break;

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

//=========================================================
// RunTask
//=========================================================
void CNPC_BigMomma::RunTask( const Task_t *pTask )
{
	switch ( pTask->iTask )
	{
	case TASK_CHECK_NODE_PROXIMITY:
		{
			float distance;

			if ( GetTarget() == NULL )
				TaskFail( FAIL_NO_TARGET );
			else
			{
				if ( GetNavigator()->IsGoalActive() )
				{
					distance = ( GetTarget()->GetAbsOrigin() - GetAbsOrigin() ).Length2D();
					// Set the appropriate activity based on an overlapping range
					// overlap the range to prevent oscillation
					if ( distance < GetNodeRange() )
					{
						//Msg( "BM: Reached node PROXIMITY!!\n" );
						TaskComplete();
						GetNavigator()->ClearGoal();		// Stop moving
					}
				}
				else
					TaskComplete();
			}
		}

		break;

	case TASK_WAIT_NODE:
		if ( GetTarget() != NULL && (GetTarget()->GetSpawnFlags() & SF_INFOBM_WAIT) )
			return;

		if ( gpGlobals->curtime > m_flWaitFinished )
			TaskComplete();
		//Msg( "BM: The WAIT is over!\n" );
		break;

	case TASK_PLAY_NODE_PRESEQUENCE:
	case TASK_PLAY_NODE_SEQUENCE:

		if ( IsSequenceFinished() )
		{
			CBaseEntity *pTarget = NULL;

			if (  GetTarget() )
				 pTarget = gEntList.FindEntityByName( NULL, STRING( GetTarget()->m_target ), NULL );

			if ( pTarget )
			{
				 SetActivity( ACT_IDLE );
				 TaskComplete();
			}
		}
		
		break;

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

//=========================================================
// HandleAnimEvent - catches the monster-specific messages
// that occur when tagged animation frames are played.
//
// Returns number of events handled, 0 if none.
//=========================================================
void CNPC_BigMomma::HandleAnimEvent( animevent_t *pEvent )
{
	CPASAttenuationFilter filter( this );

	Vector vecFwd, vecRight, vecUp;
	QAngle angles;
	angles = GetAbsAngles();
	AngleVectors( angles, &vecFwd, &vecRight, &vecUp );

	switch( pEvent->event )
	{
		case BIG_AE_MELEE_ATTACKBR:
		case BIG_AE_MELEE_ATTACKBL:
		case BIG_AE_MELEE_ATTACK1:
		{

⌨️ 快捷键说明

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