aboutsummaryrefslogtreecommitdiff
path: root/mp/src/game/server/EnvBeam.cpp
diff options
context:
space:
mode:
authorJoe Ludwig <[email protected]>2013-06-26 15:22:04 -0700
committerJoe Ludwig <[email protected]>2013-06-26 15:22:04 -0700
commit39ed87570bdb2f86969d4be821c94b722dc71179 (patch)
treeabc53757f75f40c80278e87650ea92808274aa59 /mp/src/game/server/EnvBeam.cpp
downloadsource-sdk-2013-39ed87570bdb2f86969d4be821c94b722dc71179.tar.xz
source-sdk-2013-39ed87570bdb2f86969d4be821c94b722dc71179.zip
First version of the SOurce SDK 2013
Diffstat (limited to 'mp/src/game/server/EnvBeam.cpp')
-rw-r--r--mp/src/game/server/EnvBeam.cpp762
1 files changed, 762 insertions, 0 deletions
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<CBaseFilter *>(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 );
+ }
+}