📄 hl1_npc_osprey.cpp
字号:
#include "cbase.h"
#include "beam_shared.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 "hl1_npc_hgrunt.h"
#include "soundent.h"
#include "game.h"
#include "NPCEvent.h"
#include "EntityList.h"
#include "activitylist.h"
#include "animation.h"
#include "engine/IEngineSound.h"
#include "ammodef.h"
#include "basecombatweapon.h"
#include "hl1_basegrenade.h"
#include "customentity.h"
#include "soundenvelope.h"
#include "hl1_cbasehelicopter.h"
#include "IEffects.h"
extern short g_sModelIndexFireball;
typedef struct
{
int isValid;
EHANDLE hGrunt;
Vector vecOrigin;
Vector vecAngles;
} t_ospreygrunt;
#define LOADED_WITH_GRUNTS 0 //WORST NAME EVER!
#define UNLOADING_GRUNTS 1
#define GRUNTS_DEPLOYED 2 //Waiting for them to finish repelin
#define SF_WAITFORTRIGGER 0x40
#define MAX_CARRY 24
#define DEFAULT_SPEED 250
#define HELICOPTER_THINK_INTERVAL 0.1
class CNPC_Osprey : public CBaseHelicopter
{
DECLARE_CLASS( CNPC_Osprey, CBaseHelicopter );
public:
int ObjectCaps( void ) { return BaseClass::ObjectCaps() & ~FCAP_ACROSS_TRANSITION; }
void Spawn( void );
void Precache( void );
Class_T Classify( void ) { return CLASS_NONE; };
int BloodColor( void ) { return DONT_BLEED; }
void FindAllThink( void );
void DeployThink( void );
bool HasDead( void );
void Flight( void );
void HoverThink( void );
CAI_BaseNPC *MakeGrunt( Vector vecSrc );
void InitializeRotorSound( void );
void PrescheduleThink( void );
void Event_Killed( CBaseEntity *pInflictor, CBaseEntity *pAttacker, float flDamage, int bitsDamageType );
void DyingThink( void );
/*
void CrashTouch( CBaseEntity *pOther );
void DyingThink( void );
void CommandUse( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value );
// int TakeDamage( entvars_t* pevInflictor, entvars_t* pevAttacker, float flDamage, int bitsDamageType );
void TraceAttack( CBaseEntity *pAttacker, float flDamage, const Vector &vecDir, trace_t *ptr, int bitsDamageType);
void ShowDamage( void );*/
float m_startTime;
float m_flIdealtilt;
float m_flRotortilt;
float m_flRightHealth;
float m_flLeftHealth;
int m_iUnits;
EHANDLE m_hGrunt[MAX_CARRY];
Vector m_vecOrigin[MAX_CARRY];
EHANDLE m_hRepel[4];
int m_iSoundState;
int m_iSpriteTexture;
int m_iPitch;
int m_iExplode;
int m_iTailGibs;
int m_iBodyGibs;
int m_iEngineGibs;
int m_iDoLeftSmokePuff;
int m_iDoRightSmokePuff;
int m_iRepelState;
float m_flPrevGoalVel;
int m_iRotorAngle;
int m_nDebrisModel;
DECLARE_DATADESC();
};
LINK_ENTITY_TO_CLASS( monster_osprey, CNPC_Osprey );
BEGIN_DATADESC( CNPC_Osprey )
DEFINE_FIELD( CNPC_Osprey, m_startTime, FIELD_TIME ),
DEFINE_FIELD( CNPC_Osprey, m_flIdealtilt, FIELD_FLOAT ),
DEFINE_FIELD( CNPC_Osprey, m_flRotortilt, FIELD_FLOAT ),
DEFINE_FIELD( CNPC_Osprey, m_flRightHealth, FIELD_FLOAT ),
DEFINE_FIELD( CNPC_Osprey, m_flLeftHealth, FIELD_FLOAT ),
DEFINE_FIELD( CNPC_Osprey, m_iUnits, FIELD_INTEGER ),
DEFINE_ARRAY( CNPC_Osprey, m_hGrunt, FIELD_EHANDLE, MAX_CARRY ),
DEFINE_ARRAY( CNPC_Osprey, m_vecOrigin, FIELD_POSITION_VECTOR, MAX_CARRY ),
DEFINE_ARRAY( CNPC_Osprey, m_hRepel, FIELD_EHANDLE, 4 ),
// DEFINE_FIELD( CNPC_Osprey, m_iSoundState, FIELD_INTEGER ),
// DEFINE_FIELD( CNPC_Osprey, m_iSpriteTexture, FIELD_INTEGER ),
// DEFINE_FIELD( CNPC_Osprey, m_iPitch, FIELD_INTEGER ),
DEFINE_FIELD( CNPC_Osprey, m_iDoLeftSmokePuff, FIELD_INTEGER ),
DEFINE_FIELD( CNPC_Osprey, m_iDoRightSmokePuff, FIELD_INTEGER ),
DEFINE_THINKFUNC( CNPC_Osprey, FindAllThink ),
DEFINE_THINKFUNC( CNPC_Osprey, DeployThink ),
/* DEFINE_FUNCTION ( CNPC_Osprey, HoverThink ),
DEFINE_FUNCTION ( CNPC_Osprey, CrashTouch ),
DEFINE_FUNCTION ( CNPC_Osprey, DyingThink ),
DEFINE_FUNCTION ( CNPC_Osprey, CommandUse ),*/
END_DATADESC()
void CNPC_Osprey :: Spawn( void )
{
Precache( );
// motor
SetModel( "models/osprey.mdl" );
m_spawnflags &= ~SF_AWAITINPUT;
BaseClass::Spawn();
Vector mins, maxs;
ExtractBbox( 0, mins, maxs );
// UTIL_SetSize( this, Vector ( -6, -6, -6 ), Vector ( 6, 6, 6 ) ); //HACKHACK - Temp for demo.
UTIL_SetSize( this, mins, maxs );
UTIL_SetOrigin( this, GetAbsOrigin() );
AddFlag( FL_NPC );
m_takedamage = DAMAGE_YES;
m_flRightHealth = 200;
m_flLeftHealth = 200;
m_iHealth = 69;
m_flFieldOfView = 0; // 180 degrees
SetSequence( 0 );
ResetSequenceInfo( );
m_flCycle = random->RandomInt( 0,0xFF );
// InitBoneControllers();
m_startTime = gpGlobals->curtime + 1;
//FindAllThink();
// SetUse( CommandUse );
/* if (!( m_spawnflags & SF_WAITFORTRIGGER))
{
SetThink( gpGlobals->curtime + 1.0 );
}*/
m_flMaxSpeed = (float)BASECHOPPER_MAX_SPEED / 2;
m_iRepelState = LOADED_WITH_GRUNTS;
m_flPrevGoalVel = 9999;
m_iRotorAngle = -1;
SetBoneController( 0, m_iRotorAngle );
}
void CNPC_Osprey::Precache( void )
{
UTIL_PrecacheOther( "monster_human_grunt" );
engine->PrecacheModel("models/osprey.mdl");
engine->PrecacheModel("models/HVR.mdl");
enginesound->PrecacheSound("apache/ap_rotor4.wav");
enginesound->PrecacheSound("weapons/mortarhit.wav");
m_iSpriteTexture = engine->PrecacheModel( "sprites/rope.vmt" );
m_iExplode = engine->PrecacheModel( "sprites/fexplo.vmt" );
m_iTailGibs = engine->PrecacheModel( "models/osprey_tailgibs.mdl" );
m_iBodyGibs = engine->PrecacheModel( "models/osprey_bodygibs.mdl" );
m_iEngineGibs = engine->PrecacheModel( "models/osprey_enginegibs.mdl" );
m_nDebrisModel = engine->PrecacheModel( "models/gibs/metalgibs.mdl" );
BaseClass::Precache();
}
//------------------------------------------------------------------------------
// Purpose :
// Input :
// Output :
//------------------------------------------------------------------------------
void CNPC_Osprey::InitializeRotorSound( void )
{
CSoundEnvelopeController &controller = CSoundEnvelopeController::GetController();
CPASAttenuationFilter filter( this );
m_pRotorSound = controller.SoundCreate( filter, entindex(), CHAN_STATIC, "apache/ap_rotor4.wav", 0.2 );
BaseClass::InitializeRotorSound();
}
void CNPC_Osprey::FindAllThink( void )
{
CBaseEntity *pEntity = NULL;
m_iUnits = 0;
while ( ( pEntity = gEntList.FindEntityByClassname( pEntity, "monster_human_grunt" ) ) != NULL)
{
if ( m_iUnits > MAX_CARRY )
break;
if (pEntity->IsAlive())
{
m_hGrunt[m_iUnits] = pEntity;
m_vecOrigin[m_iUnits] = pEntity->GetAbsOrigin();
m_iUnits++;
}
}
if (m_iUnits == 0)
{
Msg( "osprey error: no grunts to resupply\n");
UTIL_Remove( this );
return;
}
m_startTime = 0.0f;
}
void CNPC_Osprey :: DeployThink( void )
{
Vector vecForward;
Vector vecRight;
Vector vecUp;
Vector vecSrc;
SetLocalAngularVelocity( QAngle ( 0, 0, 0 ) );
SetAbsVelocity( Vector ( 0, 0, 0 ) );
AngleVectors( GetAbsAngles(), &vecForward, &vecRight, &vecUp );
trace_t tr;
UTIL_TraceLine( GetAbsOrigin(), GetAbsOrigin() + Vector( 0, 0, -4096.0), MASK_SOLID_BRUSHONLY, this,COLLISION_GROUP_NONE, &tr);
CSoundEnt::InsertSound ( SOUND_DANGER, tr.endpos, 400, 0.3 );
vecSrc = GetAbsOrigin() + vecForward * 32 + vecRight * 100 + vecUp * -96;
m_hRepel[0] = MakeGrunt( vecSrc );
vecSrc = GetAbsOrigin() + vecForward * -64 + vecRight * 100 + vecUp * -96;
m_hRepel[1] = MakeGrunt( vecSrc );
vecSrc = GetAbsOrigin() + vecForward * 32 + vecRight * -100 + vecUp * -96;
m_hRepel[2] = MakeGrunt( vecSrc );
vecSrc = GetAbsOrigin() + vecForward * -64 + vecRight * -100 + vecUp * -96;
m_hRepel[3] = MakeGrunt( vecSrc );
m_iRepelState = GRUNTS_DEPLOYED;
HoverThink();
}
bool CNPC_Osprey :: HasDead( )
{
for (int i = 0; i < m_iUnits; i++)
{
if (m_hGrunt[i] == NULL || !m_hGrunt[i]->IsAlive())
{
return TRUE;
}
else
{
m_vecOrigin[i] = m_hGrunt[i]->GetAbsOrigin(); // send them to where they died
}
}
return FALSE;
}
void CNPC_Osprey::HoverThink( void )
{
int i = 0;
for (i = 0; i < 4; i++)
{
CBaseEntity *pRepel = (CBaseEntity*)m_hRepel[i];
if ( pRepel != NULL && pRepel->m_iHealth > 0 && pRepel->GetMoveType() == MOVETYPE_FLY )
{
break;
}
}
if ( i == 4 )
m_iRepelState = LOADED_WITH_GRUNTS;
// ShowDamage();
}
CAI_BaseNPC *CNPC_Osprey::MakeGrunt( Vector vecSrc )
{
CBaseEntity *pEntity;
CAI_BaseNPC *pGrunt;
trace_t tr;
UTIL_TraceLine( vecSrc, vecSrc + Vector( 0, 0, -4096.0), MASK_NPCSOLID, this, COLLISION_GROUP_NONE, &tr);
if ( tr.m_pEnt && tr.m_pEnt->GetSolid() != SOLID_BSP)
return NULL;
for (int i = 0; i < m_iUnits; i++)
{
if (m_hGrunt[i] == NULL || !m_hGrunt[i]->IsAlive())
{
if (m_hGrunt[i] != NULL && m_hGrunt[i]->m_nRenderMode == kRenderNormal)
{
m_hGrunt[i]->SUB_StartFadeOut( );
}
pEntity = Create( "monster_human_grunt", vecSrc, GetAbsAngles() );
pGrunt = pEntity->MyNPCPointer( );
pGrunt->SetMoveType( MOVETYPE_FLY );
pGrunt->SetAbsVelocity( Vector( 0, 0, random->RandomFloat( -196, -128 ) ) );
pGrunt->SetActivity( ACT_GLIDE );
pGrunt->RemoveFlag( FL_ONGROUND );
pGrunt->SetOwnerEntity(this);
CBeam *pBeam = CBeam::BeamCreate( "sprites/rope.vmt", 1.0 );
pBeam->PointEntInit( vecSrc + Vector(0,0,112), pGrunt );
pBeam->SetBeamFlags( FBEAM_SOLID );
pBeam->SetColor( 255, 255, 255 );
pBeam->SetThink( SUB_Remove );
pBeam->SetNextThink( gpGlobals->curtime + -4096.0 * tr.fraction / pGrunt->GetAbsVelocity().z + 0.5 );
// ALERT( at_console, "%d at %.0f %.0f %.0f\n", i, m_vecOrigin[i].x, m_vecOrigin[i].y, m_vecOrigin[i].z );
pGrunt->m_vecLastPosition = m_vecOrigin[i];
m_hGrunt[i] = pGrunt;
return pGrunt;
}
}
// ALERT( at_console, "none dead\n");
return NULL;
}
void CNPC_Osprey::Flight( void )
{
if ( m_iRepelState == LOADED_WITH_GRUNTS )
{
BaseClass::Flight();
// adjust angle of osprey rotors
if ( m_angleVelocity > 0 )
{
m_iRotorAngle = UTIL_Approach(-45, m_iRotorAngle, 5 * (m_angleVelocity / 10));
}
else
{
m_iRotorAngle = UTIL_Approach(-1, m_iRotorAngle, 5);
}
SetBoneController( 0, m_iRotorAngle );
}
}
void CNPC_Osprey::PrescheduleThink( void )
{
BaseClass::PrescheduleThink();
StudioFrameAdvance( );
if ( m_startTime != 0.0 && m_startTime <= gpGlobals->curtime )
FindAllThink();
if ( m_pGoalEnt )
{
if ( m_flPrevGoalVel != m_pGoalEnt->m_flSpeed )
{
if ( m_flPrevGoalVel == 0 && m_pGoalEnt->m_flSpeed != 0 )
{
if ( HasDead() && m_iRepelState == LOADED_WITH_GRUNTS )
m_iRepelState = UNLOADING_GRUNTS;
}
m_flPrevGoalVel = m_pGoalEnt->m_flSpeed;
}
}
if ( m_iRepelState == UNLOADING_GRUNTS )
DeployThink();
else if ( m_iRepelState == GRUNTS_DEPLOYED )
HoverThink();
}
void CNPC_Osprey::Event_Killed( CBaseEntity *pInflictor, CBaseEntity *pAttacker, float flDamage, int bitsDamageType )
{
SetMoveType( MOVETYPE_FLYGRAVITY );
SetGravity( 0.3 );
SetLocalAngularVelocity( QAngle( random->RandomFloat( -20, 20 ), 0, random->RandomFloat( -50, 50 ) ) );
//STOP_SOUND( ENT(pev), CHAN_STATIC, "apache/ap_rotor4.wav" );
// add gravity
UTIL_SetSize( this, Vector( -32, -32, -64), Vector( 32, 32, 0) );
SetThink( DyingThink );
SetTouch( CrashTouch );
// pev->nextthink = gpGlobals->curtime + 0.1;
m_iHealth = 0;
m_takedamage = DAMAGE_NO;
m_startTime = gpGlobals->curtime + 4.0;
}
//-----------------------------------------------------------------------------
// Purpose: Lame, temporary death
//-----------------------------------------------------------------------------
void CNPC_Osprey::DyingThink( void )
{
StudioFrameAdvance( );
SetNextThink( gpGlobals->curtime + 0.1f );
if( random->RandomInt( 0, 50 ) == 1 )
{
Vector vecSize = Vector( 60, 60, 30 );
CPVSFilter filter( GetAbsOrigin() );
te->BreakModel( filter, 0.0, &GetAbsOrigin(), &vecSize, &vec3_origin, m_nDebrisModel, 100, 0, 2.5, BREAK_METAL );
}
QAngle angVel = GetLocalAngularVelocity();
if( angVel.y < 400 )
{
angVel.y *= 1.1;
SetLocalAngularVelocity( angVel );
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -