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/shared/tf2/weapon_laserdesignator.cpp | |
| download | archived-source-engine-2018-hl2-src-master.tar.xz archived-source-engine-2018-hl2-src-master.zip | |
Diffstat (limited to 'game/shared/tf2/weapon_laserdesignator.cpp')
| -rw-r--r-- | game/shared/tf2/weapon_laserdesignator.cpp | 394 |
1 files changed, 394 insertions, 0 deletions
diff --git a/game/shared/tf2/weapon_laserdesignator.cpp b/game/shared/tf2/weapon_laserdesignator.cpp new file mode 100644 index 0000000..4f9ef46 --- /dev/null +++ b/game/shared/tf2/weapon_laserdesignator.cpp @@ -0,0 +1,394 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// +#include "cbase.h" +#include "NPCEvent.h" +#include "tf_basecombatweapon.h" +#include "smoke_trail.h" +#include "tf_player.h" +#include "in_buttons.h" +#include "tf_gamerules.h" +#include "ammodef.h" +#include "IEffects.h" +#include "vstdlib/random.h" +#include "effects.h" +#include "baseviewmodel.h" +#include "basegrenade_shared.h" +#include "grenade_limpetmine.h" +#include "tf_obj_sentrygun.h" +#include "tf_obj_aerial_sentry_station.h" + + +// Damage CVars +ConVar weapon_laserdesignator_range( "weapon_laserdesignator_range","1024", FCVAR_NONE, "Laser Designator maximum range" ); + +// ------------------------------------------------------------------------ // +// CWeaponLaserDesignator +// ------------------------------------------------------------------------ // +class CWeaponLaserDesignator : public CBaseTFCombatWeapon +{ + DECLARE_CLASS( CWeaponLaserDesignator, CBaseTFCombatWeapon ); +public: + virtual void Precache( void ); + virtual float GetFireRate( void ); + virtual bool Holster( CBaseCombatWeapon *pSwitchingTo = NULL ); + virtual bool ComputeEMPFireState( void ); + virtual void ItemPostFrame( void ); + virtual void PrimaryAttack( void ); + + bool ValidDesignationTarget( CBaseEntity *pEntity ); + bool TargetIsInLock( CBaseTFPlayer *pPlayer, CBaseEntity *pTarget, float *flMaxDot ); + + // Designation + void StartDesignating( void ); + void StopDesignating( void ); + void UpdateBeam( void ); + void DesignateSentriesToAttack( CBaseEntity *pEntity ); + +public: + // Designation + bool m_bDesignating; + + // Beam + CBeam *m_pBeam; +}; + +LINK_ENTITY_TO_CLASS( weapon_laserdesignator, CWeaponLaserDesignator ); +PRECACHE_WEAPON_REGISTER(weapon_laserdesignator); + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CWeaponLaserDesignator::Precache( void ) +{ + BaseClass::Precache(); + PrecacheModel( "sprites/laserbeam.vmt" ); +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +float CWeaponLaserDesignator::GetFireRate() +{ + return 0.2; +} + +//----------------------------------------------------------------------------- +// Purpose: Stop thinking and holster +//----------------------------------------------------------------------------- +bool CWeaponLaserDesignator::Holster( CBaseCombatWeapon *pSwitchingTo ) +{ + StopDesignating(); + return BaseClass::Holster(pSwitchingTo); +} + +//----------------------------------------------------------------------------- +// Purpose: +// Output : Returns true on success, false on failure. +//----------------------------------------------------------------------------- +bool CWeaponLaserDesignator::ComputeEMPFireState( void ) +{ + if (IsOwnerEMPed()) + { + // FIXME: Need a sound + //UTIL_EmitSound( pPlayer->pev, CHAN_WEAPON, g_pszEMPGatlingFizzle, 1.0, ATTN_NORM ); + return false; + } + return true; +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CWeaponLaserDesignator::ItemPostFrame( void ) +{ + CBasePlayer *pPlayer = GetOwner(); + if (pPlayer == NULL) + return; + + // Are we already welding? + if ( m_bDesignating ) + { + if ( pPlayer->m_nButtons & (IN_ATTACK | IN_ATTACK2) ) + { + UpdateBeam(); + } + else + { + StopDesignating(); + } + } + else + { + if ( (pPlayer->m_nButtons & IN_ATTACK) && (m_flNextPrimaryAttack <= gpGlobals->curtime) ) + { + // Start designating + PrimaryAttack(); + UpdateBeam(); + } + } + + // Always idle + WeaponIdle(); +} + +//----------------------------------------------------------------------------- +// Purpose: Start designating with the laser +//----------------------------------------------------------------------------- +void CWeaponLaserDesignator::StartDesignating( void ) +{ + m_bDesignating = true; + + if ( !m_pBeam ) + { + CBaseTFPlayer *pPlayer = ToBaseTFPlayer( m_hOwner ); + if ( !pPlayer ) + return; + int iIndex = pPlayer->entindex(); + + m_pBeam = CBeam::BeamCreate( "sprites/laserbeam.vmt", 1 ); + m_pBeam->PointEntInit( vec3_origin, iIndex ); + m_pBeam->SetEndAttachment( 1 ); + m_pBeam->SetColor( 255, 32, 32 ); + m_pBeam->SetBrightness( 255 ); + m_pBeam->SetNoise( 0 ); + m_pBeam->SetWidth( 2 ); + m_pBeam->SetEndWidth( 1 ); + m_pBeam->SetStartEntity( ENTINDEX(m_hOwner->edict()) ); + } +} + +//----------------------------------------------------------------------------- +// Purpose: Stop designating with the laser +//----------------------------------------------------------------------------- +void CWeaponLaserDesignator::StopDesignating( void ) +{ + m_bDesignating = false; + if ( m_pBeam ) + { + UTIL_Remove( m_pBeam ); + m_pBeam = NULL; + } +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CWeaponLaserDesignator::PrimaryAttack( void ) +{ + CBaseTFPlayer *pPlayer = ToBaseTFPlayer( m_hOwner ); + if ( !pPlayer ) + return; + + if ( !ComputeEMPFireState() ) + return; + + WeaponSound(SINGLE); + PlayAttackAnimation( GetPrimaryAttackActivity() ); + pPlayer->AddEffects( EF_MUZZLEFLASH ); + + StartDesignating(); +} + +//----------------------------------------------------------------------------- +// Purpose: Update the beam position and do designator functions +//----------------------------------------------------------------------------- +void CWeaponLaserDesignator::UpdateBeam( void ) +{ + CBaseTFPlayer *pPlayer = ToBaseTFPlayer( m_hOwner ); + if ( !pPlayer ) + return; + + ASSERT( m_pBeam ); + + // "Fire" the designator beam + Vector vecSrc = pPlayer->Weapon_ShootPosition( pPlayer->GetOrigin() ); + Vector vecAiming; + pPlayer->EyeVectors( &vecAiming ); + Vector vecEnd = vecSrc + vecAiming * weapon_laserdesignator_range.GetFloat(); + + trace_t tr; + TFGameRules()->WeaponTraceLine(vecSrc, vecEnd, MASK_SHOT, pPlayer, DMG_ENERGYBEAM, &tr); + + // Update beam visual + m_pBeam->SetStartPos( tr.endpos ); + m_pBeam->RelinkBeam(); + + // Perform designator functions + // Did we hit something? + CBaseEntity *pEntity = CBaseEntity::Instance( tr.u.ent ); + if ( pEntity ) + { + // TODO: We dynamic_cast the entity we choose twice. Fix it. + + // If we hit a target we don't care about, try and grab the nearest valid target to our crosshair + if ( !ValidDesignationTarget( pEntity ) ) + { + pEntity = NULL; + + // Grab the entity nearest the crosshair + float bestdot = AUTOAIM_20DEGREES; + float flSize = weapon_laserdesignator_range.GetFloat() * 0.5; + Vector vecCenter = vecSrc + vecAiming * flSize; + + // Find a target. + CBaseEntity *pList[100]; + Vector delta( flSize, flSize, flSize ); + int count = UTIL_EntitiesInBox( pList, 100, vecCenter - delta, vecCenter + delta, FL_CLIENT|FL_NPC|FL_OBJECT ); + for ( int i = 0; i < count; i++ ) + { + CBaseEntity *pTarget = pList[i]; + if ( !ValidDesignationTarget(pTarget) ) + continue; + if ( TargetIsInLock( pPlayer, pTarget, &bestdot ) == false ) + continue; + if ( (pTarget->Center() - pPlayer->Center() ).Length() > weapon_laserdesignator_range.GetFloat() ) + continue; + + // Can shoot at this one + pEntity = pTarget; + } + } + + // Couldn't find anything + if ( !pEntity ) + return; + + // If we hit a player, and it's an enemy, tell my sentryguns to attack it + if ( pEntity->IsPlayer() && !pPlayer->InSameTeam(pEntity) ) + { + DesignateSentriesToAttack( pEntity ); + } + else if ( pEntity->GetFlags() & FL_NPC ) + { + // If it's an enemy NPC, tell my sentryguns to attack it + if ( !pPlayer->InSameTeam( pEntity ) ) + { + DesignateSentriesToAttack( pEntity ); + } + } + else + { + // Is it a sentrygun? If so, tell it to toggle it's sunken state. + if ( pEntity->Classify() == CLASS_MILITARY ) + { + CObjectSentrygun *pSentry = dynamic_cast<CObjectSentrygun *>(pEntity); + if ( pSentry && pSentry->GetBuilder() == pPlayer ) + { + pSentry->ToggleTurtle(); + } + else + { + // If it's an enemy object, tell my sentryguns to attack it + if ( !pPlayer->InSameTeam( pEntity ) ) + { + DesignateSentriesToAttack( pEntity ); + } + } + } + + // Is it a limpet mine? If so, detonate it + CLimpetMine *pLimpet = dynamic_cast<CLimpetMine *>(pEntity); + if ( pLimpet && pLimpet->IsLive() && pLimpet->m_hOwner->pev == pPlayer->pev ) + { + pLimpet->Use( pPlayer, pPlayer, USE_ON, 0 ); + } + } + } +} + +//----------------------------------------------------------------------------- +// Purpose: Return true if the specified entity is a valid one for designation +//----------------------------------------------------------------------------- +bool CWeaponLaserDesignator::ValidDesignationTarget( CBaseEntity *pEntity ) +{ + // Ignore the world + if ( pEntity->entindex() == 0 ) + return false; + + // Ignore players on my team + if ( pEntity->IsPlayer() && pEntity->InSameTeam(m_hOwner) ) + return false; + + // Is it a sentrygun? If so, tell it to toggle it's sunken state. + if ( pEntity->Classify() == CLASS_MILITARY ) + return true; + + // My limpet mines are valid + CLimpetMine *pLimpet = dynamic_cast<CLimpetMine *>(pEntity); + if ( pLimpet && pLimpet->IsLive() && pLimpet->m_hOwner->pev == m_hOwner->pev ) + return true; + + // NPCs are valid + if ( pEntity->GetFlags() & FL_NPC ) + return true; + + return false; +} + +//----------------------------------------------------------------------------- +// Purpose: Return true if the target entity's close enough to the player's crosshair to lock onto +//----------------------------------------------------------------------------- +bool CWeaponLaserDesignator::TargetIsInLock( CBaseTFPlayer *pPlayer, CBaseEntity *pTarget, float *flMaxDot ) +{ + Vector center = pTarget->Center(); + Vector dir = center - pPlayer->Center(); + float length = VectorNormalize( dir ); + Vector forward, right, up; + pPlayer->EyeVectors( &forward, &right, &up ); + + // Make sure it's in front of the player + if ( DotProduct( dir, forward ) < 0.0f ) + return false; + + float dot = fabs( DotProduct(dir, right ) ) + fabs( DotProduct(dir, up ) ); + + // Tweak for distance + dot *= 1.0f + 4.0f * ( length / MAX_COORD_RANGE ); + + // Outside the dot? + if ( dot > *flMaxDot ) + return false; + + // Open LOS? + trace_t tr; + UTIL_TraceLine( pPlayer->Center(), center, MASK_SHOT, edict(), COLLISION_GROUP_NONE, &tr ); + if ( ( tr.fraction != 1.0f ) && ( tr.u.ent != pTarget->edict() ) ) + return false; + + *flMaxDot = dot; + return true; +} + +//----------------------------------------------------------------------------- +// Purpose: Set the player's sentryguns to all attack the specified target +//----------------------------------------------------------------------------- +void CWeaponLaserDesignator::DesignateSentriesToAttack( CBaseEntity *pEntity ) +{ + CBaseTFPlayer *pPlayer = ToBaseTFPlayer( m_hOwner ); + if ( !pPlayer ) + return; + + // Tell all this player's sentryguns + for ( int i = 0; i < pPlayer->m_aObjects.Size(); i++ ) + { + CBaseObject *pObj = pPlayer->m_aObjects[i]; + if ( !pObj ) + continue; + + if ( pObj->IsSentrygun() ) + { + CObjectSentrygun *pSentry = static_cast<CObjectSentrygun *>(pObj); + pSentry->DesignateTarget( pEntity ); + } + + if ( pObj->GetType() == OBJ_AERIAL_SENTRY_STATION ) + { + CObjectAerialSentryStation *pSentryStation = static_cast<CObjectAerialSentryStation *>(pObj); + pSentryStation->DesignateTarget( pEntity ); + } + } +}
\ No newline at end of file |