📄 hl1_npc_nihilanth.cpp
字号:
#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 "Sprite.h"
#include "hl1_ai_basenpc.h"
#include "ai_senses.h"
#include "Sprite.h"
#include "beam_shared.h"
#include "logicrelay.h"
#include "AI_Navigator.h"
#define N_SCALE 15
#define N_SPHERES 20
ConVar sk_nihilanth_health( "sk_nihilanth_health", "800" );
ConVar sk_nihilanth_zap( "sk_nihilanth_zap", "30" );
class CNPC_Nihilanth : public CHL1BaseNPC
{
DECLARE_CLASS( CNPC_Nihilanth, CHL1BaseNPC );
public:
void Spawn( void );
void Precache( void );
Class_T Classify( void ) { return CLASS_ALIEN_MILITARY; };
void SetObjectCollisionBox( void )
{
SetAbsMins( GetAbsOrigin() + Vector( -16 * N_SCALE, -16 * N_SCALE, -48 * N_SCALE ) );
SetAbsMaxs( GetAbsOrigin() + Vector( 16 * N_SCALE, 16 * N_SCALE, 28 * N_SCALE ) );
}
/* void Killed( entvars_t *pevAttacker, int iGib );
void GibMonster( void );
void TargetSphere( USE_TYPE useType, float value );
CBaseEntity *RandomTargetname( const char *szName );
void MakeFriend( Vector vecPos );
int TakeDamage( entvars_t* pevInflictor, entvars_t* pevAttacker, float flDamage, int bitsDamageType );
void TraceAttack( entvars_t *pevAttacker, float flDamage, Vector vecDir, TraceResult *ptr, int bitsDamageType);
// x_teleattack1.wav the looping sound of the teleport attack ball.*/
int OnTakeDamage_Alive( const CTakeDamageInfo &info );
void TraceAttack( const CTakeDamageInfo &info, const Vector &vecDir, trace_t *ptr );
void PainSound( void );
void DeathSound( void );
void StartupThink( void );
void NullThink( void );
void HuntThink( void );
void DyingThink( void );
void Flight( void );
void NextActivity( void );
void FloatSequence( void );
void HandleAnimEvent( animevent_t *pEvent );
bool EmitSphere( void );
void ShootBalls( void );
bool AbsorbSphere( void );
void MakeFriend( Vector vecStart );
static const char *pAttackSounds[]; // vocalization: play sometimes when he launches an attack
static const char *pBallSounds[]; // the sound of the lightening ball launch
static const char *pShootSounds[]; // grunting vocalization: play sometimes when he launches an attack
static const char *pRechargeSounds[]; // vocalization: play when he recharges
static const char *pLaughSounds[]; // vocalization: play sometimes when hit and still has lots of health
static const char *pPainSounds[]; // vocalization: play sometimes when hit and has much less health and no more chargers
static const char *pDeathSounds[]; // vocalization: play as he dies
void InputTurnBabyOn( inputdata_t &inputdata );
void InputTurnBabyOff( inputdata_t &inputdata );
float m_flForce;
float m_flNextPainSound;
Vector m_velocity;
Vector m_avelocity;
Vector m_vecTarget;
Vector m_posTarget;
Vector m_vecDesired;
Vector m_posDesired;
float m_flMinZ;
float m_flMaxZ;
Vector m_vecGoal;
float m_flLastSeen;
float m_flPrevSeen;
int m_irritation;
int m_iLevel;
int m_iTeleport;
EHANDLE m_hRecharger;
EHANDLE m_hSphere[N_SPHERES];
int m_iActiveSpheres;
float m_flAdj;
CSprite *m_pBall;
char m_szRechargerTarget[64];
char m_szDrawUse[64];
char m_szTeleportUse[64];
char m_szTeleportTouch[64];
char m_szDeadUse[64];
char m_szDeadTouch[64];
float m_flShootEnd;
float m_flShootTime;
EHANDLE m_hFriend[3];
DECLARE_DATADESC();
};
LINK_ENTITY_TO_CLASS( monster_nihilanth, CNPC_Nihilanth );
BEGIN_DATADESC( CNPC_Nihilanth )
DEFINE_FIELD( CNPC_Nihilanth, m_flForce, FIELD_FLOAT ),
DEFINE_FIELD( CNPC_Nihilanth, m_flNextPainSound, FIELD_TIME ),
DEFINE_FIELD( CNPC_Nihilanth, m_velocity, FIELD_VECTOR ),
DEFINE_FIELD( CNPC_Nihilanth, m_avelocity, FIELD_VECTOR ),
DEFINE_FIELD( CNPC_Nihilanth, m_vecTarget, FIELD_VECTOR ),
DEFINE_FIELD( CNPC_Nihilanth, m_posTarget, FIELD_POSITION_VECTOR ),
DEFINE_FIELD( CNPC_Nihilanth, m_vecDesired, FIELD_VECTOR ),
DEFINE_FIELD( CNPC_Nihilanth, m_posDesired, FIELD_POSITION_VECTOR ),
DEFINE_FIELD( CNPC_Nihilanth, m_flMinZ, FIELD_FLOAT ),
DEFINE_FIELD( CNPC_Nihilanth, m_flMaxZ, FIELD_FLOAT ),
DEFINE_FIELD( CNPC_Nihilanth, m_vecGoal, FIELD_VECTOR ),
DEFINE_FIELD( CNPC_Nihilanth, m_flLastSeen, FIELD_TIME ),
DEFINE_FIELD( CNPC_Nihilanth, m_flPrevSeen, FIELD_TIME ),
DEFINE_FIELD( CNPC_Nihilanth, m_irritation, FIELD_INTEGER ),
DEFINE_FIELD( CNPC_Nihilanth, m_iLevel, FIELD_INTEGER ),
DEFINE_FIELD( CNPC_Nihilanth, m_iTeleport, FIELD_INTEGER ),
DEFINE_FIELD( CNPC_Nihilanth, m_hRecharger, FIELD_EHANDLE ),
DEFINE_ARRAY( CNPC_Nihilanth, m_hSphere, FIELD_EHANDLE, N_SPHERES ),
DEFINE_FIELD( CNPC_Nihilanth, m_iActiveSpheres, FIELD_INTEGER ),
DEFINE_FIELD( CNPC_Nihilanth, m_flAdj, FIELD_FLOAT ),
DEFINE_FIELD( CNPC_Nihilanth, m_pBall, FIELD_CLASSPTR ),
DEFINE_ARRAY( CNPC_Nihilanth, m_szRechargerTarget, FIELD_CHARACTER, 64 ),
DEFINE_ARRAY( CNPC_Nihilanth, m_szDrawUse, FIELD_CHARACTER, 64 ),
DEFINE_ARRAY( CNPC_Nihilanth, m_szTeleportUse, FIELD_CHARACTER, 64 ),
DEFINE_ARRAY( CNPC_Nihilanth, m_szTeleportTouch, FIELD_CHARACTER, 64 ),
DEFINE_ARRAY( CNPC_Nihilanth, m_szDeadUse, FIELD_CHARACTER, 64 ),
DEFINE_ARRAY( CNPC_Nihilanth, m_szDeadTouch, FIELD_CHARACTER, 64 ),
DEFINE_FIELD( CNPC_Nihilanth, m_flShootEnd, FIELD_TIME ),
DEFINE_FIELD( CNPC_Nihilanth, m_flShootTime, FIELD_TIME ),
DEFINE_ARRAY( CNPC_Nihilanth, m_hFriend, FIELD_EHANDLE, 3 ),
DEFINE_THINKFUNC( CNPC_Nihilanth, NullThink ),
DEFINE_THINKFUNC( CNPC_Nihilanth, StartupThink ),
DEFINE_THINKFUNC( CNPC_Nihilanth, HuntThink ),
DEFINE_THINKFUNC( CNPC_Nihilanth, DyingThink ),
DEFINE_INPUTFUNC( CNPC_Nihilanth, FIELD_VOID, "TurnBabyOn", InputTurnBabyOn ),
DEFINE_INPUTFUNC( CNPC_Nihilanth, FIELD_VOID, "TurnBabyOff", InputTurnBabyOff ),
END_DATADESC()
class CNihilanthHVR : public CAI_BaseNPC
{
DECLARE_CLASS( CNihilanthHVR, CBaseEntity );
public:
void Spawn( void );
void Precache( void );
void CircleInit( CBaseEntity *pTarget );
void AbsorbInit( void );
void GreenBallInit( void );
void RemoveTouch( CBaseEntity *pOther );
/*void Zap( void );
void Teleport( void );*/
void HoverThink( void );
bool CircleTarget( Vector vecTarget );
void BounceTouch( CBaseEntity *pOther );
void ZapThink( void );
void ZapInit( CBaseEntity *pEnemy );
void ZapTouch( CBaseEntity *pOther );
void TeleportThink( void );
void TeleportTouch( CBaseEntity *pOther );
void MovetoTarget( Vector vecTarget );
void DissipateThink( void );
CSprite *SpriteInit( const char *pSpriteName, CNihilanthHVR *pOwner );
void TeleportInit( CNPC_Nihilanth *pOwner, CBaseEntity *pEnemy, CBaseEntity *pTarget, CBaseEntity *pTouch );
float m_flIdealVel;
Vector m_vecIdeal;
CNPC_Nihilanth *m_pNihilanth;
EHANDLE m_hTouch;
float m_flBallScale;
void SetSprite( CBaseEntity *pSprite )
{
m_hSprite = pSprite;
}
CBaseEntity *GetSprite( void )
{
return m_hSprite.Get();
}
void SetBeam( CBaseEntity *pBeam )
{
m_hBeam = pBeam;
}
CBaseEntity *GetBeam( void )
{
return m_hBeam.Get();
}
private:
EHANDLE m_hSprite;
EHANDLE m_hBeam;
DECLARE_DATADESC();
};
LINK_ENTITY_TO_CLASS( nihilanth_energy_ball, CNihilanthHVR );
BEGIN_DATADESC( CNihilanthHVR )
DEFINE_FIELD( CNihilanthHVR, m_flIdealVel, FIELD_FLOAT ),
DEFINE_FIELD( CNihilanthHVR, m_flBallScale, FIELD_FLOAT ),
DEFINE_FIELD( CNihilanthHVR, m_vecIdeal, FIELD_VECTOR ),
DEFINE_FIELD( CNihilanthHVR, m_pNihilanth, FIELD_CLASSPTR ),
DEFINE_FIELD( CNihilanthHVR, m_hTouch, FIELD_EHANDLE ),
DEFINE_FIELD( CNihilanthHVR, m_hSprite, FIELD_EHANDLE ),
DEFINE_THINKFUNC( CNihilanthHVR, HoverThink ),
DEFINE_ENTITYFUNC( CNihilanthHVR, BounceTouch ),
DEFINE_THINKFUNC( CNihilanthHVR, ZapThink ),
DEFINE_ENTITYFUNC( CNihilanthHVR, ZapTouch ),
DEFINE_THINKFUNC( CNihilanthHVR, DissipateThink ),
DEFINE_THINKFUNC( CNihilanthHVR, TeleportThink ),
DEFINE_ENTITYFUNC( CNihilanthHVR, TeleportTouch ),
DEFINE_ENTITYFUNC( CNihilanthHVR, RemoveTouch ),
END_DATADESC()
//=========================================================
// Nihilanth, final Boss monster
//=========================================================
const char *CNPC_Nihilanth::pAttackSounds[] =
{
"X/x_attack1.wav",
"X/x_attack2.wav",
"X/x_attack3.wav",
};
const char *CNPC_Nihilanth::pBallSounds[] =
{
"X/x_ballattack1.wav",
};
const char *CNPC_Nihilanth::pShootSounds[] =
{
"X/x_shoot1.wav",
};
const char *CNPC_Nihilanth::pRechargeSounds[] =
{
"X/x_recharge1.wav",
"X/x_recharge2.wav",
"X/x_recharge3.wav",
};
const char *CNPC_Nihilanth::pLaughSounds[] =
{
"X/x_laugh1.wav",
"X/x_laugh2.wav",
};
const char *CNPC_Nihilanth::pPainSounds[] =
{
"X/x_pain1.wav",
"X/x_pain2.wav",
};
const char *CNPC_Nihilanth::pDeathSounds[] =
{
"X/x_die1.wav",
};
void CNPC_Nihilanth::Spawn( void )
{
Precache( );
// motor
SetMoveType( MOVETYPE_FLY );
SetSolid( SOLID_BBOX );
SetModel( "models/nihilanth.mdl" );
//UTIL_SetSize( this, Vector( -300, -300, 0), Vector(300, 300, 512));
//UTIL_SetSize(this, Vector( -32, -32, 0), Vector(32, 32, 64 ));
UTIL_SetSize(this, Vector( -16 * N_SCALE, -16 * N_SCALE, -48 * N_SCALE ), Vector( 16 * N_SCALE, 16 * N_SCALE, 28 * N_SCALE ) );
UTIL_SetOrigin( this, GetAbsOrigin() - Vector( 0, 0, 64 ) );
AddFlag( FL_NPC );
m_takedamage = DAMAGE_AIM;
m_iHealth = sk_nihilanth_health.GetFloat();
SetViewOffset ( Vector( 0, 0, 300 ) );
m_flFieldOfView = -1; // 360 degrees
SetSequence( 0 );
ResetSequenceInfo( );
InitBoneControllers();
SetThink( &CNPC_Nihilanth::StartupThink );
SetNextThink( gpGlobals->curtime + 0.1 );
m_vecDesired = Vector( 1, 0, 0 );
m_posDesired = Vector( GetAbsOrigin().x, GetAbsOrigin().y, 512 );
m_iLevel = 1;
m_iTeleport = 1;
if (m_szRechargerTarget[0] == '\0') strcpy( m_szRechargerTarget, "n_recharger" );
if (m_szDrawUse[0] == '\0') strcpy( m_szDrawUse, "n_draw" );
if (m_szTeleportUse[0] == '\0') strcpy( m_szTeleportUse, "n_leaving" );
if (m_szTeleportTouch[0] == '\0') strcpy( m_szTeleportTouch, "n_teleport" );
if (m_szDeadUse[0] == '\0') strcpy( m_szDeadUse, "n_dead" );
if (m_szDeadTouch[0] == '\0') strcpy( m_szDeadTouch, "n_ending" );
SetBloodColor( BLOOD_COLOR_YELLOW );
}
void CNPC_Nihilanth::Precache( void )
{
engine->PrecacheModel("models/nihilanth.mdl");
engine->PrecacheModel("sprites/lgtning.vmt");
UTIL_PrecacheOther( "nihilanth_energy_ball" );
UTIL_PrecacheOther( "monster_alien_controller" );
UTIL_PrecacheOther( "monster_alien_slave" );
PRECACHE_SOUND_ARRAY( pAttackSounds );
PRECACHE_SOUND_ARRAY( pBallSounds );
PRECACHE_SOUND_ARRAY( pShootSounds );
PRECACHE_SOUND_ARRAY( pRechargeSounds );
PRECACHE_SOUND_ARRAY( pLaughSounds );
PRECACHE_SOUND_ARRAY( pPainSounds );
PRECACHE_SOUND_ARRAY( pDeathSounds );
enginesound->PrecacheSound("debris/beamstart7.wav");
}
void CNPC_Nihilanth::PainSound( void )
{
if (m_flNextPainSound > gpGlobals->curtime)
return;
m_flNextPainSound = gpGlobals->curtime + random->RandomFloat( 2, 5 );
if ( m_iHealth > sk_nihilanth_health.GetFloat() / 2)
{
CPASAttenuationFilter filter( this );
enginesound->EmitSound( filter, entindex(), CHAN_VOICE, RANDOM_SOUND_ARRAY( pLaughSounds ), 1, 0.2 );
}
else if (m_irritation >= 2)
{
CPASAttenuationFilter filter( this );
enginesound->EmitSound( filter, entindex(), CHAN_VOICE, RANDOM_SOUND_ARRAY( pPainSounds ), 1, 0.2 );
}
}
void CNPC_Nihilanth::DeathSound( void )
{
CPASAttenuationFilter filter( this );
enginesound->EmitSound( filter, entindex(), CHAN_VOICE, RANDOM_SOUND_ARRAY( pDeathSounds ), 1, 0.1 );
}
int CNPC_Nihilanth::OnTakeDamage_Alive( const CTakeDamageInfo &info )
{
if ( info.GetInflictor() == this )
return 0;
if ( info.GetDamage() >= m_iHealth )
{
m_iHealth = 1;
if ( m_irritation != 3 )
return 0;
}
PainSound( );
m_iHealth -= info.GetDamage();
return 0;
}
void CNPC_Nihilanth::TraceAttack( const CTakeDamageInfo &info, const Vector &vecDir, trace_t *ptr )
{
if (m_irritation == 3)
m_irritation = 2;
if (m_irritation == 2 && ptr->hitbox == 3 && info.GetDamage() > 2)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -