From 39ed87570bdb2f86969d4be821c94b722dc71179 Mon Sep 17 00:00:00 2001 From: Joe Ludwig Date: Wed, 26 Jun 2013 15:22:04 -0700 Subject: First version of the SOurce SDK 2013 --- mp/src/game/server/EnvBeam.cpp | 762 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 762 insertions(+) create mode 100644 mp/src/game/server/EnvBeam.cpp (limited to 'mp/src/game/server/EnvBeam.cpp') diff --git a/mp/src/game/server/EnvBeam.cpp b/mp/src/game/server/EnvBeam.cpp new file mode 100644 index 00000000..ae103477 --- /dev/null +++ b/mp/src/game/server/EnvBeam.cpp @@ -0,0 +1,762 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: Implements visual effects entities: sprites, beams, bubbles, etc. +// +// $NoKeywords: $ +//=============================================================================// + +#include "cbase.h" +#include "beam_shared.h" +#include "ndebugoverlay.h" +#include "filters.h" + +// memdbgon must be the last include file in a .cpp file!!! +#include "tier0/memdbgon.h" + +// Keeps us from doing strcmps in the tracefilter. +string_t g_iszPhysicsPropClassname; + +enum Touch_t +{ + touch_none = 0, + touch_player_only, + touch_npc_only, + touch_player_or_npc, + touch_player_or_npc_or_physicsprop, +}; + +class CEnvBeam : public CBeam +{ +public: + DECLARE_CLASS( CEnvBeam, CBeam ); + + void Spawn( void ); + void Precache( void ); + void Activate( void ); + + void StrikeThink( void ); + void UpdateThink( void ); + void RandomArea( void ); + void RandomPoint( const Vector &vecSrc ); + void Zap( const Vector &vecSrc, const Vector &vecDest ); + + void Strike( void ); + + bool PassesTouchFilters(CBaseEntity *pOther); + + void InputTurnOn( inputdata_t &inputdata ); + void InputTurnOff( inputdata_t &inputdata ); + void InputToggle( inputdata_t &inputdata ); + void InputStrikeOnce( inputdata_t &inputdata ); + + void TurnOn( void ); + void TurnOff( void ); + void Toggle( void ); + + const char *GetDecalName( void ){ return STRING( m_iszDecal );} + + inline bool ServerSide( void ) + { + if ( m_life == 0 && !HasSpawnFlags(SF_BEAM_RING) ) + return true; + + return false; + } + + DECLARE_DATADESC(); + + void BeamUpdateVars( void ); + + int m_active; + int m_spriteTexture; + + string_t m_iszStartEntity; + string_t m_iszEndEntity; + float m_life; + float m_boltWidth; + float m_noiseAmplitude; + int m_speed; + float m_restrike; + string_t m_iszSpriteName; + int m_frameStart; + + float m_radius; + + Touch_t m_TouchType; + string_t m_iFilterName; + EHANDLE m_hFilter; + + string_t m_iszDecal; + + COutputEvent m_OnTouchedByEntity; +}; + +LINK_ENTITY_TO_CLASS( env_beam, CEnvBeam ); + +BEGIN_DATADESC( CEnvBeam ) + + DEFINE_FIELD( m_active, FIELD_INTEGER ), + DEFINE_FIELD( m_spriteTexture, FIELD_INTEGER ), + + DEFINE_KEYFIELD( m_iszStartEntity, FIELD_STRING, "LightningStart" ), + DEFINE_KEYFIELD( m_iszEndEntity, FIELD_STRING, "LightningEnd" ), + DEFINE_KEYFIELD( m_life, FIELD_FLOAT, "life" ), + DEFINE_KEYFIELD( m_boltWidth, FIELD_FLOAT, "BoltWidth" ), + DEFINE_KEYFIELD( m_noiseAmplitude, FIELD_FLOAT, "NoiseAmplitude" ), + DEFINE_KEYFIELD( m_speed, FIELD_INTEGER, "TextureScroll" ), + DEFINE_KEYFIELD( m_restrike, FIELD_FLOAT, "StrikeTime" ), + DEFINE_KEYFIELD( m_iszSpriteName, FIELD_STRING, "texture" ), + DEFINE_KEYFIELD( m_frameStart, FIELD_INTEGER, "framestart" ), + DEFINE_KEYFIELD( m_radius, FIELD_FLOAT, "Radius" ), + DEFINE_KEYFIELD( m_TouchType, FIELD_INTEGER, "TouchType" ), + DEFINE_KEYFIELD( m_iFilterName, FIELD_STRING, "filtername" ), + DEFINE_KEYFIELD( m_iszDecal, FIELD_STRING, "decalname" ), + + DEFINE_FIELD( m_hFilter, FIELD_EHANDLE ), + + // Function Pointers + DEFINE_FUNCTION( StrikeThink ), + DEFINE_FUNCTION( UpdateThink ), + + // Input functions + DEFINE_INPUTFUNC( FIELD_VOID, "TurnOn", InputTurnOn ), + DEFINE_INPUTFUNC( FIELD_VOID, "TurnOff", InputTurnOff ), + DEFINE_INPUTFUNC( FIELD_VOID, "Toggle", InputToggle ), + DEFINE_INPUTFUNC( FIELD_VOID, "StrikeOnce", InputStrikeOnce ), + + DEFINE_OUTPUT( m_OnTouchedByEntity, "OnTouchedByEntity" ), + +END_DATADESC() + + + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CEnvBeam::Spawn( void ) +{ + if ( !m_iszSpriteName ) + { + SetThink( &CEnvBeam::SUB_Remove ); + return; + } + + BaseClass::Spawn(); + + m_noiseAmplitude = MIN(MAX_BEAM_NOISEAMPLITUDE, m_noiseAmplitude); + + // Check for tapering + if ( HasSpawnFlags( SF_BEAM_TAPEROUT ) ) + { + SetWidth( m_boltWidth ); + SetEndWidth( 0 ); + } + else + { + SetWidth( m_boltWidth ); + SetEndWidth( GetWidth() ); // Note: EndWidth is not scaled + } + + if ( ServerSide() ) + { + SetThink( &CEnvBeam::UpdateThink ); + SetNextThink( gpGlobals->curtime ); + SetFireTime( gpGlobals->curtime ); + + if ( GetEntityName() != NULL_STRING ) + { + if ( !(m_spawnflags & SF_BEAM_STARTON) ) + { + AddEffects( EF_NODRAW ); + m_active = 0; + SetNextThink( TICK_NEVER_THINK ); + } + else + { + m_active = 1; + } + } + } + else + { + m_active = 0; + if ( !GetEntityName() || FBitSet(m_spawnflags, SF_BEAM_STARTON) ) + { + SetThink( &CEnvBeam::StrikeThink ); + SetNextThink( gpGlobals->curtime + 1.0f ); + } + } + +} + + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CEnvBeam::Precache( void ) +{ + if ( !Q_stristr( STRING(m_iszSpriteName), ".vmt" ) ) + { + // HACK/YWB: This was almost always the laserbeam.spr, so alloc'ing the name a second time with the proper extension isn't going to + // kill us on memrory. + //Warning( "Level Design Error: %s (%i:%s) Sprite name (%s) missing .vmt extension!\n", + // STRING( m_iClassname ), entindex(), GetEntityName(), STRING(m_iszSpriteName) ); + + char fixedname[ 512 ]; + Q_strncpy( fixedname, STRING( m_iszSpriteName ), sizeof( fixedname ) ); + + Q_SetExtension( fixedname, ".vmt", sizeof( fixedname ) ); + + m_iszSpriteName = AllocPooledString( fixedname ); + } + + g_iszPhysicsPropClassname = AllocPooledString( "prop_physics" ); + + m_spriteTexture = PrecacheModel( STRING(m_iszSpriteName) ); + BaseClass::Precache(); +} + + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CEnvBeam::Activate( void ) +{ + // Get a handle to my filter entity if there is one + if (m_iFilterName != NULL_STRING) + { + m_hFilter = dynamic_cast(gEntList.FindEntityByName( NULL, m_iFilterName )); + } + + BaseClass::Activate(); + + if ( ServerSide() ) + BeamUpdateVars(); +} + + +//----------------------------------------------------------------------------- +// Purpose: Input handler to turn the lightning on either continually or for +// interval refiring. +//----------------------------------------------------------------------------- +void CEnvBeam::InputTurnOn( inputdata_t &inputdata ) +{ + if ( !m_active ) + { + TurnOn(); + } +} + + +//----------------------------------------------------------------------------- +// Purpose: Input handler to turn the lightning off. +//----------------------------------------------------------------------------- +void CEnvBeam::InputTurnOff( inputdata_t &inputdata ) +{ + if ( m_active ) + { + TurnOff(); + } +} + + +//----------------------------------------------------------------------------- +// Purpose: Input handler to toggle the lightning on/off. +//----------------------------------------------------------------------------- +void CEnvBeam::InputToggle( inputdata_t &inputdata ) +{ + if ( m_active ) + { + TurnOff(); + } + else + { + TurnOn(); + } +} + + +//----------------------------------------------------------------------------- +// Purpose: Input handler for making the beam strike once. This will not affect +// any interval refiring that might be going on. If the lifetime is set +// to zero (infinite) it will turn on and stay on. +//----------------------------------------------------------------------------- +void CEnvBeam::InputStrikeOnce( inputdata_t &inputdata ) +{ + Strike(); +} + + +//----------------------------------------------------------------------------- +// Purpose: Turns the lightning on. If it is set for interval refiring, it will +// begin doing so. If it is set to be continually on, it will do so. +//----------------------------------------------------------------------------- +void CEnvBeam::TurnOn( void ) +{ + m_active = 1; + + if ( ServerSide() ) + { + RemoveEffects( EF_NODRAW ); + DoSparks( GetAbsStartPos(), GetAbsEndPos() ); + + SetThink( &CEnvBeam::UpdateThink ); + SetNextThink( gpGlobals->curtime ); + SetFireTime( gpGlobals->curtime ); + } + else + { + SetThink( &CEnvBeam::StrikeThink ); + SetNextThink( gpGlobals->curtime ); + } +} + + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CEnvBeam::TurnOff( void ) +{ + m_active = 0; + + if ( ServerSide() ) + { + AddEffects( EF_NODRAW ); + } + + SetNextThink( TICK_NEVER_THINK ); + SetThink( NULL ); +} + + +//----------------------------------------------------------------------------- +// Purpose: Think function for striking at intervals. +//----------------------------------------------------------------------------- +void CEnvBeam::StrikeThink( void ) +{ + if ( m_life != 0 ) + { + if ( m_spawnflags & SF_BEAM_RANDOM ) + SetNextThink( gpGlobals->curtime + m_life + random->RandomFloat( 0, m_restrike ) ); + else + SetNextThink( gpGlobals->curtime + m_life + m_restrike ); + } + m_active = 1; + + if (!m_iszEndEntity) + { + if (!m_iszStartEntity) + { + RandomArea( ); + } + else + { + CBaseEntity *pStart = RandomTargetname( STRING(m_iszStartEntity) ); + if (pStart != NULL) + { + RandomPoint( pStart->GetAbsOrigin() ); + } + else + { + Msg( "env_beam: unknown entity \"%s\"\n", STRING(m_iszStartEntity) ); + } + } + return; + } + + Strike(); +} + + +//----------------------------------------------------------------------------- +// Purpose: Strikes once for its configured lifetime. +//----------------------------------------------------------------------------- +void CEnvBeam::Strike( void ) +{ + CBroadcastRecipientFilter filter; + + CBaseEntity *pStart = RandomTargetname( STRING(m_iszStartEntity) ); + CBaseEntity *pEnd = RandomTargetname( STRING(m_iszEndEntity) ); + + if ( pStart == NULL || pEnd == NULL ) + return; + + m_speed = clamp( (int) m_speed, 0, (int) MAX_BEAM_SCROLLSPEED ); + + int pointStart = IsStaticPointEntity( pStart ); + int pointEnd = IsStaticPointEntity( pEnd ); + + if ( pointStart || pointEnd ) + { + if ( m_spawnflags & SF_BEAM_RING ) + { + // don't work + return; + } + + te->BeamEntPoint( filter, 0.0, + pointStart ? 0 : pStart->entindex(), + pointStart ? &pStart->GetAbsOrigin() : NULL, + pointEnd ? 0 : pEnd->entindex(), + pointEnd ? &pEnd->GetAbsOrigin() : NULL, + m_spriteTexture, + 0, // No halo + m_frameStart, + (int)m_flFrameRate, + m_life, + m_boltWidth, + m_boltWidth, // End width + 0, // No fade + m_noiseAmplitude, + m_clrRender->r, m_clrRender->g, m_clrRender->b, m_clrRender->a, + m_speed ); + } + else + { + if ( m_spawnflags & SF_BEAM_RING) + { + te->BeamRing( filter, 0.0, + pStart->entindex(), + pEnd->entindex(), + m_spriteTexture, + 0, // No halo + m_frameStart, + (int)m_flFrameRate, + m_life, + m_boltWidth, + 0, // No spread + m_noiseAmplitude, + m_clrRender->r, + m_clrRender->g, + m_clrRender->b, + m_clrRender->a, + m_speed ); + } + else + { + te->BeamEnts( filter, 0.0, + pStart->entindex(), + pEnd->entindex(), + m_spriteTexture, + 0, // No halo + m_frameStart, + (int)m_flFrameRate, + m_life, + m_boltWidth, + m_boltWidth, // End width + 0, // No fade + m_noiseAmplitude, + m_clrRender->r, + m_clrRender->g, + m_clrRender->b, + m_clrRender->a, + m_speed ); + + } + } + + DoSparks( pStart->GetAbsOrigin(), pEnd->GetAbsOrigin() ); + if ( m_flDamage > 0 ) + { + trace_t tr; + UTIL_TraceLine( pStart->GetAbsOrigin(), pEnd->GetAbsOrigin(), MASK_SOLID, NULL, COLLISION_GROUP_NONE, &tr ); + BeamDamageInstant( &tr, m_flDamage ); + } + +} + + +class CTraceFilterPlayersNPCs : public ITraceFilter +{ +public: + bool ShouldHitEntity( IHandleEntity *pServerEntity, int contentsMask ) + { + CBaseEntity *pEntity = EntityFromEntityHandle( pServerEntity ); + if ( pEntity ) + { + if ( pEntity->IsPlayer() || pEntity->MyNPCPointer() ) + return true; + } + + return false; + } + virtual TraceType_t GetTraceType() const + { + return TRACE_ENTITIES_ONLY; + } +}; + +class CTraceFilterPlayersNPCsPhysicsProps : public ITraceFilter +{ +public: + bool ShouldHitEntity( IHandleEntity *pServerEntity, int contentsMask ) + { + CBaseEntity *pEntity = EntityFromEntityHandle( pServerEntity ); + if ( pEntity ) + { + if ( pEntity->IsPlayer() || pEntity->MyNPCPointer() || pEntity->m_iClassname == g_iszPhysicsPropClassname ) + return true; + } + + return false; + } + virtual TraceType_t GetTraceType() const + { + return TRACE_ENTITIES_ONLY; + } +}; + +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +bool CEnvBeam::PassesTouchFilters(CBaseEntity *pOther) +{ + bool fPassedSoFar = false; + + // Touched some player or NPC! + if( m_TouchType != touch_npc_only ) + { + if( pOther->IsPlayer() ) + { + fPassedSoFar = true; + } + } + + if( m_TouchType != touch_player_only ) + { + if( pOther->IsNPC() ) + { + fPassedSoFar = true; + } + } + + if( m_TouchType == touch_player_or_npc_or_physicsprop ) + { + if( pOther->m_iClassname == g_iszPhysicsPropClassname ) + { + fPassedSoFar = true; + } + } + + if( fPassedSoFar ) + { + CBaseFilter* pFilter = (CBaseFilter*)(m_hFilter.Get()); + return (!pFilter) ? true : pFilter->PassesFilter( this, pOther ); + } + + return false; +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CEnvBeam::UpdateThink( void ) +{ + // Apply damage every 1/10th of a second. + if ( ( m_flDamage > 0 ) && ( gpGlobals->curtime >= m_flFireTime + 0.1 ) ) + { + trace_t tr; + UTIL_TraceLine( GetAbsStartPos(), GetAbsEndPos(), MASK_SOLID, NULL, COLLISION_GROUP_NONE, &tr ); + BeamDamage( &tr ); + // BeamDamage calls RelinkBeam, so no need to call it again. + } + else + { + RelinkBeam(); + } + + if( m_TouchType != touch_none ) + { + trace_t tr; + Ray_t ray; + ray.Init( GetAbsStartPos(), GetAbsEndPos() ); + + if( m_TouchType == touch_player_or_npc_or_physicsprop ) + { + CTraceFilterPlayersNPCsPhysicsProps traceFilter; + enginetrace->TraceRay( ray, MASK_SHOT, &traceFilter, &tr ); + } + else + { + CTraceFilterPlayersNPCs traceFilter; + enginetrace->TraceRay( ray, MASK_SHOT, &traceFilter, &tr ); + } + + if( tr.fraction != 1.0 && PassesTouchFilters( tr.m_pEnt ) ) + { + m_OnTouchedByEntity.FireOutput( tr.m_pEnt, this, 0 ); + return; + } + } + + SetNextThink( gpGlobals->curtime ); +} + + +//----------------------------------------------------------------------------- +// Purpose: +// Input : &vecSrc - +// &vecDest - +//----------------------------------------------------------------------------- +void CEnvBeam::Zap( const Vector &vecSrc, const Vector &vecDest ) +{ + CBroadcastRecipientFilter filter; + + te->BeamPoints( filter, 0.0, + &vecSrc, + &vecDest, + m_spriteTexture, + 0, // No halo + m_frameStart, + (int)m_flFrameRate, + m_life, + m_boltWidth, + m_boltWidth, // End width + 0, // No fade + m_noiseAmplitude, + m_clrRender->r, + m_clrRender->g, + m_clrRender->b, + m_clrRender->a, + m_speed ); + + DoSparks( vecSrc, vecDest ); +} + + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CEnvBeam::RandomArea( void ) +{ + int iLoops = 0; + + for (iLoops = 0; iLoops < 10; iLoops++) + { + Vector vecSrc = GetAbsOrigin(); + + Vector vecDir1 = Vector( random->RandomFloat( -1.0, 1.0 ), random->RandomFloat( -1.0, 1.0 ),random->RandomFloat( -1.0, 1.0 ) ); + VectorNormalize( vecDir1 ); + trace_t tr1; + UTIL_TraceLine( vecSrc, vecSrc + vecDir1 * m_radius, MASK_SOLID_BRUSHONLY, this, COLLISION_GROUP_NONE, &tr1 ); + + if (tr1.fraction == 1.0) + continue; + + Vector vecDir2; + do { + vecDir2 = Vector( random->RandomFloat( -1.0, 1.0 ), random->RandomFloat( -1.0, 1.0 ),random->RandomFloat( -1.0, 1.0 ) ); + } while (DotProduct(vecDir1, vecDir2 ) > 0); + VectorNormalize( vecDir2 ); + trace_t tr2; + UTIL_TraceLine( vecSrc, vecSrc + vecDir2 * m_radius, MASK_SOLID_BRUSHONLY, this, COLLISION_GROUP_NONE, &tr2 ); + + if (tr2.fraction == 1.0) + continue; + + if ((tr1.endpos - tr2.endpos).Length() < m_radius * 0.1) + continue; + + UTIL_TraceLine( tr1.endpos, tr2.endpos, MASK_SOLID_BRUSHONLY, this, COLLISION_GROUP_NONE, &tr2 ); + + if (tr2.fraction != 1.0) + continue; + + Zap( tr1.endpos, tr2.endpos ); + + break; + } +} + + +//----------------------------------------------------------------------------- +// Purpose: +// Input : vecSrc - +//----------------------------------------------------------------------------- +void CEnvBeam::RandomPoint( const Vector &vecSrc ) +{ + int iLoops = 0; + + for (iLoops = 0; iLoops < 10; iLoops++) + { + Vector vecDir1 = Vector( random->RandomFloat( -1.0, 1.0 ), random->RandomFloat( -1.0, 1.0 ),random->RandomFloat( -1.0, 1.0 ) ); + VectorNormalize( vecDir1 ); + trace_t tr1; + UTIL_TraceLine( vecSrc, vecSrc + vecDir1 * m_radius, MASK_SOLID_BRUSHONLY, this, COLLISION_GROUP_NONE, &tr1 ); + + if ((tr1.endpos - vecSrc).Length() < m_radius * 0.1) + continue; + + if (tr1.fraction == 1.0) + continue; + + Zap( vecSrc, tr1.endpos ); + break; + } +} + + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CEnvBeam::BeamUpdateVars( void ) +{ + CBaseEntity *pStart = gEntList.FindEntityByName( NULL, m_iszStartEntity ); + CBaseEntity *pEnd = gEntList.FindEntityByName( NULL, m_iszEndEntity ); + + if (( pStart == NULL ) || ( pEnd == NULL )) + { + return; + } + + m_nNumBeamEnts = 2; + + m_speed = clamp( (int) m_speed, 0, (int) MAX_BEAM_SCROLLSPEED ); + + // NOTE: If the end entity is the beam itself (and the start entity + // isn't *also* the beam itself, we've got problems. This is a problem + // because SetAbsStartPos actually sets the entity's origin. + if ( ( pEnd == this ) && ( pStart != this ) ) + { + DevMsg("env_beams cannot have the end entity be the beam itself\n" + "unless the start entity is also the beam itself!\n" ); + Assert(0); + } + + SetModelName( m_iszSpriteName ); + SetTexture( m_spriteTexture ); + + SetType( BEAM_ENTPOINT ); + + if ( IsStaticPointEntity( pStart ) ) + { + SetAbsStartPos( pStart->GetAbsOrigin() ); + } + else + { + SetStartEntity( pStart ); + } + + if ( IsStaticPointEntity( pEnd ) ) + { + SetAbsEndPos( pEnd->GetAbsOrigin() ); + } + else + { + SetEndEntity( pEnd ); + } + + RelinkBeam(); + + SetWidth( MIN(MAX_BEAM_WIDTH, m_boltWidth) ); + SetNoise( MIN(MAX_BEAM_NOISEAMPLITUDE, m_noiseAmplitude) ); + SetFrame( m_frameStart ); + SetScrollRate( m_speed ); + if ( m_spawnflags & SF_BEAM_SHADEIN ) + { + SetBeamFlags( FBEAM_SHADEIN ); + } + else if ( m_spawnflags & SF_BEAM_SHADEOUT ) + { + SetBeamFlags( FBEAM_SHADEOUT ); + } +} -- cgit v1.2.3