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_missiledefense.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_missiledefense.cpp')
| -rw-r--r-- | game/server/hl2/npc_missiledefense.cpp | 496 |
1 files changed, 496 insertions, 0 deletions
diff --git a/game/server/hl2/npc_missiledefense.cpp b/game/server/hl2/npc_missiledefense.cpp new file mode 100644 index 0000000..f07984c --- /dev/null +++ b/game/server/hl2/npc_missiledefense.cpp @@ -0,0 +1,496 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#include "cbase.h" +#include "ai_basenpc.h" +#include "ai_hull.h" +#include "ai_senses.h" +#include "ai_memory.h" +#include "soundent.h" +#include "smoke_trail.h" +#include "weapon_rpg.h" +#include "gib.h" +#include "ndebugoverlay.h" +#include "IEffects.h" +#include "vstdlib/random.h" +#include "engine/IEngineSound.h" +#include "ammodef.h" +#include "hl2_shareddefs.h" + +// memdbgon must be the last include file in a .cpp file!!! +#include "tier0/memdbgon.h" + +#define MD_FULLAMMO 50 + + +#define MD_BC_YAW 0 +#define MD_BC_PITCH 1 +#define MD_AP_LGUN 2 +#define MD_AP_RGUN 1 +#define MD_GIB_COUNT 4 +#define MD_GIB_MODEL "models/gibs/missile_defense_gibs.mdl" +#define MD_YAW_SPEED 24 +#define MD_PITCH_SPEED 12 + +//========================================================= +//========================================================= +class CNPC_MissileDefense : public CAI_BaseNPC +{ + DECLARE_CLASS( CNPC_MissileDefense, CAI_BaseNPC ); + DECLARE_DATADESC(); + +public: + CNPC_MissileDefense( void ) { }; + void Precache( void ); + void Spawn( void ); + Class_T Classify( void ) { return CLASS_NONE; } + int GetSoundInterests( void ) { return SOUND_NONE; } + float MaxYawSpeed( void ) { return 90.f; } + + void RunAI(void); + void FireCannons( void ); + void AimGun( void ); + void EnemyShootPosition(CBaseEntity* pEnemy, Vector *vPosition); + + void Event_Killed( const CTakeDamageInfo &info ); + int OnTakeDamage_Alive( const CTakeDamageInfo &info ); + void Gib(); + void GetGunAim( Vector *vecAim ); + ~CNPC_MissileDefense(); + + Vector m_vGunAng; + int m_iAmmoLoaded; + float m_flReloadedTime; +}; + +LINK_ENTITY_TO_CLASS( npc_missiledefense, CNPC_MissileDefense ); + +//========================================================= +//========================================================= +BEGIN_DATADESC( CNPC_MissileDefense ) + + DEFINE_FIELD( m_iAmmoLoaded, FIELD_INTEGER ), + DEFINE_FIELD( m_flReloadedTime, FIELD_TIME ), + DEFINE_FIELD( m_vGunAng, FIELD_VECTOR ), + +END_DATADESC() + +//--------------------------------------------------------- +//--------------------------------------------------------- +void CNPC_MissileDefense::Precache( void ) +{ + PrecacheModel("models/missile_defense.mdl"); + PrecacheModel(MD_GIB_MODEL); + + PrecacheScriptSound( "NPC_MissileDefense.Attack" ); + PrecacheScriptSound( "NPC_MissileDefense.Reload" ); + PrecacheScriptSound( "NPC_MissileDefense.Turn" ); + +} + + +//--------------------------------------------------------- +//--------------------------------------------------------- +void CNPC_MissileDefense::GetGunAim( Vector *vecAim ) +{ + Vector vecPos; + QAngle vecAng; + + GetAttachment( MD_AP_LGUN, vecPos, vecAng ); + + vecAng.x = GetLocalAngles().x + GetBoneController( MD_BC_PITCH ); + vecAng.z = 0; + vecAng.y = GetLocalAngles().y + GetBoneController( MD_BC_YAW ); + + Vector vecForward; + AngleVectors( vecAng, &vecForward ); + + *vecAim = vecForward; +} + + +#define NOISE 0.035f +#define MD_ATTN_CANNON 0.4 +//------------------------------------------------------------------------------ +// Purpose : +// Input : +// Output : +//------------------------------------------------------------------------------ +void CNPC_MissileDefense::FireCannons( void ) +{ + // ---------------------------------------------- + // Make sure I have an enemy + // ---------------------------------------------- + if (GetEnemy() == NULL) + { + return; + } + + // ---------------------------------------------- + // Make sure I have ammo + // ---------------------------------------------- + if( m_iAmmoLoaded < 1 ) + { + return; + } + // ---------------------------------------------- + // Make sure gun it pointing in right direction + // ---------------------------------------------- + Vector vGunDir; + GetGunAim( &vGunDir ); + Vector vTargetPos; + EnemyShootPosition(GetEnemy(),&vTargetPos); + + Vector vTargetDir = vTargetPos - GetAbsOrigin(); + VectorNormalize( vTargetDir ); + + float fDotPr = DotProduct( vGunDir, vTargetDir ); + if (fDotPr < 0.95) + { + return; + } + + // ---------------------------------------------- + // Check line of sight + // ---------------------------------------------- + trace_t tr; + AI_TraceLine( GetEnemy()->EyePosition(), GetAbsOrigin(), MASK_SOLID_BRUSHONLY, this, COLLISION_GROUP_NONE, &tr); + if (tr.fraction < 1.0) + { + return; + } + + Vector vecRight; + Vector vecDir; + Vector vecCenter; + AngleVectors( GetLocalAngles(), NULL, &vecRight, NULL ); + + vecCenter = WorldSpaceCenter(); + + if( GetEnemy() == NULL ) + { + return; + } + + bool fSound = false; + if( random->RandomInt( 0, 3 ) == 0 ) + { + fSound = true; + } + + + EmitSound( "NPC_MissileDefense.Attack" ); + + Vector vecGun; + QAngle vecAng; + + GetAttachment( MD_AP_LGUN, vecGun, vecAng ); + + Vector vecTarget; + EnemyShootPosition(GetEnemy(),&vecTarget); + + vecDir = vecTarget - vecCenter; + VectorNormalize(vecDir); + vecDir.x += random->RandomFloat( -NOISE, NOISE ); + vecDir.y += random->RandomFloat( -NOISE, NOISE ); + + Vector vecStart = vecGun + vecDir * 110; + Vector vecEnd = vecGun + vecDir * 4096; + UTIL_Tracer( vecStart, vecEnd, 0, TRACER_DONT_USE_ATTACHMENT, 3000 + random->RandomFloat( 0, 2000 ), fSound ); + + vecDir = vecTarget - vecCenter; + VectorNormalize(vecDir); + vecDir.x += random->RandomFloat( -NOISE, NOISE ); + vecDir.y += random->RandomFloat( -NOISE, NOISE ); + vecDir.z += random->RandomFloat( -NOISE, NOISE ); + + GetAttachment( MD_AP_RGUN, vecGun, vecAng ); + vecStart = vecGun + vecDir * 110; + vecEnd = vecGun + vecDir * 4096; + UTIL_Tracer( vecStart, vecEnd, 0, TRACER_DONT_USE_ATTACHMENT, 3000 + random->RandomFloat( 0, 2000 ) ); + + m_iAmmoLoaded -= 2; + + if( m_iAmmoLoaded < 1 ) + { + // Incite a reload. + EmitSound( "NPC_MissileDefense.Reload" ); + m_flReloadedTime = gpGlobals->curtime + 0.3; + return; + } + + // Do damage to the missile based on distance. + // if < 1, make damage 0. + + float flDist = (GetEnemy()->GetLocalOrigin() - vecGun).Length(); + float flDamage; + + flDamage = 4000 - flDist; + + flDamage /= 1000.0; + + if( flDamage > 0 ) + { + if( flDist <= 1500 ) + { + flDamage *= 2; + } + + CTakeDamageInfo info( this, this, flDamage, DMG_MISSILEDEFENSE ); + CalculateBulletDamageForce( &info, GetAmmoDef()->Index("SMG1"), vecDir, GetEnemy()->GetAbsOrigin() ); + GetEnemy()->TakeDamage( info ); + } +} + + +//--------------------------------------------------------- +//--------------------------------------------------------- +void CNPC_MissileDefense::Spawn( void ) +{ + Precache(); + + SetModel( "models/missile_defense.mdl" ); + UTIL_SetSize( this, Vector( -36, -36 , 0 ), Vector( 36, 36, 64 ) ); + + SetSolid( SOLID_BBOX ); + SetMoveType( MOVETYPE_NONE ); + m_takedamage = DAMAGE_YES; + SetBloodColor( DONT_BLEED ); + m_iHealth = 10; + m_flFieldOfView = 0.1; + m_NPCState = NPC_STATE_NONE; + CapabilitiesClear(); + CapabilitiesAdd ( bits_CAP_INNATE_RANGE_ATTACK1 ); + + // Hate missiles + AddClassRelationship( CLASS_MISSILE, D_HT, 5 ); + + m_spawnflags |= SF_NPC_LONG_RANGE; + + m_flReloadedTime = gpGlobals->curtime; + + InitBoneControllers(); + + NPCInit(); + + SetBoneController( MD_BC_YAW, 10 ); + SetBoneController( MD_BC_PITCH, 0 ); + + SetBodygroup( 1, 1 ); + SetBodygroup( 2, 1 ); + SetBodygroup( 3, 1 ); + SetBodygroup( 4, 1 ); + + m_NPCState = NPC_STATE_IDLE; +} + +//------------------------------------------------------------------------------ +// Purpose : +// Input : +// Output : +//------------------------------------------------------------------------------ +int CNPC_MissileDefense::OnTakeDamage_Alive( const CTakeDamageInfo &info ) +{ + // Only take blast damage + if (info.GetDamageType() & DMG_BLAST ) + { + return BaseClass::OnTakeDamage_Alive( info ); + } + else + { + return 0; + } +} + +//------------------------------------------------------------------------------ +// Purpose : +// Input : +// Output : +//------------------------------------------------------------------------------ +void CNPC_MissileDefense::Event_Killed( const CTakeDamageInfo &info ) +{ + StopSound( "NPC_MissileDefense.Turn" ); + Gib(); +} + +//------------------------------------------------------------------------------ +// Purpose : +// Input : +// Output : +//------------------------------------------------------------------------------ +void CNPC_MissileDefense::Gib(void) +{ + // Sparks + for (int i = 0; i < 4; i++) + { + Vector sparkPos = GetAbsOrigin(); + sparkPos.x += random->RandomFloat(-12,12); + sparkPos.y += random->RandomFloat(-12,12); + sparkPos.z += random->RandomFloat(-12,12); + g_pEffects->Sparks(sparkPos); + } + // Smoke + UTIL_Smoke(GetAbsOrigin(), random->RandomInt(10, 15), 10); + + // Light + CBroadcastRecipientFilter filter; + + te->DynamicLight( filter, 0.0, + &GetAbsOrigin(), 255, 180, 100, 0, 100, 0.1, 0 ); + + // Remove top parts + SetBodygroup( 1, 0 ); + SetBodygroup( 2, 0 ); + SetBodygroup( 3, 0 ); + SetBodygroup( 4, 0 ); + m_takedamage = 0; + SetThink(NULL); + + // Throw manhackgibs + CGib::SpawnSpecificGibs( this, MD_GIB_COUNT, 300, 500, MD_GIB_MODEL); +} + +//------------------------------------------------------------------------------ +// Purpose : +// Input : +// Output : +//------------------------------------------------------------------------------ +void CNPC_MissileDefense::RunAI( void ) +{ + // If my enemy is dead clear the memory and reset m_hEnemy + if (GetEnemy() != NULL && + !GetEnemy()->IsAlive()) + { + ClearEnemyMemory(); + SetEnemy( NULL ); + } + + if (GetEnemy() == NULL ) + { + GetSenses()->Look( 4092 ); + SetEnemy( BestEnemy( ) ); + + if (GetEnemy() != NULL) + { + m_iAmmoLoaded = MD_FULLAMMO; + m_flReloadedTime = gpGlobals->curtime; + } + } + + if( m_iAmmoLoaded < 1 && gpGlobals->curtime > m_flReloadedTime ) + { + m_iAmmoLoaded = MD_FULLAMMO; + } + + AimGun(); + FireCannons(); + SetNextThink( gpGlobals->curtime + 0.05 ); +} + +//------------------------------------------------------------------------------ +// Purpose : Add a little prediction into my enemy aim position +// Input : +// Output : +//------------------------------------------------------------------------------ +void CNPC_MissileDefense::EnemyShootPosition(CBaseEntity* pEnemy, Vector *vPosition) +{ + // This should never happen, but just in case + if (!pEnemy) + { + return; + } + + *vPosition = pEnemy->GetAbsOrigin(); + + // Add prediction but prevents us from flipping around as enemy approaches us + float flDist = (pEnemy->GetAbsOrigin() - GetAbsOrigin()).Length(); + Vector vPredVel = pEnemy->GetSmoothedVelocity() * 0.5; + if ( flDist > vPredVel.Length()) + { + *vPosition += vPredVel; + } +} + +//------------------------------------------------------------------------------ +// Purpose : +// Input : +// Output : +//------------------------------------------------------------------------------ +void CNPC_MissileDefense::AimGun( void ) +{ + if (GetEnemy() == NULL) + { + StopSound( "NPC_MissileDefense.Turn" ); + return; + } + + Vector forward, right, up; + AngleVectors( GetLocalAngles(), &forward, &right, &up ); + + // Get gun attachment points + Vector vBasePos; + QAngle vBaseAng; + GetAttachment( MD_AP_LGUN, vBasePos, vBaseAng ); + + Vector vTargetPos; + EnemyShootPosition(GetEnemy(),&vTargetPos); + + Vector vTargetDir = vTargetPos - vBasePos; + VectorNormalize( vTargetDir ); + + Vector vecOut; + vecOut.x = DotProduct( forward, vTargetDir ); + vecOut.y = -DotProduct( right, vTargetDir ); + vecOut.z = DotProduct( up, vTargetDir ); + + QAngle angles; + VectorAngles(vecOut, angles); + + if (angles.y > 180) + angles.y = angles.y - 360; + if (angles.y < -180) + angles.y = angles.y + 360; + if (angles.x > 180) + angles.x = angles.x - 360; + if (angles.x < -180) + angles.x = angles.x + 360; + + float flOldX = m_vGunAng.x; + float flOldY = m_vGunAng.y; + + if (angles.x > m_vGunAng.x) + m_vGunAng.x = MIN( angles.x, m_vGunAng.x + MD_PITCH_SPEED ); + if (angles.x < m_vGunAng.x) + m_vGunAng.x = MAX( angles.x, m_vGunAng.x - MD_PITCH_SPEED ); + if (angles.y > m_vGunAng.y) + m_vGunAng.y = MIN( angles.y, m_vGunAng.y + MD_YAW_SPEED ); + if (angles.y < m_vGunAng.y) + m_vGunAng.y = MAX( angles.y, m_vGunAng.y - MD_YAW_SPEED ); + + m_vGunAng.y = SetBoneController( MD_BC_YAW, m_vGunAng.y ); + m_vGunAng.x = SetBoneController( MD_BC_PITCH, m_vGunAng.x ); + + if (flOldX != m_vGunAng.x || flOldY != m_vGunAng.y) + { + EmitSound( "NPC_MissileDefense.Turn" ); + } + else + { + StopSound( "NPC_MissileDefense.Turn" ); + } +} + + +//------------------------------------------------------------------------------ +// Purpose : +// Input : +// Output : +//------------------------------------------------------------------------------ +CNPC_MissileDefense::~CNPC_MissileDefense(void) +{ + StopSound( "NPC_MissileDefense.Turn" ); +} |