//========= Copyright Valve Corporation, All rights reserved. ============// // // Purpose: // // $NoKeywords: $ //=============================================================================// #include "cbase.h" #include "c_ai_basenpc.h" #include "beam_shared.h" #include "prop_portal_shared.h" #define FLOOR_TURRET_PORTAL_EYE_ATTACHMENT 1 #define FLOOR_TURRET_PORTAL_LASER_ATTACHMENT 2 #define FLOOR_TURRET_PORTAL_LASER_RANGE 8192 #define FLOOR_TURRET_PORTAL_END_POINT_PULSE_SCALE 4.0f class C_NPC_Portal_FloorTurret : public C_AI_BaseNPC { public: DECLARE_CLASS( C_NPC_Portal_FloorTurret, C_AI_BaseNPC ); DECLARE_CLIENTCLASS(); virtual ~C_NPC_Portal_FloorTurret( void ); virtual void Spawn( void ); virtual void ClientThink( void ); bool IsLaserOn( void ) { return m_pBeam != NULL; } void LaserOff( void ); void LaserOn( void ); float LaserEndPointSize( void ); private: CBeam *m_pBeam; bool m_bOutOfAmmo; bool m_bLaserOn; int m_sLaserHaloSprite; float m_fPulseOffset; float m_bBeamFlickerOff; float m_fBeamFlickerTime; }; IMPLEMENT_CLIENTCLASS_DT( C_NPC_Portal_FloorTurret, DT_NPC_Portal_FloorTurret, CNPC_Portal_FloorTurret ) RecvPropBool( RECVINFO( m_bOutOfAmmo ) ), RecvPropBool( RECVINFO( m_bLaserOn ) ), RecvPropInt( RECVINFO( m_sLaserHaloSprite ) ), END_RECV_TABLE() C_NPC_Portal_FloorTurret::~C_NPC_Portal_FloorTurret( void ) { LaserOff(); if( m_pBeam ) m_pBeam->Remove(); } void C_NPC_Portal_FloorTurret::Spawn( void ) { SetThink( &C_NPC_Portal_FloorTurret::ClientThink ); SetNextClientThink( CLIENT_THINK_ALWAYS ); m_pBeam = NULL; m_fPulseOffset = RandomFloat( 0.0f, 2.0f * M_PI ); m_bBeamFlickerOff = false; m_fBeamFlickerTime = 0.0f; BaseClass::Spawn(); } void C_NPC_Portal_FloorTurret::ClientThink( void ) { if ( m_bOutOfAmmo && m_fBeamFlickerTime < gpGlobals->curtime ) { m_fBeamFlickerTime = gpGlobals->curtime + RandomFloat( 0.05f, 0.3f ); m_bBeamFlickerOff = !m_bBeamFlickerOff; } if ( m_bLaserOn && !m_bBeamFlickerOff ) LaserOn(); else LaserOff(); } void C_NPC_Portal_FloorTurret::LaserOff( void ) { if( m_pBeam ) { m_pBeam->AddEffects( EF_NODRAW ); } } void C_NPC_Portal_FloorTurret::LaserOn( void ) { if ( !IsBoneAccessAllowed() ) { LaserOff(); return; } Vector vecMuzzle; QAngle angMuzzleDir; GetAttachment( FLOOR_TURRET_PORTAL_LASER_ATTACHMENT, vecMuzzle, angMuzzleDir ); Vector vecEye; QAngle angEyeDir; GetAttachment( FLOOR_TURRET_PORTAL_EYE_ATTACHMENT, vecEye, angEyeDir ); Vector vecMuzzleDir; AngleVectors( angEyeDir, &vecMuzzleDir ); if (!m_pBeam) { m_pBeam = CBeam::BeamCreate( "effects/redlaser1.vmt", 0.2 ); m_pBeam->SetColor( 255, 32, 32 ); m_pBeam->SetBrightness( 255 ); m_pBeam->SetNoise( 0 ); m_pBeam->SetWidth( IsX360() ? ( 1.5f ) : ( 0.75f ) ); // On low end TVs these lasers are very hard to see at a distance m_pBeam->SetEndWidth( 0 ); m_pBeam->SetScrollRate( 0 ); m_pBeam->SetFadeLength( 0 ); m_pBeam->SetHaloTexture( m_sLaserHaloSprite ); m_pBeam->SetHaloScale( 4.0f ); m_pBeam->SetCollisionGroup( COLLISION_GROUP_NONE ); m_pBeam->PointsInit( vecMuzzle + vecMuzzleDir, vecMuzzle ); m_pBeam->SetBeamFlag( FBEAM_REVERSED ); m_pBeam->SetStartEntity( this ); } else { m_pBeam->RemoveEffects( EF_NODRAW ); } // Trace to find an endpoint Vector vEndPoint; float fEndFraction; Ray_t rayPath; rayPath.Init( vecMuzzle, vecMuzzle + vecMuzzleDir * FLOOR_TURRET_PORTAL_LASER_RANGE ); CTraceFilterSkipClassname traceFilter( this, "prop_energy_ball", COLLISION_GROUP_NONE ); if ( UTIL_Portal_TraceRay_Beam( rayPath, MASK_SHOT, &traceFilter, &fEndFraction ) ) vEndPoint = vecMuzzle + vecMuzzleDir * FLOOR_TURRET_PORTAL_LASER_RANGE; // Trace went through portal and endpoint is unknown else vEndPoint = vecMuzzle + vecMuzzleDir * FLOOR_TURRET_PORTAL_LASER_RANGE * fEndFraction; // Trace hit a wall // The beam is backwards, sort of. The endpoint is the sniper. This is // so that the beam can be tapered to very thin where it emits from the turret. m_pBeam->PointsInit( vEndPoint, vecMuzzle ); m_pBeam->SetHaloScale( LaserEndPointSize() ); } float C_NPC_Portal_FloorTurret::LaserEndPointSize( void ) { return ( ( MAX( 0.0f, sinf( gpGlobals->curtime * M_PI + m_fPulseOffset ) ) ) * FLOOR_TURRET_PORTAL_END_POINT_PULSE_SCALE + 3.0f ) * ( IsX360() ? ( 3.0f ) : ( 1.5f ) ); }