diff options
| author | FluorescentCIAAfricanAmerican <[email protected]> | 2020-04-22 12:56:21 -0400 |
|---|---|---|
| committer | FluorescentCIAAfricanAmerican <[email protected]> | 2020-04-22 12:56:21 -0400 |
| commit | 3bf9df6b2785fa6d951086978a3e66f49427166a (patch) | |
| tree | 2c0f1f0c63c4832882bc93814ebd2c2b1c6224e5 /game/server/hl2/npc_bullseye.cpp | |
| download | archived-source-engine-2018-hl2-src-master.tar.xz archived-source-engine-2018-hl2-src-master.zip | |
Diffstat (limited to 'game/server/hl2/npc_bullseye.cpp')
| -rw-r--r-- | game/server/hl2/npc_bullseye.cpp | 473 |
1 files changed, 473 insertions, 0 deletions
diff --git a/game/server/hl2/npc_bullseye.cpp b/game/server/hl2/npc_bullseye.cpp new file mode 100644 index 0000000..6dcbf85 --- /dev/null +++ b/game/server/hl2/npc_bullseye.cpp @@ -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 ); +} |