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

📄 hl1_npc_scientist.cpp

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

	return false;
}

//=========================================================
// PainSound
//=========================================================
void CNPC_Scientist::PainSound ( void )
{
	if (gpGlobals->curtime < m_flPainTime )
		return;
	
	m_flPainTime = gpGlobals->curtime + random->RandomFloat( 0.5, 0.75 );

	CPASAttenuationFilter filter( this );

	switch (random->RandomInt( 0,4 ) )
	{
		case 0: enginesound->EmitSound( filter, entindex(), CHAN_VOICE, "scientist/sci_pain1.wav", 1, ATTN_NORM, 0, GetExpresser()->GetVoicePitch()); break;
		case 1: enginesound->EmitSound( filter, entindex(), CHAN_VOICE, "scientist/sci_pain2.wav", 1, ATTN_NORM, 0, GetExpresser()->GetVoicePitch()); break;
		case 2: enginesound->EmitSound( filter, entindex(), CHAN_VOICE, "scientist/sci_pain3.wav", 1, ATTN_NORM, 0, GetExpresser()->GetVoicePitch()); break;
		case 3: enginesound->EmitSound( filter, entindex(), CHAN_VOICE, "scientist/sci_pain4.wav", 1, ATTN_NORM, 0, GetExpresser()->GetVoicePitch()); break;
		case 4: enginesound->EmitSound( filter, entindex(), CHAN_VOICE, "scientist/sci_pain5.wav", 1, ATTN_NORM, 0, GetExpresser()->GetVoicePitch()); break;
	}
}

//=========================================================
// DeathSound 
//=========================================================
void CNPC_Scientist::DeathSound ( void )
{
	PainSound();
}


void CNPC_Scientist::Heal( void )
{
	if ( !CanHeal() )
		  return;

	Vector target = GetFollowTarget()->GetAbsOrigin() - GetAbsOrigin();
	if ( target.Length() > 100 )
		return;

	GetTarget()->TakeHealth( sk_scientist_heal.GetFloat(), DMG_GENERIC );
	// Don't heal again for 1 minute
	m_flHealTime = gpGlobals->curtime + 60;
}

int CNPC_Scientist::TranslateSchedule( int scheduleType )
{
	switch( scheduleType )
	{
	// Hook these to make a looping schedule
	case SCHED_TARGET_FACE:
		{
			int baseType;

			// call base class default so that scientist will talk
			// when 'used' 
			baseType = BaseClass::TranslateSchedule( scheduleType );

			if (baseType == SCHED_IDLE_STAND)
				return SCHED_TARGET_FACE;	// override this for different target face behavior
			else
				return baseType;
		}
		break;

	case SCHED_TARGET_CHASE:
		return SCHED_SCI_FOLLOWTARGET;
		break;

	case SCHED_IDLE_STAND:
		{
			int baseType;
				
			baseType = BaseClass::TranslateSchedule( scheduleType );

			if (baseType == SCHED_IDLE_STAND)
				return SCHED_SCI_IDLESTAND;	// override this for different target face behavior
			else
				return baseType;
		}
		break;
	}

	return BaseClass::TranslateSchedule( scheduleType );
}

Activity CNPC_Scientist::NPC_TranslateActivity( Activity newActivity )
{
	if ( GetFollowTarget() && GetEnemy() )
	{
		CBaseEntity *pEnemy = GetEnemy();

		int relationship = D_NU;

		// Nothing scary, just me and the player
		if ( pEnemy != NULL )
			 relationship = IRelationType( pEnemy );

		if ( relationship == D_HT || relationship == D_FR )
		{
			if ( newActivity == ACT_WALK )
				 return ACT_WALK_SCARED;
			else if ( newActivity == ACT_RUN )
				 return ACT_RUN_SCARED;
		}
	}

	return BaseClass::NPC_TranslateActivity( newActivity );
}

int CNPC_Scientist::SelectSchedule( void )
{
	// so we don't keep calling through the EHANDLE stuff
	CBaseEntity *pEnemy = GetEnemy();

	if ( GetFollowTarget() )
	{
		// so we don't keep calling through the EHANDLE stuff
		CBaseEntity *pEnemy = GetEnemy();

		int relationship = D_NU;

		// Nothing scary, just me and the player
		if ( pEnemy != NULL )
			 relationship = IRelationType( pEnemy );

		if ( relationship != D_HT && relationship != D_FR )
		{
			// If I'm already close enough to my target
			if ( TargetDistance() <= 128 )
			{
				if ( CanHeal() )	// Heal opportunistically
					return SCHED_SCI_HEAL;
			}
		}
	}
	else if ( HasCondition( COND_PLAYER_PUSHING ) && !(GetSpawnFlags() & SF_NPC_PREDISASTER ) )
	{		// Player wants me to move
			return SCHED_HL1TALKER_FOLLOW_MOVE_AWAY;
	}

	if ( BehaviorSelectSchedule() )
	{
		return BaseClass::SelectSchedule();
	}

	
	
	if ( HasCondition( COND_HEAR_DANGER ) && m_NPCState != NPC_STATE_PRONE )
	{
		CSound *pSound;
		pSound = GetBestSound();

		if ( pSound && pSound->IsSoundType(SOUND_DANGER) )
			return SCHED_TAKE_COVER_FROM_BEST_SOUND;
	}

	switch( m_NPCState )
	{

	case NPC_STATE_ALERT:	
	case NPC_STATE_IDLE:

		if ( pEnemy )
		{
			if ( HasCondition( COND_SEE_ENEMY ) )
				m_flFearTime = gpGlobals->curtime;
			else if ( DisregardEnemy( pEnemy ) )		// After 15 seconds of being hidden, return to alert
			{
				SetEnemy( NULL );
				pEnemy = NULL;
			}
		}

		if ( HasCondition( COND_LIGHT_DAMAGE ) ||  HasCondition( COND_HEAVY_DAMAGE ) )
		{
			// flinch if hurt
			return SCHED_SMALL_FLINCH;
		}
	
		// Cower when you hear something scary
		if ( HasCondition( COND_HEAR_DANGER ) || HasCondition( COND_HEAR_COMBAT ) ) 
		{
			CSound *pSound;
			pSound = GetBestSound();
		
			if ( pSound )
			{
				if ( pSound->IsSoundType(SOUND_DANGER | SOUND_COMBAT) )
				{
					if ( gpGlobals->curtime - m_flFearTime > 3 )	// Only cower every 3 seconds or so
					{
						m_flFearTime = gpGlobals->curtime;		// Update last fear
						return SCHED_SCI_STARTLE;	// This will just duck for a second
					}
				}
			}
		}
		
		if ( GetFollowTarget() )
		{
			if ( !GetFollowTarget()->IsAlive() )
			{
				// UNDONE: Comment about the recently dead player here?
				StopFollowing();
				break;
			}
			
			int relationship = D_NU;

			// Nothing scary, just me and the player
			if ( pEnemy != NULL )
				 relationship = IRelationType( pEnemy );
			
			if ( relationship != D_HT )
			{
				return SCHED_TARGET_FACE;	// Just face and follow.
			}
			else	// UNDONE: When afraid, scientist won't move out of your way.  Keep This?  If not, write move away scared
			{
				if ( HasCondition( COND_NEW_ENEMY ) ) // I just saw something new and scary, react
					return SCHED_SCI_FEAR;					// React to something scary
				return SCHED_SCI_FACETARGETSCARED;	// face and follow, but I'm scared!
			}
		}

		// try to say something about smells
		TrySmellTalk();
		break;


	case NPC_STATE_COMBAT:

		if ( HasCondition( COND_NEW_ENEMY ) )
			return SCHED_SCI_FEAR;					// Point and scream!
		if ( HasCondition( COND_SEE_ENEMY ) )
			return SCHED_SCI_COVER;		// Take Cover
		
		if ( HasCondition( COND_HEAR_COMBAT ) || HasCondition( COND_HEAR_DANGER ) )
			 return SCHED_TAKE_COVER_FROM_BEST_SOUND;	// Cower and panic from the scary sound!
	
		return SCHED_SCI_COVER;			// Run & Cower
		break;
	}

	return BaseClass::SelectSchedule();
}

NPC_STATE CNPC_Scientist::SelectIdealState ( void )
{
	switch ( m_NPCState )
	{
	case NPC_STATE_ALERT:
	case NPC_STATE_IDLE:
		if ( HasCondition( COND_NEW_ENEMY ) )
		{
			if ( GetFollowTarget() && GetEnemy() )
			{
				int relationship = IRelationType( GetEnemy() );
				if ( relationship != D_FR || relationship != D_HT && ( !HasCondition( COND_LIGHT_DAMAGE  ) || !HasCondition( COND_HEAVY_DAMAGE ) ) )
				{
					// Don't go to combat if you're following the player
					m_IdealNPCState = NPC_STATE_ALERT;
					return m_IdealNPCState;
				}
				StopFollowing();
			}
		}
		else if ( HasCondition( COND_LIGHT_DAMAGE  ) || HasCondition( COND_HEAVY_DAMAGE ) ) 
		{
			// Stop following if you take damage
			if ( GetFollowTarget() )
				 StopFollowing();
		}
		break;

	case NPC_STATE_COMBAT:
		{
			CBaseEntity *pEnemy = GetEnemy();
			if ( pEnemy != NULL )
			{
				if ( DisregardEnemy( pEnemy ) )		// After 15 seconds of being hidden, return to alert
				{
					// Strip enemy when going to alert
					m_IdealNPCState = NPC_STATE_ALERT;
					SetEnemy( NULL );
					return m_IdealNPCState;
				}
				// Follow if only scared a little
				if ( GetFollowTarget() )
				{
					m_IdealNPCState = NPC_STATE_ALERT;
					return m_IdealNPCState;
				}

				if ( HasCondition( COND_SEE_ENEMY ) )
				{
					m_flFearTime = gpGlobals->curtime;
					m_IdealNPCState = NPC_STATE_COMBAT;
					return m_IdealNPCState;
				}

			}
		}
		break;
	}

	return BaseClass::SelectIdealState();
}

int CNPC_Scientist::FriendNumber( int arrayNumber )
{
	static int array[3] = { 1, 2, 0 };
	if ( arrayNumber < 3 )
		return array[ arrayNumber ];
	return arrayNumber;
}

float CNPC_Scientist::TargetDistance( void )
{
	// If we lose the player, or he dies, return a really large distance
	if ( GetTarget() == NULL || !GetTarget()->IsAlive() )
		return 1e6;

	return (GetTarget()->GetLocalOrigin() - GetLocalOrigin()).Length();
}

//=========================================================
// Dead Scientist PROP
//=========================================================
class CNPC_DeadScientist : public CAI_BaseNPC
{
	DECLARE_CLASS( CNPC_DeadScientist, CAI_BaseNPC );
public:

	void Spawn( void );
	Class_T	Classify ( void ) { return	CLASS_NONE; }

	bool KeyValue( const char *szKeyName, const char *szValue );
	float MaxYawSpeed ( void ) { return 8.0f; }

	int	m_iPose;// which sequence to display	-- temporary, don't need to save
	int m_iDesiredSequence;
	static char *m_szPoses[7];
};


char *CNPC_DeadScientist::m_szPoses[] = { "lying_on_back", "lying_on_stomach", "dead_sitting", "dead_hang", "dead_table1", "dead_table2", "dead_table3" };

bool CNPC_DeadScientist::KeyValue( const char *szKeyName, const char *szValue )
{
	if ( FStrEq( szKeyName, "pose" ) )
		m_iPose = atoi( szValue );
	else 
		BaseClass::KeyValue( szKeyName, szValue );

	return true;
}

LINK_ENTITY_TO_CLASS( monster_scientist_dead, CNPC_DeadScientist );

//
// ********** DeadScientist SPAWN **********
//
void CNPC_DeadScientist::Spawn( void )
{
	engine->PrecacheModel("models/scientist.mdl");
	SetModel( "models/scientist.mdl" );
	
	m_fEffects			= 0;
	SetSequence( 0 );
	m_bloodColor		= BLOOD_COLOR_RED;

	SetRenderColor( 255, 255, 255, 255 );

	if ( m_nBody == -1 )
	{// -1 chooses a random head
		m_nBody = random->RandomInt( 0, NUM_SCIENTIST_HEADS-1);// pick a head, any head
	}
	// Luther is black, make his hands black
	if ( m_nBody == HEAD_LUTHER )
		m_nSkin = 1;
	else
		m_nSkin = 0;

	SetSequence( LookupSequence( m_szPoses[m_iPose] ) );

	if ( GetSequence() == -1)
	{
		Msg ( "Dead scientist with bad pose\n" );
	}

	m_iHealth			= 0.0;//gSkillData.barneyHealth;

	NPCInitDead();

}


//=========================================================
// Sitting Scientist PROP
//=========================================================


LINK_ENTITY_TO_CLASS( monster_sitting_scientist, CNPC_SittingScientist );

//IMPLEMENT_CUSTOM_AI( monster_sitting_scientist, CNPC_SittingScientist );

//IMPLEMENT_SERVERCLASS_ST( CNPC_SittingScientist, DT_NPC_SittingScientist )
//END_SEND_TABLE()


//---------------------------------------------------------
// Save/Restore
//---------------------------------------------------------
BEGIN_DATADESC( CNPC_SittingScientist )
	DEFINE_FIELD( CNPC_SittingScientist, m_iHeadTurn, FIELD_INTEGER ),
	DEFINE_FIELD( CNPC_SittingScientist, m_flResponseDelay, FIELD_FLOAT ),

	DEFINE_THINKFUNC( CNPC_SittingScientist, SittingThink ),
END_DATADESC()


// animation sequence aliases 
typedef enum
{
SITTING_ANIM_sitlookleft,
SITTING_ANIM_sitlookright,
SITTING_ANIM_sitscared,
SITTING_ANIM_sitting2,
SITTING_ANIM_sitting3
} SITTING_ANIM;


//
// ********** Scientist SPAWN **********
//
void CNPC_SittingScientist :: Spawn( )
{
	engine->PrecacheModel("models/scientist.mdl");
	SetModel("models/scientist.mdl");
	Precache();

	InitBoneControllers();

	SetHullType(HULL_HUMAN);
	SetHullSizeNormal();

	SetSolid( SOLID_BBOX );
	AddSolidFlags( FSOLID_NOT_STANDABLE );
	SetMoveType( MOVETYPE_STEP );
	m_fEffects			= 0;
	m_iHealth			= 50;
	
	m_bloodColor		= BLOOD_COLOR_RED;
	m_flFieldOfView		= VIEW_FIELD_WIDE; // indicates the width of this monster's forward view cone ( as a dotproduct result )

⌨️ 快捷键说明

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