source-engine/game/server/env_effectsscript.cpp

543 lines
12 KiB
C++
Raw Normal View History

2020-04-22 16:56:21 +00:00
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
// $NoKeywords: $
//=============================================================================//
#include "cbase.h"
#include "baseanimating.h"
#include "Sprite.h"
#include "SpriteTrail.h"
#include <ctype.h>
#include "animation.h"
#include "eventlist.h"
#include "npcevent.h"
// memdbgon must be the last include file in a .cpp file!!!
#include "tier0/memdbgon.h"
enum EffectType
{
EFFECT_TYPE_TRAIL = 1,
EFFECT_TYPE_SPRITE
};
bool g_bUnget = false;
unsigned char *buffer;
char name[ 256 ];
const char *currenttoken;
int tokencount;
char token[ 1204 ];
class CEffectScriptElement
{
public:
CEffectScriptElement();
char m_szEffectName[128];
CHandle<CSpriteTrail> m_pTrail;
CHandle<CSprite> m_pSprite;
int m_iType;
int m_iRenderType;
int m_iR;
int m_iG;
int m_iB;
int m_iA;
char m_szAttachment[128];
char m_szMaterial[128];
float m_flScale;
float m_flFadeTime;
float m_flTextureRes;
bool m_bStopFollowOnKill;
bool IsActive( void ) { return m_bActive; }
void Activate( void ) { m_bActive = true; }
void Deactivate( void ) { m_bActive = false; }
private:
bool m_bActive;
};
CEffectScriptElement::CEffectScriptElement()
{
m_pTrail = NULL;
m_pSprite = NULL;
m_iType = 0;
Deactivate();
m_iRenderType = kRenderTransAdd;
m_iR = 255;
m_iG = 0;
m_iB = 0;
m_iA = 255;
m_flScale = 1.0f;
m_flFadeTime = 1.0f;
m_flTextureRes = -1.0f;
m_bStopFollowOnKill = false;
}
//-----------------------------------------------------------------------------
// An entity which emits other entities at points
//-----------------------------------------------------------------------------
class CEnvEffectsScript : public CBaseAnimating
{
public:
DECLARE_CLASS( CEnvEffectsScript, CBaseAnimating );
DECLARE_DATADESC();
virtual void Precache();
virtual void Spawn();
virtual int UpdateTransmitState();
void InputSetSequence( inputdata_t &inputdata );
void ParseScriptFile( void );
void LoadFromBuffer( const char *scriptfile, const char *buffer );
virtual void Think( void );
void ParseNewEffect( void );
const char *GetScriptFile( void )
{
return STRING( m_iszScriptName );
}
void HandleAnimEvent ( animevent_t *pEvent );
void TrailEffectEvent( CEffectScriptElement *pEffect );
void SpriteEffectEvent( CEffectScriptElement *pEffect );
CEffectScriptElement *GetScriptElementByName( const char *pName );
private:
string_t m_iszScriptName;
CUtlVector< CEffectScriptElement > m_ScriptElements;
//-----------------------------------------------------------------------------
// Purpose:
// Output : Returns true on success, false on failure.
//-----------------------------------------------------------------------------
bool IsRootCommand( void )
{
if ( !Q_stricmp( token, "effect" ) )
return true;
return false;
}
};
inline bool ParseToken( void )
{
if ( g_bUnget )
{
g_bUnget = false;
return true;
}
currenttoken = engine->ParseFile( currenttoken, token, sizeof( token ) );
tokencount++;
return currenttoken != NULL ? true : false;
}
inline void Unget()
{
g_bUnget = true;
}
inline bool TokenWaiting( void )
{
const char *p = currenttoken;
while ( *p && *p!='\n')
{
// Special handler for // comment blocks
if ( *p == '/' && *(p+1) == '/' )
return false;
if ( !V_isspace( *p ) || V_isalnum( *p ) )
return true;
p++;
}
return false;
}
//-----------------------------------------------------------------------------
// Save/load
//-----------------------------------------------------------------------------
BEGIN_DATADESC( CEnvEffectsScript )
// Inputs
DEFINE_INPUTFUNC( FIELD_STRING, "SetSequence", InputSetSequence ),
DEFINE_KEYFIELD( m_iszScriptName, FIELD_STRING, "scriptfile" ),
// DEFINE_FIELD( m_ScriptElements, CUtlVector < CEffectScriptElement > ),
DEFINE_FUNCTION( Think ),
END_DATADESC()
LINK_ENTITY_TO_CLASS( env_effectscript, CEnvEffectsScript );
//-----------------------------------------------------------------------------
// Should we transmit it to the client?
//-----------------------------------------------------------------------------
int CEnvEffectsScript::UpdateTransmitState()
{
return SetTransmitState( FL_EDICT_ALWAYS );
}
//-----------------------------------------------------------------------------
// Precache
//-----------------------------------------------------------------------------
void CEnvEffectsScript::Precache()
{
BaseClass::Precache();
PrecacheModel( STRING( GetModelName() ) );
if ( m_iszScriptName != NULL_STRING )
ParseScriptFile();
else
Warning( "CEnvEffectsScript with no script!\n" );
}
//-----------------------------------------------------------------------------
// Spawn
//-----------------------------------------------------------------------------
void CEnvEffectsScript::Spawn()
{
Precache();
BaseClass::Spawn();
// We need a model for its animation sequences even though we don't render it
SetModel( STRING( GetModelName() ) );
AddEffects( EF_NODRAW );
SetThink( &CEnvEffectsScript::Think );
SetNextThink( gpGlobals->curtime + 0.1f );
}
void CEnvEffectsScript::Think( void )
{
StudioFrameAdvance();
DispatchAnimEvents( this );
SetNextThink( gpGlobals->curtime + 0.1f );
}
void CEnvEffectsScript::TrailEffectEvent( CEffectScriptElement *pEffect )
{
if ( pEffect->IsActive() == false )
{
//Only one type of this effect active at a time.
if ( pEffect->m_pTrail == NULL )
{
pEffect->m_pTrail = CSpriteTrail::SpriteTrailCreate( pEffect->m_szMaterial, GetAbsOrigin(), true );
pEffect->m_pTrail->FollowEntity( this );
pEffect->m_pTrail->SetTransparency( pEffect->m_iRenderType, pEffect->m_iR, pEffect->m_iG, pEffect->m_iB, pEffect->m_iA, kRenderFxNone );
pEffect->m_pTrail->SetStartWidth( pEffect->m_flScale );
if ( pEffect->m_flTextureRes < 0.0f )
{
pEffect->m_pTrail->SetTextureResolution( 1.0f / ( 16.0f * pEffect->m_flScale ) );
}
else
{
pEffect->m_pTrail->SetTextureResolution( pEffect->m_flTextureRes );
}
pEffect->m_pTrail->SetLifeTime( pEffect->m_flFadeTime );
pEffect->m_pTrail->TurnOn();
pEffect->m_pTrail->SetAttachment( this, LookupAttachment( pEffect->m_szAttachment ) );
pEffect->Activate();
}
}
}
void CEnvEffectsScript::SpriteEffectEvent( CEffectScriptElement *pEffect )
{
if ( pEffect->IsActive() == false )
{
//Only one type of this effect active at a time.
if ( pEffect->m_pSprite == NULL )
{
pEffect->m_pSprite = CSprite::SpriteCreate( pEffect->m_szMaterial, GetAbsOrigin(), true );
pEffect->m_pSprite->FollowEntity( this );
pEffect->m_pSprite->SetTransparency( pEffect->m_iRenderType, pEffect->m_iR, pEffect->m_iG, pEffect->m_iB, pEffect->m_iA, kRenderFxNone );
pEffect->m_pSprite->SetScale( pEffect->m_flScale );
pEffect->m_pSprite->TurnOn();
pEffect->m_pSprite->SetAttachment( this, LookupAttachment( pEffect->m_szAttachment ) );
pEffect->Activate();
}
}
}
void CEnvEffectsScript::HandleAnimEvent ( animevent_t *pEvent )
{
if ( pEvent->event == AE_START_SCRIPTED_EFFECT )
{
CEffectScriptElement *pCurrent = GetScriptElementByName( pEvent->options );
if ( pCurrent )
{
if ( pCurrent->m_iType == EFFECT_TYPE_TRAIL )
TrailEffectEvent( pCurrent );
else if ( pCurrent->m_iType == EFFECT_TYPE_SPRITE )
SpriteEffectEvent( pCurrent );
}
return;
}
if ( pEvent->event == AE_STOP_SCRIPTED_EFFECT )
{
CEffectScriptElement *pCurrent = GetScriptElementByName( pEvent->options );
if ( pCurrent && pCurrent->IsActive() )
{
pCurrent->Deactivate();
if ( pCurrent->m_iType == EFFECT_TYPE_TRAIL )
{
if ( pCurrent->m_bStopFollowOnKill == true )
{
Vector vOrigin;
GetAttachment( pCurrent->m_pTrail->m_nAttachment, vOrigin );
pCurrent->m_pTrail->StopFollowingEntity();
pCurrent->m_pTrail->m_hAttachedToEntity = NULL;
pCurrent->m_pTrail->m_nAttachment = 0;
pCurrent->m_pTrail->SetAbsOrigin( vOrigin);
}
pCurrent->m_pTrail->FadeAndDie( pCurrent->m_flFadeTime );
pCurrent->m_pTrail = NULL;
}
else if ( pCurrent->m_iType == EFFECT_TYPE_SPRITE )
{
if ( pCurrent->m_bStopFollowOnKill == true )
{
Vector vOrigin;
GetAttachment( pCurrent->m_pSprite->m_nAttachment, vOrigin );
pCurrent->m_pSprite->StopFollowingEntity();
pCurrent->m_pSprite->m_hAttachedToEntity = NULL;
pCurrent->m_pSprite->m_nAttachment = 0;
pCurrent->m_pSprite->SetAbsOrigin( vOrigin);
}
pCurrent->m_pSprite->FadeAndDie( pCurrent->m_flFadeTime );
pCurrent->m_pSprite = NULL;
}
}
return;
}
BaseClass::HandleAnimEvent( pEvent );
}
//-----------------------------------------------------------------------------
// Purpose: Input that sets the sequence of the entity
//-----------------------------------------------------------------------------
void CEnvEffectsScript::InputSetSequence( inputdata_t &inputdata )
{
if ( inputdata.value.StringID() != NULL_STRING )
{
int nSequence = LookupSequence( STRING( inputdata.value.StringID() ) );
if ( nSequence != ACT_INVALID )
{
SetSequence( nSequence );
ResetSequenceInfo();
SetCycle( 0.0f );
m_flPlaybackRate = 1.0f;
}
}
}
void CEnvEffectsScript::ParseScriptFile( void )
{
int length = 0;
m_ScriptElements.RemoveAll();
const char *pScriptName = GetScriptFile();
//Reset everything.
g_bUnget = false;
currenttoken = NULL;
tokencount = 0;
memset( token, 0, 1204 );
memset( name, 0, 256 );
unsigned char *buffer = (unsigned char *)UTIL_LoadFileForMe( pScriptName, &length );
if ( length <= 0 || !buffer )
{
DevMsg( 1, "CEnvEffectsScript: failed to load %s\n", pScriptName );
return;
}
currenttoken = (const char *)buffer;
LoadFromBuffer( pScriptName, (const char *)buffer );
UTIL_FreeFile( buffer );
}
void CEnvEffectsScript::LoadFromBuffer( const char *scriptfile, const char *buffer )
{
while ( 1 )
{
ParseToken();
if ( !token[0] )
{
break;
}
if ( !Q_stricmp( token, "effect" ) )
{
ParseNewEffect();
}
else
{
Warning( "CEnvEffectsScript: Unknown entry type '%s'\n", token );
break;
}
}
}
void CEnvEffectsScript::ParseNewEffect( void )
{
//Add a new effect to the list.
CEffectScriptElement NewElement;
// Effect Group Name
ParseToken();
Q_strncpy( NewElement.m_szEffectName, token, sizeof( NewElement.m_szEffectName ) );
while ( 1 )
{
ParseToken();
// Oops, part of next definition
if( IsRootCommand() )
{
Unget();
break;
}
if ( !Q_stricmp( token, "{" ) )
{
while ( 1 )
{
ParseToken();
if ( !Q_stricmp( token, "}" ) )
break;
if ( !Q_stricmp( token, "type" ) )
{
ParseToken();
if ( !Q_stricmp( token, "trail" ) )
NewElement.m_iType = EFFECT_TYPE_TRAIL;
else if ( !Q_stricmp( token, "sprite" ) )
NewElement.m_iType = EFFECT_TYPE_SPRITE;
continue;
}
if ( !Q_stricmp( token, "material" ) )
{
ParseToken();
Q_strncpy( NewElement.m_szMaterial, token, sizeof( NewElement.m_szMaterial ) );
PrecacheModel( NewElement.m_szMaterial );
continue;
}
if ( !Q_stricmp( token, "attachment" ) )
{
ParseToken();
Q_strncpy( NewElement.m_szAttachment, token, sizeof( NewElement.m_szAttachment ) );
continue;
}
if ( !Q_stricmp( token, "color" ) )
{
ParseToken();
sscanf( token, "%i %i %i %i", &NewElement.m_iR, &NewElement.m_iG, &NewElement.m_iB, &NewElement.m_iA );
continue;
}
if ( !Q_stricmp( token, "scale" ) )
{
ParseToken();
NewElement.m_flScale = atof( token );
continue;
}
if ( !Q_stricmp( token, "texturescale" ) )
{
ParseToken();
float flTextureScale = atof( token );
NewElement.m_flTextureRes = (flTextureScale > 0.0f) ? 1.0f / flTextureScale : 0.0f;
continue;
}
if ( !Q_stricmp( token, "fadetime" ) )
{
ParseToken();
NewElement.m_flFadeTime = atof( token );
continue;
}
if ( !Q_stricmp( token, "stopfollowonkill" ) )
{
ParseToken();
NewElement.m_bStopFollowOnKill = !!atoi( token );
continue;
}
}
break;
}
}
m_ScriptElements.AddToTail( NewElement );
}
CEffectScriptElement *CEnvEffectsScript::GetScriptElementByName( const char *pName )
{
for ( int i = 0; i < m_ScriptElements.Count(); i++ )
{
CEffectScriptElement *pCurrent = &m_ScriptElements.Element( i );
if ( pCurrent && !Q_stricmp( pCurrent->m_szEffectName, pName ) )
{
return pCurrent;
}
}
return NULL;
}