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

📄 hl1_npc_turret.cpp

📁 hl2 source code. Do not use it illegal.
💻 CPP
📖 第 1 页 / 共 3 页
字号:
#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_Senses.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"

#define TURRET_SHOTS	2
#define TURRET_RANGE	(100 * 12)
#define TURRET_SPREAD	Vector( 0, 0, 0 )
#define TURRET_TURNRATE	30		//angles per 0.1 second
#define TURRET_MAXWAIT	15		// seconds turret will stay active w/o a target
#define TURRET_MAXSPIN	5		// seconds turret barrel will spin w/o a target
#define TURRET_MACHINE_VOLUME	0.5

typedef enum
{
//	TURRET_ANIM_NONE = 0,
	TURRET_ANIM_FIRE = 0,	
	TURRET_ANIM_SPIN,
	TURRET_ANIM_DEPLOY,
	TURRET_ANIM_RETIRE,
	TURRET_ANIM_DIE,
} TURRET_ANIM;

#define SF_MONSTER_TURRET_AUTOACTIVATE	32
#define SF_MONSTER_TURRET_STARTINACTIVE	64

#define TURRET_GLOW_SPRITE "sprites/flare3.vmt"

#define TURRET_ORIENTATION_FLOOR 0
#define TURRET_ORIENTATION_CEILING 1

class CNPC_BaseTurret : public CAI_BaseNPC
{
	DECLARE_CLASS( CNPC_BaseTurret, CAI_BaseNPC );
public:
	void Spawn(void);
	virtual void Precache(void);
	void EXPORT TurretUse( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value );
	
	virtual void TraceAttack( const CTakeDamageInfo &info, const Vector &vecDir, trace_t *ptr );

	virtual int OnTakeDamage( const CTakeDamageInfo &info );
	virtual int OnTakeDamage_Alive( const CTakeDamageInfo &inputInfo );

	Class_T Classify( void );

	// Think functions
	void EXPORT ActiveThink(void);
	void EXPORT SearchThink(void);
	void EXPORT AutoSearchThink(void);
	void EXPORT TurretDeath(void);

	virtual void EXPORT SpinDownCall(void) { m_iSpin = 0; }
	virtual void EXPORT SpinUpCall(void) { m_iSpin = 1; }

	void EXPORT Deploy(void);
	void EXPORT Retire(void);

	void EXPORT Initialize(void);

	virtual void Ping(void);
	virtual void EyeOn(void);
	virtual void EyeOff(void);


	void InputActivate( inputdata_t &inputdata );
	void InputDeactivate( inputdata_t &inputdata );

	void Event_Killed( const CTakeDamageInfo &info );
	virtual bool ShouldFadeOnDeath( void ) { return false; }
	bool ShouldGib( const CTakeDamageInfo &info ) { return false; }

	// other functions
	void SetTurretAnim(TURRET_ANIM anim);
	int MoveTurret(void);
	virtual void Shoot(Vector &vecSrc, Vector &vecDirToEnemy) { };
  
	float m_flMaxSpin;		// Max time to spin the barrel w/o a target
	int m_iSpin;

	CSprite *m_pEyeGlow;
	int		m_eyeBrightness;

	int	m_iDeployHeight;
	int	m_iRetractHeight;
	int m_iMinPitch;

	int m_iBaseTurnRate;	// angles per second
	float m_fTurnRate;		// actual turn rate
	int m_iOrientation;		// 0 = floor, 1 = Ceiling
	int	m_iOn;
	int m_fBeserk;			// Sometimes this bitch will just freak out
	int m_iAutoStart;		// true if the turret auto deploys when a target
							// enters its range

	Vector m_vecLastSight;
	float m_flLastSight;	// Last time we saw a target
	float m_flMaxWait;		// Max time to seach w/o a target
	int m_iSearchSpeed;		// Not Used!

	// movement
	float	m_flStartYaw;
	Vector	m_vecCurAngles;
	Vector	m_vecGoalAngles;


	float	m_flPingTime;	// Time until the next ping, used when searching
	float	m_flSpinUpTime;	// Amount of time until the barrel should spin down when searching

	float   m_flDamageTime;

	int		m_iAmmoType;

	COutputEvent	m_OnActivate;
	COutputEvent	m_OnDeactivate;

	//DEFINE_CUSTOM_AI;
	DECLARE_DATADESC();

	typedef CAI_BaseNPC BaseClass;
};

BEGIN_DATADESC( CNPC_BaseTurret )

	//FIELDS
	DEFINE_FIELD( CNPC_BaseTurret, m_flMaxSpin, FIELD_FLOAT ),
	DEFINE_FIELD( CNPC_BaseTurret, m_iSpin, FIELD_INTEGER ),

	DEFINE_FIELD( CNPC_BaseTurret, m_pEyeGlow, FIELD_CLASSPTR ),
	DEFINE_FIELD( CNPC_BaseTurret, m_eyeBrightness, FIELD_INTEGER ),
	DEFINE_FIELD( CNPC_BaseTurret, m_iDeployHeight, FIELD_INTEGER ),
	DEFINE_FIELD( CNPC_BaseTurret, m_iRetractHeight, FIELD_INTEGER ),
	DEFINE_FIELD( CNPC_BaseTurret, m_iMinPitch, FIELD_INTEGER ),

	DEFINE_FIELD( CNPC_BaseTurret, m_fTurnRate, FIELD_FLOAT ),
	DEFINE_FIELD( CNPC_BaseTurret, m_iOn, FIELD_INTEGER ),
	DEFINE_FIELD( CNPC_BaseTurret, m_fBeserk, FIELD_INTEGER ),
	DEFINE_FIELD( CNPC_BaseTurret, m_iAutoStart, FIELD_INTEGER ),

	DEFINE_FIELD( CNPC_BaseTurret, m_vecLastSight, FIELD_POSITION_VECTOR ),
	DEFINE_FIELD( CNPC_BaseTurret, m_flLastSight, FIELD_TIME ),

	DEFINE_FIELD( CNPC_BaseTurret, m_flStartYaw, FIELD_FLOAT ),
	DEFINE_FIELD( CNPC_BaseTurret, m_vecCurAngles, FIELD_VECTOR ),
	DEFINE_FIELD( CNPC_BaseTurret, m_vecGoalAngles, FIELD_VECTOR ),

	DEFINE_FIELD( CNPC_BaseTurret, m_flPingTime, FIELD_TIME ),
	DEFINE_FIELD( CNPC_BaseTurret, m_flSpinUpTime, FIELD_TIME ),

	//KEYFIELDS
	DEFINE_KEYFIELD( CNPC_BaseTurret, m_flMaxWait, FIELD_FLOAT, "maxsleep" ),
	DEFINE_KEYFIELD( CNPC_BaseTurret, m_iOrientation, FIELD_INTEGER, "orientation" ),
	DEFINE_KEYFIELD( CNPC_BaseTurret, m_iSearchSpeed, FIELD_INTEGER, "searchspeed" ),
	DEFINE_KEYFIELD( CNPC_BaseTurret, m_iBaseTurnRate, FIELD_INTEGER, "turnrate" ),
	
	//Use
	DEFINE_USEFUNC( CNPC_BaseTurret, TurretUse ),

	//Thinks
	DEFINE_THINKFUNC( CNPC_BaseTurret, ActiveThink ),
	DEFINE_THINKFUNC( CNPC_BaseTurret, SearchThink ),
	DEFINE_THINKFUNC( CNPC_BaseTurret, AutoSearchThink ),
	DEFINE_THINKFUNC( CNPC_BaseTurret, TurretDeath ),
	DEFINE_THINKFUNC( CNPC_BaseTurret, SpinDownCall ),
	DEFINE_THINKFUNC( CNPC_BaseTurret, SpinUpCall ),
	DEFINE_THINKFUNC( CNPC_BaseTurret, Deploy ),
	DEFINE_THINKFUNC( CNPC_BaseTurret, Retire ),
	DEFINE_THINKFUNC( CNPC_BaseTurret, Initialize ),

	//Inputs
	DEFINE_INPUTFUNC( CNPC_BaseTurret, FIELD_VOID, "Activate",	InputActivate ),
	DEFINE_INPUTFUNC( CNPC_BaseTurret, FIELD_VOID, "Deactivate",	InputDeactivate ),

	//Outputs
	DEFINE_OUTPUT( CNPC_BaseTurret, m_OnActivate,	"OnActivate"),
	DEFINE_OUTPUT( CNPC_BaseTurret, m_OnDeactivate,	"OnDeactivate"),

END_DATADESC()


void CNPC_BaseTurret::Spawn()
{ 
	Precache( );
	SetNextThink( gpGlobals->curtime + 1 );
	SetMoveType( MOVETYPE_FLY );
	SetSequence( 0 );
	m_flCycle			= 0;
	SetSolid( SOLID_BBOX );
	AddSolidFlags( FSOLID_NOT_STANDABLE );
	m_takedamage		= DAMAGE_YES;
	AddFlag( FL_AIMTARGET );

	AddFlag( FL_NPC );
	SetUse( &CNPC_BaseTurret::TurretUse );

	if (( m_spawnflags & SF_MONSTER_TURRET_AUTOACTIVATE ) 
		&& !( m_spawnflags & SF_MONSTER_TURRET_STARTINACTIVE ))
	{
		m_iAutoStart = true;
	}

	ResetSequenceInfo( );

	SetBoneController(0, 0);
	SetBoneController(1, 0);

	m_flFieldOfView = VIEW_FIELD_FULL;

	m_bloodColor = DONT_BLEED;
	m_flDamageTime = 0;

	if ( GetSpawnFlags() & SF_MONSTER_TURRET_STARTINACTIVE )
	{
		 SetTurretAnim( TURRET_ANIM_RETIRE );
		 m_flCycle = 0.0f;
		 m_flPlaybackRate = 0.0f;
	}
}


void CNPC_BaseTurret::Precache()
{
	m_iAmmoType = GetAmmoDef()->Index("12mmRound");	

	enginesound->PrecacheSound ("turret/tu_fire1.wav");
	enginesound->PrecacheSound ("turret/tu_ping.wav");
	enginesound->PrecacheSound ("turret/tu_active2.wav");
	enginesound->PrecacheSound ("turret/tu_die.wav");
	enginesound->PrecacheSound ("turret/tu_die2.wav");
	enginesound->PrecacheSound ("turret/tu_die3.wav");
	enginesound->PrecacheSound ("turret/tu_deploy.wav");
	enginesound->PrecacheSound ("turret/tu_spinup.wav");
	enginesound->PrecacheSound ("turret/tu_spindown.wav");
	enginesound->PrecacheSound ("turret/tu_search.wav");
	enginesound->PrecacheSound ("turret/tu_alert.wav");
}

Class_T CNPC_BaseTurret::Classify( void )
{
	if (m_iOn || m_iAutoStart)
		return	CLASS_MACHINE;
	return CLASS_NONE;
}

//=========================================================
// TraceAttack - being attacked
//=========================================================
void CNPC_BaseTurret::TraceAttack( const CTakeDamageInfo &info, const Vector &vecDir, trace_t *ptr )
{
	CTakeDamageInfo ainfo = info;

	if ( ptr->hitgroup == 10 )	
	{
		// hit armor
		if ( m_flDamageTime != gpGlobals->curtime || (random->RandomInt(0,10) < 1) )
		{
			g_pEffects->Ricochet( ptr->endpos, ptr->plane.normal );
			m_flDamageTime = gpGlobals->curtime;
		}

		ainfo.SetDamage( 0.1 );// don't hurt the monster much, but allow bits_COND_LIGHT_DAMAGE to be generated
	}

	if ( m_takedamage == DAMAGE_NO )
		return;

	//DevMsg( 1, "traceattack: %f\n", ainfo.GetDamage() );

	AddMultiDamage( info, this );
}

//=========================================================
// TakeDamage - take damage. 
//=========================================================
int CNPC_BaseTurret::OnTakeDamage_Alive( const CTakeDamageInfo &inputInfo )
{
	if ( m_takedamage == DAMAGE_NO )
		return 0;

	float flDamage = inputInfo.GetDamage();

	if (!m_iOn)
		flDamage /= 10.0;

	m_iHealth -= flDamage;
	if (m_iHealth <= 0)
	{
		m_iHealth = 0;
		m_takedamage = DAMAGE_NO;
		m_flDamageTime = gpGlobals->curtime;

//		ClearBits (pev->flags, FL_MONSTER); // why are they set in the first place???

		SetUse(NULL);
		SetThink(&CNPC_BaseTurret::TurretDeath);
		SetNextThink( gpGlobals->curtime + 0.1 );

		m_OnDeactivate.FireOutput(this, this);

		return 0;
	}

	if (m_iHealth <= 10)
	{
		if (m_iOn)
		{
			m_fBeserk = 1;
			SetThink(&CNPC_BaseTurret::SearchThink);
		}
	}
	return 1;
}

int CNPC_BaseTurret::OnTakeDamage( const CTakeDamageInfo &info )
{
	int retVal = 0;

	if (!m_takedamage)
		return 0;

	switch( m_lifeState )
	{
	case LIFE_ALIVE:
		retVal = OnTakeDamage_Alive( info );
		if ( m_iHealth <= 0 )
		{
			IPhysicsObject *pPhysics = VPhysicsGetObject();
			if ( pPhysics )
			{
				pPhysics->EnableCollisions( false );
			}
			
			Event_Killed( info );	
			Event_Dying();
		}
		return retVal;
		break;

	case LIFE_DYING:
		return OnTakeDamage_Dying( info );
	
	default:
	case LIFE_DEAD:
		return OnTakeDamage_Dead( info );
	}
}

void CNPC_BaseTurret::SetTurretAnim( TURRET_ANIM anim )
{
	/*
	if (GetSequence() != anim)
	{
		switch(anim)
		{
		case TURRET_ANIM_FIRE:
		case TURRET_ANIM_SPIN:
			if (GetSequence() != TURRET_ANIM_FIRE && GetSequence() != TURRET_ANIM_SPIN)
			{
				m_flCycle = 0;
			}
			break;
		default:
			m_flCycle = 0;
			break;
		}

		SetSequence( anim );

		ResetSequenceInfo( );

		switch(anim)
		{
		case TURRET_ANIM_RETIRE:
			m_flCycle			= 255;
			m_flPlaybackRate		= -1.0;	//play the animation backwards
			break;
		case TURRET_ANIM_DIE:
			m_flPlaybackRate		= 1.0;
			break;
		}
		//ALERT(at_console, "Turret anim #%d\n", anim);
	}
	*/

	if (GetSequence() != anim)
	{
		SetSequence( anim );

		ResetSequenceInfo( );

		switch(anim)
		{
		case TURRET_ANIM_FIRE:
		case TURRET_ANIM_SPIN:
			if (GetSequence() != TURRET_ANIM_FIRE && GetSequence() != TURRET_ANIM_SPIN)
			{
				m_flCycle = 0;
			}
			break;
		case TURRET_ANIM_RETIRE:
			m_flCycle				= 1.0;
			m_flPlaybackRate		= -1.0;	//play the animation backwards
			break;
		case TURRET_ANIM_DIE:
			m_flCycle				= 0.0;
			m_flPlaybackRate		= 1.0;
			break;
		default:
			m_flCycle = 0;
			break;
		}


	}
}

//=========================================================
// Initialize - set up the turret, initial think
//=========================================================
void CNPC_BaseTurret::Initialize(void)
{
	m_iOn = 0;
	m_fBeserk = 0;
	m_iSpin = 0;

	SetBoneController( 0, 0 );
	SetBoneController( 1, 0 );

	if (m_iBaseTurnRate == 0) m_iBaseTurnRate = TURRET_TURNRATE;
	if (m_flMaxWait == 0) m_flMaxWait = TURRET_MAXWAIT;

	QAngle angles = GetAbsAngles();
	m_flStartYaw = angles.y;
	if (m_iOrientation == TURRET_ORIENTATION_CEILING)
	{
		angles.x = 180;
		angles.y += 180;
		if( angles.y > 360 )
			angles.y -= 360;
		SetAbsAngles( angles );

//		pev->idealpitch = 180;			//not used?

		Vector view_ofs = GetViewOffset();
		view_ofs.z = -view_ofs.z;
		SetViewOffset( view_ofs );

//		pev->effects |= EF_INVLIGHT;	//no need
	}

	m_vecGoalAngles.x = 0;

	if (m_iAutoStart)
	{
		m_flLastSight = gpGlobals->curtime + m_flMaxWait;
		SetThink(&CNPC_BaseTurret::AutoSearchThink);

		SetNextThink( gpGlobals->curtime + 0.1 );
	}
	else
	{
		SetThink( SUB_DoNothing ); 
	}
}

//=========================================================
// ActiveThink - 
//=========================================================
void CNPC_BaseTurret::ActiveThink(void)
{
	int fAttack = 0;

	SetNextThink( gpGlobals->curtime + 0.1 );
	StudioFrameAdvance( );

	if ( (!m_iOn) || (GetEnemy() == NULL) )
	{
		SetEnemy( NULL );
		m_flLastSight = gpGlobals->curtime + m_flMaxWait;
		SetThink(&CNPC_BaseTurret::SearchThink);
		return;
	}
	
	// if it's dead, look for something new
	if ( !GetEnemy()->IsAlive() )
	{
		if (!m_flLastSight)
		{
			m_flLastSight = gpGlobals->curtime + 0.5; // continue-shooting timeout
		}
		else

⌨️ 快捷键说明

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