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

📄 hl1_npc_leech.cpp

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

// Animation events
#define LEECH_AE_ATTACK		1
#define LEECH_AE_FLOP		2

//#define DEBUG_BEAMS 0

ConVar sk_leech_health( "sk_leech_health", "2" );
ConVar sk_leech_dmg_bite( "sk_leech_dmg_bite", "2" );

// Movement constants

#define		LEECH_ACCELERATE		10
#define		LEECH_CHECK_DIST		45
#define		LEECH_SWIM_SPEED		50
#define		LEECH_SWIM_ACCEL		80
#define		LEECH_SWIM_DECEL		10
#define		LEECH_TURN_RATE			90
#define		LEECH_SIZEX				10
#define		LEECH_FRAMETIME			0.1

class CNPC_Leech : public CHL1BaseNPC
{
	DECLARE_CLASS( CNPC_Leech, CHL1BaseNPC );
public:

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

	static const char *pAttackSounds[];
	static const char *pAlertSounds[];

	void SwimThink( void );
	void DeadThink( void );

	void SwitchLeechState( void );
	float ObstacleDistance( CBaseEntity *pTarget );
	void UpdateMotion( void );

	void RecalculateWaterlevel( void );
	void Touch( CBaseEntity *pOther );

	void SetObjectCollisionBox( void )
	{
		SetAbsMins( GetLocalOrigin() + Vector(-8,-8,0) );
		SetAbsMaxs( GetLocalOrigin() + Vector(8,8,2) );
	}

	Disposition_t IRelationType(CBaseEntity *pTarget);

	void HandleAnimEvent( animevent_t *pEvent );

	void AttackSound( void );
	void AlertSound( void );

	void Activate( void );

	Class_T	Classify( void ) { return CLASS_INSECT; };

	void Event_Killed( const CTakeDamageInfo &info );


	bool ShouldGib(	const CTakeDamageInfo &info );

	
/*	// Base entity functions
	void Killed( entvars_t *pevAttacker, int iGib );
	int TakeDamage( entvars_t *pevInflictor, entvars_t *pevAttacker, float flDamage, int bitsDamageType );
*/

private:
	// UNDONE: Remove unused boid vars, do group behavior
	float	m_flTurning;// is this boid turning?
	bool	m_fPathBlocked;// TRUE if there is an obstacle ahead
	float	m_flAccelerate;
	float	m_obstacle;
	float	m_top;
	float	m_bottom;
	float	m_height;
	float	m_waterTime;
	float	m_sideTime;		// Timer to randomly check clearance on sides
	float	m_zTime;
	float	m_stateTime;
	float	m_attackSoundTime;
	Vector  m_oldOrigin;
};

LINK_ENTITY_TO_CLASS( monster_leech, CNPC_Leech );

BEGIN_DATADESC( CNPC_Leech )
	DEFINE_FIELD( CNPC_Leech, m_flTurning, FIELD_FLOAT ),
	DEFINE_FIELD( CNPC_Leech, m_fPathBlocked, FIELD_BOOLEAN ),
	DEFINE_FIELD( CNPC_Leech, m_flAccelerate, FIELD_FLOAT ),
	DEFINE_FIELD( CNPC_Leech, m_obstacle, FIELD_FLOAT ),
	DEFINE_FIELD( CNPC_Leech, m_top, FIELD_FLOAT ),
	DEFINE_FIELD( CNPC_Leech, m_bottom, FIELD_FLOAT ),
	DEFINE_FIELD( CNPC_Leech, m_height, FIELD_FLOAT ),
	DEFINE_FIELD( CNPC_Leech, m_waterTime, FIELD_TIME ),
	DEFINE_FIELD( CNPC_Leech, m_sideTime, FIELD_TIME ),
	DEFINE_FIELD( CNPC_Leech, m_zTime, FIELD_TIME ),
	DEFINE_FIELD( CNPC_Leech, m_stateTime, FIELD_TIME ),
	DEFINE_FIELD( CNPC_Leech, m_attackSoundTime, FIELD_TIME ),
	DEFINE_FIELD( CNPC_Leech, m_oldOrigin, FIELD_VECTOR ),

	DEFINE_THINKFUNC( CNPC_Leech, SwimThink ),
	DEFINE_THINKFUNC( CNPC_Leech, DeadThink ),
END_DATADESC()

const char *CNPC_Leech::pAttackSounds[] =
{
	"leech/leech_bite1.wav",
	"leech/leech_bite2.wav",
	"leech/leech_bite3.wav",
};

const char *CNPC_Leech::pAlertSounds[] =
{
	"leech/leech_alert1.wav",
	"leech/leech_alert2.wav",
};

bool CNPC_Leech::ShouldGib(	const CTakeDamageInfo &info )
{
	return false;
}

void CNPC_Leech::Spawn( void )
{
	Precache();
	SetModel( "models/leech.mdl" );

	SetHullType(HULL_TINY_CENTERED); 
	SetHullSizeNormal();

	UTIL_SetSize( this, Vector(-1,-1,0), Vector(1,1,2));
	// Don't push the minz down too much or the water check will fail because this entity is really point-sized
	SetSolid( SOLID_BBOX );
	AddSolidFlags( FSOLID_NOT_STANDABLE );
	SetMoveType( MOVETYPE_FLY );
	AddFlag( FL_SWIM );
	m_iHealth	= sk_leech_health.GetInt();

	m_flFieldOfView		= -0.5;	// 180 degree FOV
	SetDistLook( 750 );
	NPCInit();
	SetThink( &CNPC_Leech::SwimThink );
	SetUse( NULL );
	SetTouch( NULL );
	SetViewOffset( vec3_origin );

	m_flTurning = 0;
	m_fPathBlocked = FALSE;
	SetActivity( ACT_SWIM );
	SetState( NPC_STATE_IDLE );
	m_stateTime = gpGlobals->curtime + random->RandomFloat( 1, 5 );

	SetRenderColor( 255, 255, 255, 255 );

	m_bloodColor		= DONT_BLEED;
	SetCollisionGroup( COLLISION_GROUP_DEBRIS );
}

void CNPC_Leech::Activate( void )
{
	RecalculateWaterlevel();

	BaseClass::Activate();
}

void CNPC_Leech::DeadThink( void )
{
	if ( IsSequenceFinished() )
	{
		if ( GetActivity() == ACT_DIEFORWARD )
		{
			SetThink( NULL );
			StopAnimation();
			return;
		}
		else if ( GetFlags() & FL_ONGROUND )
		{
			AddSolidFlags( FSOLID_NOT_SOLID );
			SetActivity( ACT_DIEFORWARD );
		}
	}
	StudioFrameAdvance();
	SetNextThink( gpGlobals->curtime + 0.1 );

	// Apply damage velocity, but keep out of the walls
	if ( GetAbsVelocity().x != 0 || GetAbsVelocity().y != 0 )
	{
		trace_t tr;

		// Look 0.5 seconds ahead
		UTIL_TraceLine( GetLocalOrigin(), GetLocalOrigin() + GetAbsVelocity() * 0.5, MASK_SOLID, this, COLLISION_GROUP_NONE, &tr);
		if (tr.fraction != 1.0)
		{
			Vector vVelocity = GetAbsVelocity();

			vVelocity.x = 0;
			vVelocity.y = 0;

			SetAbsVelocity( vVelocity );
		}
	}
}


Disposition_t CNPC_Leech::IRelationType( CBaseEntity *pTarget )
{
	if ( pTarget->IsPlayer() )
		return D_HT;
	
	return BaseClass::IRelationType( pTarget );
}

void CNPC_Leech::Touch( CBaseEntity *pOther )
{
	if ( !pOther->IsPlayer() )
		 return;

	if ( pOther == GetTouchTrace().m_pEnt )
	{
		if ( pOther->GetAbsVelocity() == vec3_origin )
			 return;

		SetBaseVelocity( pOther->GetAbsVelocity() );
		AddFlag( FL_BASEVELOCITY );
	}
}

void CNPC_Leech::HandleAnimEvent( animevent_t *pEvent )
{
	CBaseEntity *pEnemy = GetEnemy();

	switch( pEvent->event )
	{
	case LEECH_AE_FLOP:
		// Play flop sound
		break;

	case LEECH_AE_ATTACK:
		AttackSound();
		
		if ( pEnemy != NULL )
		{
			Vector dir, face;
	
			AngleVectors( GetAbsAngles(), &face );
			
			face.z = 0;
			dir = (pEnemy->GetLocalOrigin() - GetLocalOrigin() );
			dir.z = 0;
			
			VectorNormalize( dir );
			VectorNormalize( face );
						
			if ( DotProduct(dir, face) > 0.9 )		// Only take damage if the leech is facing the prey
			{
				CTakeDamageInfo info( this, this, sk_leech_dmg_bite.GetInt(), DMG_SLASH );
				CalculateMeleeDamageForce( &info, dir, pEnemy->GetAbsOrigin() );
				pEnemy->TakeDamage( info );
			}
		}
		m_stateTime -= 2;
		break;
	

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


void CNPC_Leech::Precache( void )
{
	engine->PrecacheModel("models/leech.mdl");

    PRECACHE_SOUND_ARRAY(pAttackSounds);
	PRECACHE_SOUND_ARRAY(pAlertSounds);
}


void CNPC_Leech::AttackSound( void )
{
	if ( gpGlobals->curtime > m_attackSoundTime )
	{
		CPASAttenuationFilter filter( this );

		enginesound->EmitSound(filter, entindex(), CHAN_VOICE, pAttackSounds[ random->RandomInt(0,ARRAYSIZE(pAttackSounds)-1) ], 1.0, ATTN_NORM, 0, PITCH_NORM );
		m_attackSoundTime = gpGlobals->curtime + 0.5;
	}
}


void CNPC_Leech::AlertSound( void )
{
	CPASAttenuationFilter filter( this );

	enginesound->EmitSound(filter, entindex(), CHAN_VOICE, pAlertSounds[ random->RandomInt(0,ARRAYSIZE(pAlertSounds)-1) ], 1.0, ATTN_NORM * 0.5, 0, PITCH_NORM );
}

void CNPC_Leech::SwitchLeechState( void )
{
	m_stateTime = gpGlobals->curtime + random->RandomFloat( 3, 6 );
	if ( m_NPCState == NPC_STATE_COMBAT )
	{
		SetEnemy ( NULL );
		SetState( NPC_STATE_IDLE );
		// We may be up against the player, so redo the side checks
		m_sideTime = 0;
	}
	else
	{
		GetSenses()->Look( GetSenses()->GetDistLook() );
		CBaseEntity *pEnemy = BestEnemy();
		if ( pEnemy && pEnemy->GetWaterLevel() != 0 )
		{
			SetEnemy ( pEnemy );
			SetState( NPC_STATE_COMBAT );
			m_stateTime = gpGlobals->curtime + random->RandomFloat( 18, 25 );
			AlertSound();
		}
	}
}

void CNPC_Leech::RecalculateWaterlevel( void )
{
	// Calculate boundaries
	Vector vecTest = GetLocalOrigin() - Vector(0,0,400);

	trace_t tr;

	UTIL_TraceLine( GetLocalOrigin(), vecTest, MASK_SOLID, this, COLLISION_GROUP_NONE, &tr);
	
	if ( tr.fraction != 1.0 )
		m_bottom = tr.endpos.z + 1;
	else
		m_bottom = vecTest.z;

	m_top = UTIL_WaterLevel( GetLocalOrigin(), GetLocalOrigin().z, GetLocalOrigin().z + 400 ) - 1;

⌨️ 快捷键说明

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