mirror of
https://github.com/nillerusr/source-engine.git
synced 2026-08-15 13:16:58 +00:00
1
This commit is contained in:
@@ -0,0 +1,400 @@
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
// $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_memory.h"
|
||||
#include "ai_route.h"
|
||||
#include "ai_motor.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 "te.h"
|
||||
#include "hl1_npc_hornet.h"
|
||||
|
||||
int iHornetTrail;
|
||||
int iHornetPuff;
|
||||
|
||||
LINK_ENTITY_TO_CLASS( hornet, CNPC_Hornet );
|
||||
|
||||
extern ConVar sk_npc_dmg_hornet;
|
||||
extern ConVar sk_plr_dmg_hornet;
|
||||
|
||||
BEGIN_DATADESC( CNPC_Hornet )
|
||||
DEFINE_FIELD( m_flStopAttack, FIELD_TIME ),
|
||||
DEFINE_FIELD( m_iHornetType, FIELD_INTEGER ),
|
||||
DEFINE_FIELD( m_flFlySpeed, FIELD_FLOAT ),
|
||||
DEFINE_FIELD( m_flDamage, FIELD_INTEGER ),
|
||||
DEFINE_FIELD( m_vecEnemyLKP, FIELD_POSITION_VECTOR ),
|
||||
|
||||
|
||||
DEFINE_ENTITYFUNC( DieTouch ),
|
||||
DEFINE_THINKFUNC( StartDart ),
|
||||
DEFINE_THINKFUNC( StartTrack ),
|
||||
DEFINE_ENTITYFUNC( DartTouch ),
|
||||
DEFINE_ENTITYFUNC( TrackTouch ),
|
||||
DEFINE_THINKFUNC( TrackTarget ),
|
||||
END_DATADESC()
|
||||
|
||||
//=========================================================
|
||||
//=========================================================
|
||||
void CNPC_Hornet::Spawn( void )
|
||||
{
|
||||
Precache();
|
||||
|
||||
SetMoveType( MOVETYPE_FLY );
|
||||
SetSolid( SOLID_BBOX );
|
||||
m_takedamage = DAMAGE_YES;
|
||||
AddFlag( FL_NPC );
|
||||
m_iHealth = 1;// weak!
|
||||
m_bloodColor = DONT_BLEED;
|
||||
|
||||
if ( g_pGameRules->IsMultiplayer() )
|
||||
{
|
||||
// hornets don't live as long in multiplayer
|
||||
m_flStopAttack = gpGlobals->curtime + 3.5;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_flStopAttack = gpGlobals->curtime + 5.0;
|
||||
}
|
||||
|
||||
m_flFieldOfView = 0.9; // +- 25 degrees
|
||||
|
||||
if ( random->RandomInt ( 1, 5 ) <= 2 )
|
||||
{
|
||||
m_iHornetType = HORNET_TYPE_RED;
|
||||
m_flFlySpeed = HORNET_RED_SPEED;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_iHornetType = HORNET_TYPE_ORANGE;
|
||||
m_flFlySpeed = HORNET_ORANGE_SPEED;
|
||||
}
|
||||
|
||||
SetModel( "models/hornet.mdl" );
|
||||
UTIL_SetSize( this, Vector( -4, -4, -4 ), Vector( 4, 4, 4 ) );
|
||||
|
||||
SetTouch( &CNPC_Hornet::DieTouch );
|
||||
SetThink( &CNPC_Hornet::StartTrack );
|
||||
|
||||
if ( GetOwnerEntity() && (GetOwnerEntity()->GetFlags() & FL_CLIENT) )
|
||||
{
|
||||
m_flDamage = sk_plr_dmg_hornet.GetFloat();
|
||||
}
|
||||
else
|
||||
{
|
||||
// no real owner, or owner isn't a client.
|
||||
m_flDamage = sk_npc_dmg_hornet.GetFloat();
|
||||
}
|
||||
|
||||
SetNextThink( gpGlobals->curtime + 0.1f );
|
||||
ResetSequenceInfo();
|
||||
|
||||
m_vecEnemyLKP = vec3_origin;
|
||||
}
|
||||
|
||||
|
||||
void CNPC_Hornet::Precache()
|
||||
{
|
||||
PrecacheModel("models/hornet.mdl");
|
||||
|
||||
iHornetPuff = PrecacheModel( "sprites/muz1.vmt" );
|
||||
iHornetTrail = PrecacheModel("sprites/laserbeam.vmt");
|
||||
|
||||
PrecacheScriptSound( "Hornet.Die" );
|
||||
PrecacheScriptSound( "Hornet.Buzz" );
|
||||
}
|
||||
|
||||
//=========================================================
|
||||
// hornets will never get mad at each other, no matter who the owner is.
|
||||
//=========================================================
|
||||
Disposition_t CNPC_Hornet::IRelationType( CBaseEntity *pTarget )
|
||||
{
|
||||
if ( pTarget->GetModelIndex() == GetModelIndex() )
|
||||
{
|
||||
return D_NU;
|
||||
}
|
||||
|
||||
return BaseClass::IRelationType( pTarget );
|
||||
}
|
||||
|
||||
//=========================================================
|
||||
// ID's Hornet as their owner
|
||||
//=========================================================
|
||||
Class_T CNPC_Hornet::Classify ( void )
|
||||
{
|
||||
if ( GetOwnerEntity() && (GetOwnerEntity()->GetFlags() & FL_CLIENT) )
|
||||
{
|
||||
return CLASS_PLAYER_BIOWEAPON;
|
||||
}
|
||||
|
||||
return CLASS_ALIEN_BIOWEAPON;
|
||||
}
|
||||
|
||||
//=========================================================
|
||||
// StartDart - starts a hornet out just flying straight.
|
||||
//=========================================================
|
||||
void CNPC_Hornet::StartDart ( void )
|
||||
{
|
||||
IgniteTrail();
|
||||
|
||||
SetTouch( &CNPC_Hornet::DartTouch );
|
||||
|
||||
SetThink( &CBaseEntity::SUB_Remove );
|
||||
SetNextThink( gpGlobals->curtime + 4 );
|
||||
}
|
||||
|
||||
|
||||
void CNPC_Hornet::DieTouch ( CBaseEntity *pOther )
|
||||
{
|
||||
if ( !pOther || !pOther->IsSolid() || pOther->IsSolidFlagSet(FSOLID_VOLUME_CONTENTS) )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
CPASAttenuationFilter filter( this );
|
||||
EmitSound( filter, entindex(), "Hornet.Die" );
|
||||
|
||||
CTakeDamageInfo info( this, GetOwnerEntity(), m_flDamage, DMG_BULLET );
|
||||
CalculateBulletDamageForce( &info, GetAmmoDef()->Index("Hornet"), GetAbsVelocity(), GetAbsOrigin() );
|
||||
pOther->TakeDamage( info );
|
||||
|
||||
m_takedamage = DAMAGE_NO;
|
||||
|
||||
AddEffects( EF_NODRAW );
|
||||
|
||||
AddSolidFlags( FSOLID_NOT_SOLID );// intangible
|
||||
|
||||
UTIL_Remove( this );
|
||||
SetTouch( NULL );
|
||||
}
|
||||
|
||||
|
||||
//=========================================================
|
||||
// StartTrack - starts a hornet out tracking its target
|
||||
//=========================================================
|
||||
void CNPC_Hornet:: StartTrack ( void )
|
||||
{
|
||||
IgniteTrail();
|
||||
|
||||
SetTouch( &CNPC_Hornet::TrackTouch );
|
||||
SetThink( &CNPC_Hornet::TrackTarget );
|
||||
|
||||
SetNextThink( gpGlobals->curtime + 0.1f );
|
||||
}
|
||||
|
||||
void TE_BeamFollow( IRecipientFilter& filter, float delay,
|
||||
int iEntIndex, int modelIndex, int haloIndex, float life, float width, float endWidth,
|
||||
float fadeLength,float r, float g, float b, float a );
|
||||
|
||||
void CNPC_Hornet::IgniteTrail( void )
|
||||
{
|
||||
Vector vColor;
|
||||
|
||||
if ( m_iHornetType == HORNET_TYPE_RED )
|
||||
vColor = Vector ( 179, 39, 14 );
|
||||
else
|
||||
vColor = Vector ( 255, 128, 0 );
|
||||
|
||||
CBroadcastRecipientFilter filter;
|
||||
TE_BeamFollow( filter, 0.0,
|
||||
entindex(),
|
||||
iHornetTrail,
|
||||
0,
|
||||
1,
|
||||
2,
|
||||
0.5,
|
||||
0.5,
|
||||
vColor.x,
|
||||
vColor.y,
|
||||
vColor.z,
|
||||
128 );
|
||||
}
|
||||
|
||||
|
||||
unsigned int CNPC_Hornet::PhysicsSolidMaskForEntity( void ) const
|
||||
{
|
||||
unsigned int iMask = BaseClass::PhysicsSolidMaskForEntity();
|
||||
|
||||
iMask &= ~CONTENTS_MONSTERCLIP;
|
||||
|
||||
return iMask;
|
||||
}
|
||||
|
||||
//=========================================================
|
||||
// Tracking Hornet hit something
|
||||
//=========================================================
|
||||
void CNPC_Hornet::TrackTouch ( CBaseEntity *pOther )
|
||||
{
|
||||
if ( !pOther->IsSolid() || pOther->IsSolidFlagSet(FSOLID_VOLUME_CONTENTS) )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if ( pOther == GetOwnerEntity() || pOther->GetModelIndex() == GetModelIndex() )
|
||||
{// bumped into the guy that shot it.
|
||||
//SetSolid( SOLID_NOT );
|
||||
return;
|
||||
}
|
||||
|
||||
int nRelationship = IRelationType( pOther );
|
||||
if ( (nRelationship == D_FR || nRelationship == D_NU || nRelationship == D_LI) )
|
||||
{
|
||||
// hit something we don't want to hurt, so turn around.
|
||||
Vector vecVel = GetAbsVelocity();
|
||||
|
||||
VectorNormalize( vecVel );
|
||||
|
||||
vecVel.x *= -1;
|
||||
vecVel.y *= -1;
|
||||
|
||||
SetAbsOrigin( GetAbsOrigin() + vecVel * 4 ); // bounce the hornet off a bit.
|
||||
SetAbsVelocity( vecVel * m_flFlySpeed );
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
DieTouch( pOther );
|
||||
}
|
||||
|
||||
void CNPC_Hornet::DartTouch( CBaseEntity *pOther )
|
||||
{
|
||||
DieTouch( pOther );
|
||||
}
|
||||
|
||||
//=========================================================
|
||||
// Hornet is flying, gently tracking target
|
||||
//=========================================================
|
||||
void CNPC_Hornet::TrackTarget ( void )
|
||||
{
|
||||
Vector vecFlightDir;
|
||||
Vector vecDirToEnemy;
|
||||
float flDelta;
|
||||
|
||||
StudioFrameAdvance( );
|
||||
|
||||
if (gpGlobals->curtime > m_flStopAttack)
|
||||
{
|
||||
SetTouch( NULL );
|
||||
SetThink( &CBaseEntity::SUB_Remove );
|
||||
SetNextThink( gpGlobals->curtime + 0.1f );
|
||||
return;
|
||||
}
|
||||
|
||||
// UNDONE: The player pointer should come back after returning from another level
|
||||
if ( GetEnemy() == NULL )
|
||||
{// enemy is dead.
|
||||
GetSenses()->Look( 1024 );
|
||||
SetEnemy( BestEnemy() );
|
||||
}
|
||||
|
||||
if ( GetEnemy() != NULL && FVisible( GetEnemy() ))
|
||||
{
|
||||
m_vecEnemyLKP = GetEnemy()->BodyTarget( GetAbsOrigin() );
|
||||
}
|
||||
else
|
||||
{
|
||||
m_vecEnemyLKP = m_vecEnemyLKP + GetAbsVelocity() * m_flFlySpeed * 0.1;
|
||||
}
|
||||
|
||||
vecDirToEnemy = m_vecEnemyLKP - GetAbsOrigin();
|
||||
VectorNormalize( vecDirToEnemy );
|
||||
|
||||
if ( GetAbsVelocity().Length() < 0.1 )
|
||||
vecFlightDir = vecDirToEnemy;
|
||||
else
|
||||
{
|
||||
vecFlightDir = GetAbsVelocity();
|
||||
VectorNormalize( vecFlightDir );
|
||||
}
|
||||
|
||||
SetAbsVelocity( vecFlightDir + vecDirToEnemy );
|
||||
|
||||
// measure how far the turn is, the wider the turn, the slow we'll go this time.
|
||||
flDelta = DotProduct ( vecFlightDir, vecDirToEnemy );
|
||||
|
||||
if ( flDelta < 0.5 )
|
||||
{// hafta turn wide again. play sound
|
||||
CPASAttenuationFilter filter( this );
|
||||
EmitSound( filter, entindex(), "Hornet.Buzz" );
|
||||
}
|
||||
|
||||
if ( flDelta <= 0 && m_iHornetType == HORNET_TYPE_RED )
|
||||
{// no flying backwards, but we don't want to invert this, cause we'd go fast when we have to turn REAL far.
|
||||
flDelta = 0.25;
|
||||
}
|
||||
|
||||
Vector vecVel = vecFlightDir + vecDirToEnemy;
|
||||
VectorNormalize( vecVel );
|
||||
|
||||
if ( GetOwnerEntity() && (GetOwnerEntity()->GetFlags() & FL_NPC) )
|
||||
{
|
||||
// random pattern only applies to hornets fired by monsters, not players.
|
||||
|
||||
vecVel.x += random->RandomFloat ( -0.10, 0.10 );// scramble the flight dir a bit.
|
||||
vecVel.y += random->RandomFloat ( -0.10, 0.10 );
|
||||
vecVel.z += random->RandomFloat ( -0.10, 0.10 );
|
||||
}
|
||||
|
||||
switch ( m_iHornetType )
|
||||
{
|
||||
case HORNET_TYPE_RED:
|
||||
SetAbsVelocity( vecVel * ( m_flFlySpeed * flDelta ) );// scale the dir by the ( speed * width of turn )
|
||||
SetNextThink( gpGlobals->curtime + random->RandomFloat( 0.1, 0.3 ) );
|
||||
break;
|
||||
default:
|
||||
Assert( false ); //fall through if release
|
||||
case HORNET_TYPE_ORANGE:
|
||||
SetAbsVelocity( vecVel * m_flFlySpeed );// do not have to slow down to turn.
|
||||
SetNextThink( gpGlobals->curtime + 0.1f );// fixed think time
|
||||
break;
|
||||
}
|
||||
|
||||
QAngle angNewAngles;
|
||||
VectorAngles( GetAbsVelocity(), angNewAngles );
|
||||
SetAbsAngles( angNewAngles );
|
||||
|
||||
SetSolid( SOLID_BBOX );
|
||||
|
||||
// if hornet is close to the enemy, jet in a straight line for a half second.
|
||||
// (only in the single player game)
|
||||
if ( GetEnemy() != NULL && !g_pGameRules->IsMultiplayer() )
|
||||
{
|
||||
if ( flDelta >= 0.4 && ( GetAbsOrigin() - m_vecEnemyLKP ).Length() <= 300 )
|
||||
{
|
||||
CPVSFilter filter( GetAbsOrigin() );
|
||||
te->Sprite( filter, 0.0,
|
||||
&GetAbsOrigin(), // pos
|
||||
iHornetPuff, // model
|
||||
0.2, //size
|
||||
128 // brightness
|
||||
);
|
||||
|
||||
CPASAttenuationFilter filter2( this );
|
||||
EmitSound( filter2, entindex(), "Hornet.Buzz" );
|
||||
SetAbsVelocity( GetAbsVelocity() * 2 );
|
||||
SetNextThink( gpGlobals->curtime + 1.0f );
|
||||
// don't attack again
|
||||
m_flStopAttack = gpGlobals->curtime;
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user