mirror of
https://github.com/nillerusr/source-engine.git
synced 2026-08-13 04:09:09 +00:00
1
This commit is contained in:
@@ -0,0 +1,473 @@
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose: Bullseyes act as targets for other NPC's to attack and to trigger
|
||||
// events
|
||||
//
|
||||
// $NoKeywords: $
|
||||
//=============================================================================//
|
||||
|
||||
#include "cbase.h"
|
||||
#include "basecombatcharacter.h"
|
||||
#include "ai_basenpc.h"
|
||||
#include "decals.h"
|
||||
#include "filters.h"
|
||||
#include "npc_bullseye.h"
|
||||
#include "collisionutils.h"
|
||||
#include "igamesystem.h"
|
||||
|
||||
// memdbgon must be the last include file in a .cpp file!!!
|
||||
#include "tier0/memdbgon.h"
|
||||
|
||||
class CBullseyeList : public CAutoGameSystem
|
||||
{
|
||||
public:
|
||||
CBullseyeList( char const *name ) : CAutoGameSystem( name )
|
||||
{
|
||||
}
|
||||
|
||||
virtual void LevelShutdownPostEntity()
|
||||
{
|
||||
Clear();
|
||||
}
|
||||
|
||||
void Clear()
|
||||
{
|
||||
m_list.Purge();
|
||||
}
|
||||
|
||||
void AddToList( CNPC_Bullseye *pBullseye );
|
||||
void RemoveFromList( CNPC_Bullseye *pBullseye );
|
||||
|
||||
CUtlVector< CNPC_Bullseye * > m_list;
|
||||
};
|
||||
|
||||
void CBullseyeList::AddToList( CNPC_Bullseye *pBullseye )
|
||||
{
|
||||
m_list.AddToTail( pBullseye );
|
||||
}
|
||||
|
||||
void CBullseyeList::RemoveFromList( CNPC_Bullseye *pBullseye )
|
||||
{
|
||||
int index = m_list.Find( pBullseye );
|
||||
if ( index != m_list.InvalidIndex() )
|
||||
{
|
||||
m_list.FastRemove( index );
|
||||
}
|
||||
}
|
||||
|
||||
CBullseyeList g_BullseyeList( "CBullseyeList" );
|
||||
|
||||
int FindBullseyesInCone( CBaseEntity **pList, int listMax, const Vector &coneOrigin, const Vector &coneAxis, float coneAngleCos, float coneLength )
|
||||
{
|
||||
if ( listMax <= 0 )
|
||||
return 0;
|
||||
|
||||
int count = 0;
|
||||
|
||||
for ( int i = g_BullseyeList.m_list.Count() - 1; i >= 0; --i )
|
||||
{
|
||||
CNPC_Bullseye *pTest = g_BullseyeList.m_list[i];
|
||||
|
||||
if ( IsPointInCone( pTest->GetAbsOrigin(), coneOrigin, coneAxis, coneAngleCos, coneLength ) )
|
||||
{
|
||||
pList[count] = pTest;
|
||||
count++;
|
||||
if ( count >= listMax )
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
|
||||
ConVar sk_bullseye_health( "sk_bullseye_health","0");
|
||||
|
||||
BEGIN_DATADESC( CNPC_Bullseye )
|
||||
|
||||
DEFINE_FIELD( m_hPainPartner, FIELD_EHANDLE ),
|
||||
DEFINE_KEYFIELD( m_fAutoaimRadius, FIELD_FLOAT, "autoaimradius" ),
|
||||
DEFINE_KEYFIELD( m_flFieldOfView, FIELD_FLOAT, "minangle" ),
|
||||
DEFINE_KEYFIELD( m_flMinDistValidEnemy, FIELD_FLOAT, "mindist" ),
|
||||
// DEFINE_FIELD( m_bPerfectAccuracy, FIELD_BOOLEAN ), // Don't save
|
||||
|
||||
// Function Pointers
|
||||
DEFINE_THINKFUNC( BullseyeThink ),
|
||||
|
||||
DEFINE_INPUTFUNC( FIELD_VOID, "InputTargeted", InputTargeted ),
|
||||
DEFINE_INPUTFUNC( FIELD_VOID, "InputReleased", InputReleased ),
|
||||
// Outputs
|
||||
DEFINE_OUTPUT( m_OnTargeted, "OnTargeted"),
|
||||
DEFINE_OUTPUT( m_OnReleased, "OnReleased"),
|
||||
|
||||
END_DATADESC()
|
||||
|
||||
LINK_ENTITY_TO_CLASS( npc_bullseye, CNPC_Bullseye );
|
||||
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Constructor
|
||||
//-----------------------------------------------------------------------------
|
||||
CNPC_Bullseye::CNPC_Bullseye( void )
|
||||
{
|
||||
m_takedamage = DAMAGE_YES;
|
||||
m_iHealth = sk_bullseye_health.GetFloat();
|
||||
m_hPainPartner = NULL;
|
||||
g_BullseyeList.AddToList( this );
|
||||
m_flFieldOfView = 360;
|
||||
m_flMinDistValidEnemy = 0;
|
||||
}
|
||||
|
||||
CNPC_Bullseye::~CNPC_Bullseye( void )
|
||||
{
|
||||
g_BullseyeList.RemoveFromList( this );
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
void CNPC_Bullseye::Precache( void )
|
||||
{
|
||||
BaseClass::Precache();
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
void CNPC_Bullseye::Spawn( void )
|
||||
{
|
||||
Precache();
|
||||
|
||||
// This is a dummy model that is never used!
|
||||
UTIL_SetSize(this, Vector(-16,-16,-16), Vector(16,16,16));
|
||||
|
||||
SetMoveType( MOVETYPE_NONE );
|
||||
SetBloodColor( BLOOD_COLOR_RED );
|
||||
ClearEffects();
|
||||
SetGravity( 0.0 );
|
||||
|
||||
m_flFieldOfView = cos( DEG2RAD(m_flFieldOfView) / 2.0 );
|
||||
|
||||
//Got blood?
|
||||
if ( m_spawnflags & SF_BULLSEYE_BLEED )
|
||||
{
|
||||
SetBloodColor(BLOOD_COLOR_RED);
|
||||
}
|
||||
else
|
||||
{
|
||||
SetBloodColor(DONT_BLEED);
|
||||
}
|
||||
|
||||
AddFlag( FL_NPC );
|
||||
AddEFlags( EFL_NO_DISSOLVE );
|
||||
|
||||
SetThink( &CNPC_Bullseye::BullseyeThink );
|
||||
SetNextThink( gpGlobals->curtime + 0.1f );
|
||||
|
||||
SetSolid( SOLID_BBOX );
|
||||
AddSolidFlags( FSOLID_NOT_STANDABLE );
|
||||
if( m_spawnflags & SF_BULLSEYE_NONSOLID )
|
||||
{
|
||||
AddSolidFlags( FSOLID_NOT_SOLID );
|
||||
}
|
||||
|
||||
if ( m_spawnflags & SF_BULLSEYE_VPHYSICSSHADOW )
|
||||
{
|
||||
VPhysicsInitShadow( false, false );
|
||||
}
|
||||
|
||||
if( m_spawnflags & SF_BULLSEYE_NODAMAGE )
|
||||
{
|
||||
m_takedamage = DAMAGE_NO;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_takedamage = DAMAGE_YES;
|
||||
}
|
||||
AddEffects( EF_NODRAW );
|
||||
|
||||
//Check our water level
|
||||
PhysicsCheckWater();
|
||||
|
||||
CapabilitiesAdd( bits_CAP_SIMPLE_RADIUS_DAMAGE );
|
||||
|
||||
m_iMaxHealth = GetHealth();
|
||||
|
||||
if( m_fAutoaimRadius > 0.0f )
|
||||
{
|
||||
// Make this an aimtarget, since it has some autoaim influence.
|
||||
AddFlag(FL_AIMTARGET);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
void CNPC_Bullseye::Activate( void )
|
||||
{
|
||||
BaseClass::Activate();
|
||||
|
||||
if ( m_spawnflags & SF_BULLSEYE_PERFECTACC )
|
||||
{
|
||||
m_bPerfectAccuracy = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_bPerfectAccuracy = false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Purpose : Override so doesn't fall to ground when killed
|
||||
//------------------------------------------------------------------------------
|
||||
void CNPC_Bullseye::Event_Killed( const CTakeDamageInfo &info )
|
||||
{
|
||||
BaseClass::Event_Killed( info );
|
||||
|
||||
if( GetParent() )
|
||||
{
|
||||
if( GetParent()->ClassMatches("prop_combine_ball") )
|
||||
{
|
||||
// If this bullseye is parented to a combine ball, explode the combine ball
|
||||
// and remove this bullseye.
|
||||
variant_t emptyVariant;
|
||||
GetParent()->AcceptInput( "explode", this, this, emptyVariant, 0 );
|
||||
|
||||
// Unhook.
|
||||
SetParent(NULL);
|
||||
|
||||
UTIL_Remove(this);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
SetMoveType( MOVETYPE_NONE );
|
||||
AddSolidFlags( FSOLID_NOT_SOLID );
|
||||
UTIL_SetSize(this, vec3_origin, vec3_origin );
|
||||
|
||||
SetNextThink( gpGlobals->curtime + 0.1f );
|
||||
SetThink( &CBaseEntity::SUB_Remove );
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Purpose : Override base implimentation to let decals pass through
|
||||
// me onto the surface beneath
|
||||
// Input :
|
||||
// Output :
|
||||
//------------------------------------------------------------------------------
|
||||
void CNPC_Bullseye::DecalTrace( trace_t *pOldTrace, char const *decalName )
|
||||
{
|
||||
int index = decalsystem->GetDecalIndexForName( decalName );
|
||||
if ( index < 0 )
|
||||
return;
|
||||
|
||||
// Get direction of original trace
|
||||
Vector vTraceDir = pOldTrace->endpos - pOldTrace->startpos;
|
||||
VectorNormalize(vTraceDir);
|
||||
|
||||
// Create a new trace that passes through me
|
||||
Vector vStartTrace = pOldTrace->endpos - (1.0 * vTraceDir);
|
||||
Vector vEndTrace = pOldTrace->endpos + (MAX_TRACE_LENGTH * vTraceDir);
|
||||
|
||||
trace_t pNewTrace;
|
||||
AI_TraceLine(vStartTrace, vEndTrace, MASK_SHOT, this, COLLISION_GROUP_NONE, &pNewTrace);
|
||||
|
||||
CBroadcastRecipientFilter filter;
|
||||
te->Decal( filter, 0.0, &pNewTrace.endpos, &pNewTrace.startpos,
|
||||
ENTINDEX( pNewTrace.m_pEnt ), pNewTrace.hitbox, index );
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
void CNPC_Bullseye::ImpactTrace( trace_t *pTrace, int iDamageType, const char *pCustomImpactName )
|
||||
{
|
||||
// Get direction of original trace
|
||||
Vector vTraceDir = pTrace->endpos - pTrace->startpos;
|
||||
VectorNormalize(vTraceDir);
|
||||
|
||||
// Create a new trace that passes through me
|
||||
Vector vStartTrace = pTrace->endpos - (1.0 * vTraceDir);
|
||||
Vector vEndTrace = pTrace->endpos + (MAX_TRACE_LENGTH * vTraceDir);
|
||||
|
||||
trace_t pNewTrace;
|
||||
AI_TraceLine(vStartTrace, vEndTrace, MASK_SHOT, this, COLLISION_GROUP_NONE, &pNewTrace);
|
||||
|
||||
CBaseEntity *pEntity = pNewTrace.m_pEnt;
|
||||
|
||||
// Only do this for BSP model entities
|
||||
if ( ( pEntity ) && ( pEntity->IsBSPModel() == false ) )
|
||||
return;
|
||||
|
||||
BaseClass::ImpactTrace( pTrace, iDamageType, pCustomImpactName );
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//
|
||||
//
|
||||
// Output :
|
||||
//-----------------------------------------------------------------------------
|
||||
Class_T CNPC_Bullseye::Classify( void )
|
||||
{
|
||||
return CLASS_BULLSEYE;
|
||||
}
|
||||
|
||||
void CNPC_Bullseye::OnRestore( void )
|
||||
{
|
||||
if ( m_spawnflags & SF_BULLSEYE_VPHYSICSSHADOW )
|
||||
{
|
||||
IPhysicsObject *pObject = VPhysicsGetObject();
|
||||
|
||||
if ( pObject == NULL )
|
||||
{
|
||||
VPhysicsInitShadow( false, false );
|
||||
}
|
||||
}
|
||||
|
||||
BaseClass::OnRestore();
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
void CNPC_Bullseye::BullseyeThink( void )
|
||||
{
|
||||
ClearCondition( COND_LIGHT_DAMAGE );
|
||||
ClearCondition( COND_HEAVY_DAMAGE );
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
//-----------------------------------------------------------------------------
|
||||
bool CNPC_Bullseye::CanBecomeRagdoll()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
//-----------------------------------------------------------------------------
|
||||
bool CNPC_Bullseye::CanBeAnEnemyOf( CBaseEntity *pEnemy )
|
||||
{
|
||||
static const float flFullFov = cos( DEG2RAD(360) / 2.0 );
|
||||
if ( fabsf( m_flFieldOfView - flFullFov ) > .01 )
|
||||
{
|
||||
if ( !FInViewCone( pEnemy ) )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if ( m_flMinDistValidEnemy > 0 )
|
||||
{
|
||||
float distSq = ( GetAbsOrigin().AsVector2D() - pEnemy->GetAbsOrigin().AsVector2D() ).LengthSqr();
|
||||
if ( distSq < Square( m_flMinDistValidEnemy ) )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return BaseClass::CanBeAnEnemyOf( pEnemy );
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Bullseyes should always report light damage if any amount of damage is taken
|
||||
// Input : fDamage - amount of damage
|
||||
// bitsDamageType - damage type
|
||||
//-----------------------------------------------------------------------------
|
||||
bool CNPC_Bullseye::IsLightDamage( const CTakeDamageInfo &info )
|
||||
{
|
||||
return ( info.GetDamage() > 0 );
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
// Input : *pAttacker -
|
||||
// flDamage -
|
||||
// &vecDir -
|
||||
// *ptr -
|
||||
// bitsDamageType -
|
||||
//-----------------------------------------------------------------------------
|
||||
void CNPC_Bullseye::TraceAttack( const CTakeDamageInfo &info, const Vector &vecDir, trace_t *ptr, CDmgAccumulator *pAccumulator )
|
||||
{
|
||||
//If specified, we must be the enemy of the target
|
||||
if ( m_spawnflags & SF_BULLSEYE_ENEMYDAMAGEONLY )
|
||||
{
|
||||
CAI_BaseNPC *pInstigator = info.GetAttacker()->MyNPCPointer();
|
||||
|
||||
if ( pInstigator == NULL )
|
||||
return;
|
||||
|
||||
if ( pInstigator->GetEnemy() != this )
|
||||
return;
|
||||
}
|
||||
|
||||
//We can bleed if we want to, we can leave decals behind...
|
||||
if ( ( m_spawnflags & SF_BULLSEYE_BLEED ) && ( m_takedamage == DAMAGE_NO ) )
|
||||
{
|
||||
TraceBleed( info.GetDamage(), vecDir, ptr, info.GetDamageType() );
|
||||
}
|
||||
|
||||
BaseClass::TraceAttack( info, vecDir, ptr, pAccumulator );
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
// Input : *pInflictor -
|
||||
// *pAttacker -
|
||||
// flDamage -
|
||||
// bitsDamageType -
|
||||
// Output : int
|
||||
//-----------------------------------------------------------------------------
|
||||
int CNPC_Bullseye::OnTakeDamage( const CTakeDamageInfo &info )
|
||||
{
|
||||
SetNextThink( gpGlobals->curtime );
|
||||
|
||||
//If specified, we must be the enemy of the target
|
||||
if ( m_spawnflags & SF_BULLSEYE_ENEMYDAMAGEONLY )
|
||||
{
|
||||
CAI_BaseNPC *pInstigator = info.GetAttacker()->MyNPCPointer();
|
||||
|
||||
if ( pInstigator == NULL )
|
||||
return 0;
|
||||
|
||||
if ( pInstigator->GetEnemy() != this )
|
||||
return 0;
|
||||
}
|
||||
|
||||
//If we're a pain proxy, send the damage through
|
||||
if ( m_hPainPartner != NULL )
|
||||
{
|
||||
m_hPainPartner->TakeDamage( info );
|
||||
|
||||
//Fire all pain indicators but take no real damage
|
||||
CTakeDamageInfo subInfo = info;
|
||||
subInfo.SetDamage( 0 );
|
||||
return BaseClass::OnTakeDamage( subInfo );
|
||||
}
|
||||
|
||||
return BaseClass::OnTakeDamage( info );
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
// Input : *pOther -
|
||||
//-----------------------------------------------------------------------------
|
||||
void CNPC_Bullseye::SetPainPartner( CBaseEntity *pOther )
|
||||
{
|
||||
m_hPainPartner = pOther;
|
||||
}
|
||||
|
||||
void CNPC_Bullseye::InputTargeted( inputdata_t &inputdata )
|
||||
{
|
||||
m_OnTargeted.FireOutput( inputdata.pActivator, inputdata.pCaller, 0 );
|
||||
}
|
||||
|
||||
void CNPC_Bullseye::InputReleased( inputdata_t &inputdata )
|
||||
{
|
||||
m_OnReleased.FireOutput( inputdata.pActivator, inputdata.pCaller, 0 );
|
||||
}
|
||||
Reference in New Issue
Block a user