source-engine/game/server/smokestack.cpp

277 lines
7.5 KiB
C++
Raw Normal View History

2020-04-22 16:56:21 +00:00
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose: Implements the server side of a steam jet particle system entity.
//
// $NoKeywords: $
//=============================================================================//
#include "cbase.h"
#include "smokestack.h"
#include "particle_light.h"
#include "filesystem.h"
// memdbgon must be the last include file in a .cpp file!!!
#include "tier0/memdbgon.h"
//Networking
IMPLEMENT_SERVERCLASS_ST(CSmokeStack, DT_SmokeStack)
SendPropFloat(SENDINFO(m_SpreadSpeed), 0, SPROP_NOSCALE),
SendPropFloat(SENDINFO(m_Speed), 0, SPROP_NOSCALE),
SendPropFloat(SENDINFO(m_StartSize), 0, SPROP_NOSCALE),
SendPropFloat(SENDINFO(m_EndSize), 0, SPROP_NOSCALE),
SendPropFloat(SENDINFO(m_Rate), 0, SPROP_NOSCALE),
SendPropFloat(SENDINFO(m_JetLength), 0, SPROP_NOSCALE),
SendPropInt(SENDINFO(m_bEmit), 1, SPROP_UNSIGNED),
SendPropFloat(SENDINFO(m_flBaseSpread), 0, SPROP_NOSCALE),
SendPropFloat(SENDINFO( m_flRollSpeed ), 0, SPROP_NOSCALE ),
// Note: the base color is specified in the smokestack entity, but the directional
// and ambient light must come from env_particlelight entities.
SendPropVector( SENDINFO_NOCHECK(m_DirLight.m_vPos), 0, SPROP_NOSCALE ),
SendPropVector( SENDINFO_NOCHECK(m_DirLight.m_vColor), 0, SPROP_NOSCALE ),
SendPropFloat( SENDINFO_NOCHECK(m_DirLight.m_flIntensity), 0, SPROP_NOSCALE ),
SendPropVector( SENDINFO_NOCHECK(m_AmbientLight.m_vPos), 0, SPROP_NOSCALE ),
SendPropVector( SENDINFO_NOCHECK(m_AmbientLight.m_vColor), 0, SPROP_NOSCALE ),
SendPropFloat( SENDINFO_NOCHECK(m_AmbientLight.m_flIntensity), 0, SPROP_NOSCALE ),
SendPropVector(SENDINFO(m_vWind), 0, SPROP_NOSCALE),
SendPropFloat(SENDINFO(m_flTwist), 0, SPROP_NOSCALE),
SendPropIntWithMinusOneFlag( SENDINFO(m_iMaterialModel), 16 )
END_SEND_TABLE()
LINK_ENTITY_TO_CLASS( env_smokestack, CSmokeStack );
//Save/restore
BEGIN_SIMPLE_DATADESC( CSmokeStackLightInfo )
DEFINE_FIELD( m_vPos, FIELD_POSITION_VECTOR ),
DEFINE_FIELD( m_vColor, FIELD_VECTOR ),
DEFINE_FIELD( m_flIntensity, FIELD_FLOAT ),
END_DATADESC()
BEGIN_DATADESC( CSmokeStack )
//Keyvalue fields
DEFINE_KEYFIELD( m_StartSize, FIELD_FLOAT, "StartSize" ),
DEFINE_KEYFIELD( m_EndSize, FIELD_FLOAT, "EndSize" ),
DEFINE_KEYFIELD( m_InitialState, FIELD_BOOLEAN, "InitialState" ),
DEFINE_KEYFIELD( m_flBaseSpread, FIELD_FLOAT, "BaseSpread" ),
DEFINE_KEYFIELD( m_flTwist, FIELD_FLOAT, "Twist" ),
DEFINE_KEYFIELD( m_flRollSpeed, FIELD_FLOAT, "Roll" ),
DEFINE_FIELD( m_strMaterialModel, FIELD_STRING ),
DEFINE_FIELD( m_iMaterialModel,FIELD_INTEGER ),
DEFINE_EMBEDDED( m_AmbientLight ),
DEFINE_EMBEDDED( m_DirLight ),
DEFINE_KEYFIELD( m_WindAngle, FIELD_INTEGER, "WindAngle" ),
DEFINE_KEYFIELD( m_WindSpeed, FIELD_INTEGER, "WindSpeed" ),
//Regular fields
DEFINE_FIELD( m_vWind, FIELD_VECTOR ),
DEFINE_FIELD( m_bEmit, FIELD_INTEGER ),
// Inputs
DEFINE_INPUT( m_JetLength, FIELD_FLOAT, "JetLength" ),
DEFINE_INPUT( m_SpreadSpeed, FIELD_FLOAT, "SpreadSpeed" ),
DEFINE_INPUT( m_Speed, FIELD_FLOAT, "Speed" ),
DEFINE_INPUT( m_Rate, FIELD_FLOAT, "Rate" ),
DEFINE_INPUTFUNC( FIELD_VOID, "TurnOn", InputTurnOn ),
DEFINE_INPUTFUNC( FIELD_VOID, "TurnOff", InputTurnOff ),
DEFINE_INPUTFUNC( FIELD_VOID, "Toggle", InputToggle ),
END_DATADESC()
//-----------------------------------------------------------------------------
// Purpose: Called before spawning, after key values have been set.
//-----------------------------------------------------------------------------
CSmokeStack::CSmokeStack()
{
memset( &m_AmbientLight, 0, sizeof(m_AmbientLight) );
memset( &m_DirLight, 0, sizeof(m_DirLight) );
IMPLEMENT_NETWORKVAR_CHAIN( &m_AmbientLight );
IMPLEMENT_NETWORKVAR_CHAIN( &m_DirLight );
m_flTwist = 0;
SetRenderColor( 0, 0, 0, 255 );
m_vWind.GetForModify().Init();
m_WindAngle = m_WindSpeed = 0;
m_iMaterialModel = -1;
m_flRollSpeed = 0.0f;
}
CSmokeStack::~CSmokeStack()
{
}
void CSmokeStack::Spawn( void )
{
if ( m_InitialState )
{
m_bEmit = true;
}
}
void CSmokeStack::Activate()
{
DetectInSkybox();
bool bGotDirLight = false;
// Find local lights.
CBaseEntity *pTestEnt = NULL;
while ( 1 )
{
pTestEnt = gEntList.FindEntityByClassname( pTestEnt, PARTICLELIGHT_ENTNAME );
if ( !pTestEnt )
break;
CParticleLight *pLight = (CParticleLight*)pTestEnt;
if( !FStrEq( STRING(GetEntityName()), STRING(pLight->m_PSName) ) )
continue;
CSmokeStackLightInfo *pInfo = &m_AmbientLight;
if ( pLight->m_bDirectional )
{
bGotDirLight = true;
pInfo = &m_DirLight;
}
pInfo->m_flIntensity = pLight->m_flIntensity;
pInfo->m_vColor = pLight->m_vColor;
pInfo->m_vPos = pLight->GetAbsOrigin();
}
// Put our light colors in 0-1 space.
m_AmbientLight.m_vColor.GetForModify() /= 255.0f;
m_DirLight.m_vColor.GetForModify() /= 255.0f;
BaseClass::Activate();
// Legacy support..
if ( m_iMaterialModel == -1 )
m_iMaterialModel = PrecacheModel( "particle/SmokeStack.vmt" );
}
bool CSmokeStack::KeyValue( const char *szKeyName, const char *szValue )
{
if( stricmp( szKeyName, "Wind" ) == 0 )
{
sscanf( szValue, "%f %f %f", &m_vWind.GetForModify().x, &m_vWind.GetForModify().y, &m_vWind.GetForModify().z );
return true;
}
else if( stricmp( szKeyName, "WindAngle" ) == 0 )
{
m_WindAngle = atoi( szValue );
RecalcWindVector();
return true;
}
else if( stricmp( szKeyName, "WindSpeed" ) == 0 )
{
m_WindSpeed = atoi( szValue );
RecalcWindVector();
return true;
}
else if ( stricmp( szKeyName, "SmokeMaterial" ) == 0 )
{
// Make sure we have a vmt extension.
if ( Q_stristr( szValue, ".vmt" ) )
{
m_strMaterialModel = AllocPooledString( szValue );
}
else
{
char str[512];
Q_snprintf( str, sizeof( str ), "%s.vmt", szValue );
m_strMaterialModel = AllocPooledString( str );
}
const char *pName = STRING( m_strMaterialModel );
char szStrippedName[512];
m_iMaterialModel = PrecacheModel( pName );
Q_StripExtension( pName, szStrippedName, Q_strlen(pName)+1 );
int iLength = Q_strlen( szStrippedName );
szStrippedName[iLength-1] = '\0';
int iCount = 1;
char str[512];
Q_snprintf( str, sizeof( str ), "%s%d.vmt", szStrippedName, iCount );
while ( filesystem->FileExists( UTIL_VarArgs( "materials/%s", str ) ) )
{
PrecacheModel( str );
iCount++;
Q_snprintf( str, sizeof( str ), "%s%d.vmt", szStrippedName, iCount );
}
return true;
}
else
{
return BaseClass::KeyValue( szKeyName, szValue );
}
}
void CSmokeStack::Precache()
{
m_iMaterialModel = PrecacheModel( STRING( m_strMaterialModel ) );
BaseClass::Precache();
}
//-----------------------------------------------------------------------------
// Purpose: Input handler for toggling the steam jet on/off.
//-----------------------------------------------------------------------------
void CSmokeStack::InputToggle( inputdata_t &inputdata )
{
m_bEmit = !m_bEmit;
}
//-----------------------------------------------------------------------------
// Purpose: Input handler for turning on the steam jet.
//-----------------------------------------------------------------------------
void CSmokeStack::InputTurnOn( inputdata_t &inputdata )
{
m_bEmit = true;
}
//-----------------------------------------------------------------------------
// Purpose: Input handler for turning off the steam jet.
//-----------------------------------------------------------------------------
void CSmokeStack::InputTurnOff( inputdata_t &inputdata )
{
m_bEmit = false;
}
void CSmokeStack::RecalcWindVector()
{
m_vWind = Vector(
cos( DEG2RAD( (float)m_WindAngle ) ) * m_WindSpeed,
sin( DEG2RAD( (float)m_WindAngle ) ) * m_WindSpeed,
0 );
}