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

📄 hl1_npc_controller.cpp

📁 hl2 source code. Do not use it illegal.
💻 CPP
📖 第 1 页 / 共 3 页
字号:
//=========== (C) Copyright 2000 Valve, L.L.C. All rights reserved. ===========
//
// The copyright to the contents herein is the property of Valve, L.L.C.
// The contents may be used and/or copied only with the written permission of
// Valve, L.L.C., or in accordance with the terms and conditions stipulated in
// the agreement/contract under which the contents have been supplied.
//
// Purpose: Bullseyes act as targets for other NPC's to attack and to trigger
//			events 
//
// $Workfile:     $
// $Date:         $
//
//-----------------------------------------------------------------------------
// $Log: $
//
// $NoKeywords: $
//=============================================================================

#include	"cbase.h"
#include	"AI_Default.h"
#include	"AI_Task.h"
#include	"AI_Schedule.h"
#include	"AI_Node.h"
#include	"AI_Hull.h"
#include	"AI_Hint.h"
#include	"AI_Route.h"
#include	"AI_Navigator.h"
//#include	"hl1_npc_controller.h"
#include	"ai_basenpc_flyer.h"
#include	"soundent.h"
#include	"game.h"
#include	"NPCEvent.h"
#include	"EntityList.h"
#include	"activitylist.h"
#include	"animation.h"
#include	"basecombatweapon.h"
#include	"IEffects.h"
#include	"vstdlib/random.h"
#include	"engine/IEngineSound.h"
#include	"ammodef.h"
#include	"Sprite.h"
#include	"AI_MoveProbe.h"


//=========================================================
// Monster's Anim Events Go Here
//=========================================================
#define	CONTROLLER_AE_HEAD_OPEN		1
#define	CONTROLLER_AE_BALL_SHOOT	2
#define	CONTROLLER_AE_SMALL_SHOOT	3
#define CONTROLLER_AE_POWERUP_FULL	4
#define CONTROLLER_AE_POWERUP_HALF	5

#define CONTROLLER_FLINCH_DELAY			2		// at most one flinch every n secs

#define DIST_TO_CHECK	200

ConVar sk_controller_health ( "sk_controller_health", "60" );
ConVar sk_controller_dmgzap ( "sk_controller_dmgzap", "15" );
ConVar sk_controller_speedball ( "sk_controller_speedball", "650" );
ConVar sk_controller_dmgball ( "sk_controller_dmgball", "3" );

class CSprite;
class CNPC_Controller;

enum
{
	TASK_CONTROLLER_CHASE_ENEMY = LAST_SHARED_TASK,
	TASK_CONTROLLER_STRAFE,
	TASK_CONTROLLER_TAKECOVER,
	TASK_CONTROLLER_FAIL,
};

enum
{
	SCHED_CONTROLLER_CHASE_ENEMY = LAST_SHARED_SCHEDULE,
	SCHED_CONTROLLER_STRAFE,
	SCHED_CONTROLLER_TAKECOVER,
	SCHED_CONTROLLER_FAIL,
};

class CControllerNavigator : public CAI_ComponentWithOuter<CNPC_Controller, CAI_Navigator>
{
	typedef CAI_ComponentWithOuter<CNPC_Controller, CAI_Navigator> BaseClass;
public:
	CControllerNavigator( CNPC_Controller *pOuter )
	 :	BaseClass( pOuter )
	{
	}

	bool ActivityIsLocomotive( Activity activity ) { return true; }
};

class CNPC_Controller : public CAI_BaseFlyingBot
{
public:

	DECLARE_CLASS( CNPC_Controller, CAI_BaseFlyingBot );
	DEFINE_CUSTOM_AI;
	DECLARE_DATADESC();

	void Spawn( void );
	void Precache( void );

	float MaxYawSpeed( void ) { return 120.0f; }
	Class_T	Classify ( void ) { return	CLASS_ALIEN_MILITARY; }

	void HandleAnimEvent( animevent_t *pEvent );

	void RunAI( void );

	int RangeAttack1Conditions ( float flDot, float flDist );	// balls
	int RangeAttack2Conditions ( float flDot, float flDist );	// head
	int MeleeAttack1Conditions ( float flDot, float flDist ) { return COND_NONE; }	
	int MeleeAttack2Conditions ( float flDot, float flDist ) { return COND_NONE; }

	int TranslateSchedule( int scheduleType );
	void StartTask ( const Task_t *pTask );
	void RunTask ( const Task_t *pTask );

	void Stop( void );
	bool OverridePathMove( float flInterval );
	bool OverrideMove( float flInterval );

	void MoveToTarget( float flInterval, const Vector &vecMoveTarget );

	void SetActivity ( Activity NewActivity );
	bool ShouldAdvanceRoute( float flWaypointDist );
	int LookupFloat( );

	friend class CControllerNavigator;
	CAI_Navigator *CreateNavigator()
	{
		return new CControllerNavigator( this );
	}

	bool ShouldGib( const CTakeDamageInfo &info );
	bool HasAlienGibs( void ) { return true; }
	bool HasHumanGibs( void ) { return false; }

	float m_flNextFlinch; 

	float m_flShootTime;
	float m_flShootEnd;

	void PainSound( void );
	void AlertSound( void );
	void IdleSound( void );
	void AttackSound( void );
	void DeathSound( void );

	static const char *pAttackSounds[];
	static const char *pIdleSounds[];
	static const char *pAlertSounds[];
	static const char *pPainSounds[];
	static const char *pDeathSounds[];

	int OnTakeDamage_Alive( const CTakeDamageInfo &info );
	void Event_Killed( const CTakeDamageInfo &info );

	CSprite *m_pBall[2];	// hand balls
	int m_iBall[2];			// how bright it should be
	float m_iBallTime[2];	// when it should be that color
	int m_iBallCurrent[2];	// current brightness

	Vector m_vecEstVelocity;

	Vector m_velocity;
	bool m_fInCombat;

	void SetSequence( int nSequence );

	int IRelationPriority( CBaseEntity *pTarget );
};

class CNPC_ControllerHeadBall : public CAI_BaseNPC
{
public:
	DECLARE_CLASS( CNPC_ControllerHeadBall, CAI_BaseNPC );

	DECLARE_DATADESC();

	void Spawn( void );
	void Precache( void );

	void EXPORT HuntThink( void );
	void EXPORT KillThink( void );
	void EXPORT BounceTouch( CBaseEntity *pOther );
	void MovetoTarget( Vector vecTarget );

	int m_iTrail;
	int m_flNextAttack;
	float m_flSpawnTime;
	Vector m_vecIdeal;
	EHANDLE m_hOwner;

	CSprite *m_pSprite;
};

class CNPC_ControllerZapBall : public CAI_BaseNPC
{	
public:	
	DECLARE_CLASS( CNPC_ControllerHeadBall, CAI_BaseNPC );

	DECLARE_DATADESC();

	void Spawn( void );
	void Precache( void );

	void EXPORT AnimateThink( void );
	void EXPORT ExplodeTouch( CBaseEntity *pOther );

	void Kill( void );

	EHANDLE m_hOwner;
	float m_flSpawnTime;

	CSprite *m_pSprite;
};

LINK_ENTITY_TO_CLASS( monster_alien_controller, CNPC_Controller );

BEGIN_DATADESC( CNPC_Controller )

	DEFINE_ARRAY( CNPC_Controller, m_pBall, FIELD_CLASSPTR, 2 ),
	DEFINE_ARRAY( CNPC_Controller, m_iBall, FIELD_INTEGER, 2 ),
	DEFINE_ARRAY( CNPC_Controller, m_iBallTime, FIELD_TIME, 2 ),
	DEFINE_ARRAY( CNPC_Controller, m_iBallCurrent, FIELD_INTEGER, 2 ),
	DEFINE_FIELD( CNPC_Controller, m_vecEstVelocity, FIELD_VECTOR ),
	DEFINE_FIELD( CNPC_Controller, m_velocity, FIELD_VECTOR ),
	DEFINE_FIELD( CNPC_Controller, m_fInCombat, FIELD_BOOLEAN ),

END_DATADESC()


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

	SetModel( "models/controller.mdl" );
	UTIL_SetSize( this, Vector( -32, -32, 0 ), Vector( 32, 32, 64 ));

	SetSolid( SOLID_BBOX );
	AddSolidFlags( FSOLID_NOT_STANDABLE );

	SetMoveType( MOVETYPE_STEP );
	SetGravity(0.001);


	m_bloodColor		= BLOOD_COLOR_GREEN;
	m_iHealth =			sk_controller_health.GetFloat();

	m_flFieldOfView		= VIEW_FIELD_FULL;// indicates the width of this monster's forward view cone ( as a dotproduct result )
	m_NPCState			= NPC_STATE_NONE;

	SetRenderColor( 255, 255, 255, 255 );

	CapabilitiesClear();

	AddFlag( FL_FLY );
	SetNavType( NAV_FLY );

	CapabilitiesAdd( bits_CAP_MOVE_FLY | bits_CAP_INNATE_RANGE_ATTACK1 | bits_CAP_INNATE_RANGE_ATTACK2 | bits_CAP_MOVE_SHOOT);

	NPCInit();

	
	SetDefaultEyeOffset();
}

const char *CNPC_Controller::pAttackSounds[] = 
{
	"controller/con_attack1.wav",
	"controller/con_attack2.wav",
	"controller/con_attack3.wav",
};

const char *CNPC_Controller::pIdleSounds[] = 
{
	"controller/con_idle1.wav",
	"controller/con_idle2.wav",
	"controller/con_idle3.wav",
	"controller/con_idle4.wav",
	"controller/con_idle5.wav",
};

const char *CNPC_Controller::pAlertSounds[] = 
{
	"controller/con_alert1.wav",
	"controller/con_alert2.wav",
	"controller/con_alert3.wav",
};

const char *CNPC_Controller::pPainSounds[] = 
{
	"controller/con_pain1.wav",
	"controller/con_pain2.wav",
	"controller/con_pain3.wav",
};

const char *CNPC_Controller::pDeathSounds[] = 
{
	"controller/con_die1.wav",
	"controller/con_die2.wav",
};

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

	PRECACHE_SOUND_ARRAY( pAttackSounds );
	PRECACHE_SOUND_ARRAY( pIdleSounds );
	PRECACHE_SOUND_ARRAY( pAlertSounds );
	PRECACHE_SOUND_ARRAY( pPainSounds );
	PRECACHE_SOUND_ARRAY( pDeathSounds );

	engine->PrecacheModel( "sprites/xspark4.vmt");

	UTIL_PrecacheOther( "controller_energy_ball" );	
	UTIL_PrecacheOther( "controller_head_ball" );
}	

//=========================================================
// TakeDamage - 
//=========================================================
int CNPC_Controller::OnTakeDamage_Alive( const CTakeDamageInfo &info )
{
	PainSound();
	return BaseClass::OnTakeDamage_Alive( info );
}

bool CNPC_Controller::ShouldGib( const CTakeDamageInfo &info )
{
	if ( info.GetDamageType() & DMG_NEVERGIB )
		 return false;

	if ( ( info.GetDamageType() & DMG_GIB_CORPSE && m_iHealth < GIB_HEALTH_VALUE ) || ( info.GetDamageType() & DMG_ALWAYSGIB ) )
		 return true;
	
	return false;
	
}

int CNPC_Controller::IRelationPriority( CBaseEntity *pTarget )
{
	if ( pTarget->Classify() == CLASS_PLAYER )
	{
		 return BaseClass::IRelationPriority ( pTarget ) + 1;
	}

	return BaseClass::IRelationPriority( pTarget );
}

void CNPC_Controller::Event_Killed( const CTakeDamageInfo &info )
{
	if( ShouldGib(info) )
	{
		//remove the balls 
		if (m_pBall[0])
		{
			UTIL_Remove( m_pBall[0] );
			m_pBall[0] = NULL;
		}
		if (m_pBall[1])
		{
			UTIL_Remove( m_pBall[1] );
			m_pBall[1] = NULL;
		}
	}
	else
	{
		// fade balls
		if (m_pBall[0])
		{
			m_pBall[0]->FadeAndDie( 2 );
			m_pBall[0] = NULL;
		}
		if (m_pBall[1])
		{
			m_pBall[1]->FadeAndDie( 2 );
			m_pBall[1] = NULL;
		}
	}

	BaseClass::Event_Killed( info );
}

void CNPC_Controller::PainSound( void )
{
	if (random->RandomInt(0,5) < 2)
	{
		CPASAttenuationFilter filter( this );
		enginesound->EmitSound( filter, entindex(), CHAN_VOICE, RANDOM_SOUND_ARRAY( pPainSounds ), 1, ATTN_NORM );
	}
}

void CNPC_Controller::AlertSound( void )
{
	CPASAttenuationFilter filter( this );
	enginesound->EmitSound( filter, entindex(), CHAN_VOICE, RANDOM_SOUND_ARRAY( pAlertSounds ), 1, ATTN_NORM ); 
}

void CNPC_Controller::IdleSound( void )
{
	CPASAttenuationFilter filter( this );
	enginesound->EmitSound( filter, entindex(), CHAN_VOICE, RANDOM_SOUND_ARRAY( pIdleSounds ), 1, ATTN_NORM );
}

void CNPC_Controller::AttackSound( void )
{
	CPASAttenuationFilter filter( this );
	enginesound->EmitSound( filter, entindex(), CHAN_VOICE, RANDOM_SOUND_ARRAY( pAttackSounds ), 1, ATTN_NORM );
}

void CNPC_Controller::DeathSound( void )
{
	CPASAttenuationFilter filter( this );
	enginesound->EmitSound( filter, entindex(), CHAN_VOICE, RANDOM_SOUND_ARRAY( pDeathSounds ), 1, ATTN_NORM );
}

//=========================================================
// HandleAnimEvent - catches the monster-specific messages
// that occur when tagged animation frames are played.
//=========================================================
void CNPC_Controller::HandleAnimEvent( animevent_t *pEvent )
{
	switch( pEvent->event )
	{
		case CONTROLLER_AE_HEAD_OPEN:
		{
			Vector vecStart;
			QAngle angleGun;
			
			GetAttachment( 0, vecStart, angleGun );

			// BUGBUG - attach to attachment point!

⌨️ 快捷键说明

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