This commit is contained in:
FluorescentCIAAfricanAmerican
2020-04-22 12:56:21 -04:00
commit 3bf9df6b27
15370 changed files with 5489726 additions and 0 deletions
+251
View File
@@ -0,0 +1,251 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose: Definition for client-side advisor.
//
//=====================================================================================//
#include "cbase.h"
// this file contains the definitions for the message ID constants (eg ADVISOR_MSG_START_BEAM etc)
#include "npc_advisor_shared.h"
#if NPC_ADVISOR_HAS_BEHAVIOR
#include "particles_simple.h"
#include "citadel_effects_shared.h"
#include "particles_attractor.h"
#include "clienteffectprecachesystem.h"
#include "c_te_effect_dispatch.h"
#include "c_ai_basenpc.h"
#include "dlight.h"
#include "iefx.h"
//-----------------------------------------------------------------------------
// Purpose: unpack a networked entity index into a basehandle.
//-----------------------------------------------------------------------------
inline C_BaseEntity *IndexToEntity( int eindex )
{
return ClientEntityList().GetBaseEntityFromHandle(ClientEntityList().EntIndexToHandle(eindex));
}
#define ADVISOR_ELIGHT_CVARS 1 // enable/disable tuning advisor elight with console variables
#if ADVISOR_ELIGHT_CVARS
ConVar advisor_elight_e("advisor_elight_e","3");
ConVar advisor_elight_rfeet("advisor_elight_rfeet","52");
#endif
/*! Client-side reflection of the advisor class.
*/
class C_NPC_Advisor : public C_AI_BaseNPC
{
DECLARE_CLASS( C_NPC_Advisor, C_AI_BaseNPC );
DECLARE_CLIENTCLASS();
public:
// Server to client message received
virtual void ReceiveMessage( int classID, bf_read &msg );
virtual void ClientThink( void );
private:
/*
// broken into its own function so I can move it if necesasry
void Initialize();
*/
// start/stop beam particle effect from me to a pelting object
void StartBeamFX( C_BaseEntity *pOnEntity );
void StopBeamFX( C_BaseEntity *pOnEntity );
void StartElight();
void StopElight();
int m_ElightKey; // test using an elight to make the escape sequence more visible. 0 is invalid.
};
IMPLEMENT_CLIENTCLASS_DT( C_NPC_Advisor, DT_NPC_Advisor, CNPC_Advisor )
END_RECV_TABLE()
// Server to client message received
void C_NPC_Advisor::ReceiveMessage( int classID, bf_read &msg )
{
if ( classID != GetClientClass()->m_ClassID )
{
// message is for subclass
BaseClass::ReceiveMessage( classID, msg );
return;
}
int messageType = msg.ReadByte();
switch( messageType )
{
case ADVISOR_MSG_START_BEAM:
{
int eindex = msg.ReadLong();
StartBeamFX(IndexToEntity(eindex));
}
break;
case ADVISOR_MSG_STOP_BEAM:
{
int eindex = msg.ReadLong();
StopBeamFX(IndexToEntity(eindex));
}
break;
case ADVISOR_MSG_STOP_ALL_BEAMS:
{
ParticleProp()->StopEmission();
}
break;
case ADVISOR_MSG_START_ELIGHT:
{
StartElight();
}
break;
case ADVISOR_MSG_STOP_ELIGHT:
{
StopElight();
}
break;
default:
AssertMsg1( false, "Received unknown message %d", messageType);
}
}
/// only use of the clientthink on the advisor is to update the elight
void C_NPC_Advisor::ClientThink( void )
{
// if the elight has gone away, bail out
if (m_ElightKey == 0)
{
SetNextClientThink( CLIENT_THINK_NEVER );
return;
}
// get the elight
dlight_t * el = effects->GetElightByKey(m_ElightKey);
if (!el)
{
// the elight has been invalidated. bail out.
m_ElightKey = 0;
SetNextClientThink( CLIENT_THINK_NEVER );
return;
}
else
{
el->origin = WorldSpaceCenter();
#if ADVISOR_ELIGHT_CVARS
el->color.exponent = advisor_elight_e.GetFloat();
el->radius = advisor_elight_rfeet.GetFloat() * 12.0f;
#endif
}
}
//-----------------------------------------------------------------------------
// Create a telekinetic beam effect from my head to an object
// TODO: use a point attachment.
//-----------------------------------------------------------------------------
void C_NPC_Advisor::StartBeamFX( C_BaseEntity *pOnEntity )
{
Assert(pOnEntity);
if (!pOnEntity)
return;
CNewParticleEffect *pEffect = ParticleProp()->Create( "Advisor_Psychic_Beam", PATTACH_ABSORIGIN_FOLLOW );
Assert(pEffect);
if (!pEffect) return;
ParticleProp()->AddControlPoint( pEffect, 1, pOnEntity, PATTACH_ABSORIGIN_FOLLOW );
}
//-----------------------------------------------------------------------------
// terminate a telekinetic beam effect from my head to an object
//-----------------------------------------------------------------------------
void C_NPC_Advisor::StopBeamFX( C_BaseEntity *pOnEntity )
{
Assert(pOnEntity);
if (!pOnEntity)
return;
ParticleProp()->StopParticlesInvolving( pOnEntity );
}
void C_NPC_Advisor::StartElight()
{
AssertMsg(m_ElightKey == 0 , "Advisor trying to create new elight on top of old one!");
if ( m_ElightKey != 0 )
{
Warning("Advisor tried to start his elight when it was already one.\n");
}
else
{
m_ElightKey = LIGHT_INDEX_TE_DYNAMIC + this->entindex();
dlight_t * el = effects->CL_AllocElight( m_ElightKey );
if ( el )
{
// create an elight on top of me
el->origin = this->WorldSpaceCenter();
el->color.r = 235;
el->color.g = 255;
el->color.b = 255;
el->color.exponent = 3;
el->radius = 52*12;
el->decay = 0.0f;
el->die = gpGlobals->curtime + 2000.0f; // 1000 just means " a long time "
SetNextClientThink( CLIENT_THINK_ALWAYS );
}
else
{ // null out the light value
m_ElightKey = 0;
}
}
}
void C_NPC_Advisor::StopElight()
{
AssertMsg( m_ElightKey != 0, "Advisor tried to stop elight when none existed!");
dlight_t * el;
// note: the following conditional sets el if not short-circuited
if ( m_ElightKey == 0 || (el = effects->GetElightByKey(m_ElightKey)) == NULL )
{
Warning("Advisor tried to stop its elight when it had none.\n");
}
else
{
// kill the elight by setting the die value to now
el->die = gpGlobals->curtime;
}
}
#endif
/******************************************************
* Tenser, said the Tensor. *
* Tenser, said the Tensor. *
* Tension, apprehension and dissension have begun. *
******************************************************/
+167
View File
@@ -0,0 +1,167 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
//=============================================================================
#include "cbase.h"
#include "c_ai_basenpc.h"
#include "bone_setup.h"
// Must be the last file included
#include "memdbgon.h"
extern ConVar r_sequence_debug;
class C_NPC_Puppet : public C_AI_BaseNPC
{
DECLARE_CLASS( C_NPC_Puppet, C_AI_BaseNPC );
public:
virtual void ClientThink( void );
virtual void OnDataChanged( DataUpdateType_t updateType );
virtual void BuildTransformations( CStudioHdr *pStudioHdr, Vector *pos, Quaternion q[], const matrix3x4_t& cameraTransform, int boneMask, CBoneBitList &boneComputed );
virtual void AccumulateLayers( IBoneSetup &boneSetup, Vector pos[], Quaternion q[], float currentTime );
EHANDLE m_hAnimationTarget;
int m_nTargetAttachment;
DECLARE_CLIENTCLASS();
};
IMPLEMENT_CLIENTCLASS_DT( C_NPC_Puppet, DT_NPC_Puppet, CNPC_Puppet )
RecvPropEHandle( RECVINFO(m_hAnimationTarget) ),
RecvPropInt( RECVINFO(m_nTargetAttachment) ),
END_RECV_TABLE()
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void C_NPC_Puppet::OnDataChanged( DataUpdateType_t updateType )
{
BaseClass::OnDataChanged( updateType );
if ( updateType == DATA_UPDATE_CREATED )
{
SetNextClientThink( CLIENT_THINK_ALWAYS );
}
}
//-----------------------------------------------------------------------------
// Purpose: We need to slam our position!
//-----------------------------------------------------------------------------
void C_NPC_Puppet::BuildTransformations( CStudioHdr *pStudioHdr, Vector *pos, Quaternion q[], const matrix3x4_t& cameraTransform, int boneMask, CBoneBitList &boneComputed )
{
if ( m_hAnimationTarget && m_nTargetAttachment != -1 )
{
C_BaseAnimating *pTarget = m_hAnimationTarget->GetBaseAnimating();
if ( pTarget )
{
matrix3x4_t matTarget;
pTarget->GetAttachment( m_nTargetAttachment, matTarget );
MatrixCopy( matTarget, GetBoneForWrite( 0 ) );
boneComputed.ClearAll(); // FIXME: Why is this calculated already?
boneComputed.MarkBone( 0 );
}
}
// Call the baseclass
BaseClass::BuildTransformations( pStudioHdr, pos, q, cameraTransform, boneMask, boneComputed );
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void C_NPC_Puppet::ClientThink( void )
{
if ( m_hAnimationTarget == NULL )
return;
C_BaseAnimating *pTarget = m_hAnimationTarget->GetBaseAnimating();
if ( pTarget == NULL )
return;
int nTargetSequence = pTarget->GetSequence();
const char *pSequenceName = pTarget->GetSequenceName( nTargetSequence );
int nSequence = LookupSequence( pSequenceName );
if ( nSequence >= 0 )
{
if ( nSequence != GetSequence() )
{
SetSequence( nSequence );
UpdateVisibility();
}
SetCycle( pTarget->GetCycle() );
SetPlaybackRate( pTarget->GetPlaybackRate() );
}
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void C_NPC_Puppet::AccumulateLayers( IBoneSetup &boneSetup, Vector pos[], Quaternion q[], float currentTime )
{
if ( m_hAnimationTarget == NULL )
return;
C_BaseAnimatingOverlay *pTarget = dynamic_cast<C_BaseAnimatingOverlay *>( m_hAnimationTarget->GetBaseAnimating() );
if ( pTarget == NULL )
return;
// resort the layers
int layer[MAX_OVERLAYS];
int i;
for (i = 0; i < MAX_OVERLAYS; i++)
{
layer[i] = MAX_OVERLAYS;
}
for (i = 0; i < pTarget->m_AnimOverlay.Count(); i++)
{
if (pTarget->m_AnimOverlay[i].m_nOrder < MAX_OVERLAYS)
{
layer[pTarget->m_AnimOverlay[i].m_nOrder] = i;
}
}
int j;
for (j = 0; j < MAX_OVERLAYS; j++)
{
i = layer[ j ];
if (i < pTarget->m_AnimOverlay.Count())
{
float fWeight = pTarget->m_AnimOverlay[i].m_flWeight;
if (fWeight > 0)
{
const char *pSequenceName = pTarget->GetSequenceName( pTarget->m_AnimOverlay[i].m_nSequence );
int nSequence = LookupSequence( pSequenceName );
if ( nSequence >= 0 )
{
float fCycle = pTarget->m_AnimOverlay[ i ].m_flCycle;
fCycle = ClampCycle( fCycle, IsSequenceLooping( nSequence ) );
if (fWeight > 1)
fWeight = 1;
boneSetup.AccumulatePose( pos, q, nSequence, fCycle, fWeight, currentTime, NULL );
#if _DEBUG
if (Q_stristr( boneSetup.GetStudioHdr()->pszName(), r_sequence_debug.GetString()) != NULL)
{
DevMsgRT( "%6.2f : %30s : %5.3f : %4.2f : %1d\n", currentTime, boneSetup.GetStudioHdr()->pSeqdesc( nSequence ).pszLabel(), fCycle, fWeight, i );
}
#endif
}
}
}
}
}
+142
View File
@@ -0,0 +1,142 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
//=============================================================================
#include "cbase.h"
class C_PropCoreBall : public C_BaseAnimating
{
DECLARE_CLASS( C_PropCoreBall, C_BaseAnimating );
DECLARE_CLIENTCLASS();
DECLARE_DATADESC();
public:
C_PropCoreBall();
void ApplyBoneMatrixTransform( matrix3x4_t& transform );
float m_flScaleX;
float m_flScaleY;
float m_flScaleZ;
float m_flLerpTimeX;
float m_flLerpTimeY;
float m_flLerpTimeZ;
float m_flGoalTimeX;
float m_flGoalTimeY;
float m_flGoalTimeZ;
float m_flCurrentScale[3];
bool m_bRunningScale[3];
float m_flTargetScale[3];
private:
};
void RecvProxy_ScaleX( const CRecvProxyData *pData, void *pStruct, void *pOut )
{
C_PropCoreBall *pCoreData = (C_PropCoreBall *) pStruct;
pCoreData->m_flScaleX = pData->m_Value.m_Float;
if ( pCoreData->m_bRunningScale[0] == true )
{
pCoreData->m_flTargetScale[0] = pCoreData->m_flCurrentScale[0];
}
}
void RecvProxy_ScaleY( const CRecvProxyData *pData, void *pStruct, void *pOut )
{
C_PropCoreBall *pCoreData = (C_PropCoreBall *) pStruct;
pCoreData->m_flScaleY = pData->m_Value.m_Float;
if ( pCoreData->m_bRunningScale[1] == true )
{
pCoreData->m_flTargetScale[1] = pCoreData->m_flCurrentScale[1];
}
}
void RecvProxy_ScaleZ( const CRecvProxyData *pData, void *pStruct, void *pOut )
{
C_PropCoreBall *pCoreData = (C_PropCoreBall *) pStruct;
pCoreData->m_flScaleZ = pData->m_Value.m_Float;
if ( pCoreData->m_bRunningScale[2] == true )
{
pCoreData->m_flTargetScale[2] = pCoreData->m_flCurrentScale[2];
}
}
IMPLEMENT_CLIENTCLASS_DT( C_PropCoreBall, DT_PropCoreBall, CPropCoreBall )
RecvPropFloat( RECVINFO( m_flScaleX ), 0, RecvProxy_ScaleX ),
RecvPropFloat( RECVINFO( m_flScaleY ), 0, RecvProxy_ScaleY ),
RecvPropFloat( RECVINFO( m_flScaleZ ), 0, RecvProxy_ScaleZ ),
RecvPropFloat( RECVINFO( m_flLerpTimeX ) ),
RecvPropFloat( RECVINFO( m_flLerpTimeY ) ),
RecvPropFloat( RECVINFO( m_flLerpTimeZ ) ),
RecvPropFloat( RECVINFO( m_flGoalTimeX ) ),
RecvPropFloat( RECVINFO( m_flGoalTimeY ) ),
RecvPropFloat( RECVINFO( m_flGoalTimeZ ) ),
END_RECV_TABLE()
BEGIN_DATADESC( C_PropCoreBall )
DEFINE_AUTO_ARRAY( m_flTargetScale, FIELD_FLOAT ),
DEFINE_AUTO_ARRAY( m_bRunningScale, FIELD_BOOLEAN ),
END_DATADESC()
C_PropCoreBall::C_PropCoreBall( void )
{
m_flTargetScale[0] = 1.0f;
m_flTargetScale[1] = 1.0f;
m_flTargetScale[2] = 1.0f;
m_bRunningScale[0] = false;
m_bRunningScale[1] = false;
m_bRunningScale[2] = false;
}
void C_PropCoreBall::ApplyBoneMatrixTransform( matrix3x4_t& transform )
{
BaseClass::ApplyBoneMatrixTransform( transform );
float flVal[3] = { m_flTargetScale[0], m_flTargetScale[1], m_flTargetScale[2] };
float *flTargetScale[3] = { &m_flTargetScale[0], &m_flTargetScale[1], &m_flTargetScale[2] };
float flScale[3] = { m_flScaleX, m_flScaleY, m_flScaleZ };
float flLerpTime[3] = { m_flLerpTimeX, m_flLerpTimeY, m_flLerpTimeZ };
float flGoalTime[3] = { m_flGoalTimeX, m_flGoalTimeY, m_flGoalTimeZ };
bool *bRunning[3] = { &m_bRunningScale[0], &m_bRunningScale[1], &m_bRunningScale[2] };
for ( int i = 0; i < 3; i++ )
{
if ( *flTargetScale[i] != flScale[i] )
{
float deltaTime = (float)( gpGlobals->curtime - flGoalTime[i]) / flLerpTime[i];
float flRemapVal = SimpleSplineRemapVal( deltaTime, 0.0f, 1.0f, *flTargetScale[i], flScale[i] );
*bRunning[i] = true;
if ( deltaTime >= 1.0f )
{
*flTargetScale[i] = flScale[i];
*bRunning[i] = false;
}
flVal[i] = flRemapVal;
m_flCurrentScale[i] = flVal[i];
}
}
VectorScale( transform[0], flVal[0], transform[0] );
VectorScale( transform[1], flVal[1], transform[1] );
VectorScale( transform[2], flVal[2], transform[2] );
}
+196
View File
@@ -0,0 +1,196 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
//=============================================================================
#include "cbase.h"
class C_PropScalable : public C_BaseAnimating
{
DECLARE_CLASS( C_PropScalable, C_BaseAnimating );
DECLARE_CLIENTCLASS();
DECLARE_DATADESC();
public:
C_PropScalable();
virtual void ApplyBoneMatrixTransform( matrix3x4_t& transform );
virtual void GetRenderBounds( Vector &theMins, Vector &theMaxs );
// Must be available to proxy functions
float m_flScaleX;
float m_flScaleY;
float m_flScaleZ;
float m_flLerpTimeX;
float m_flLerpTimeY;
float m_flLerpTimeZ;
float m_flGoalTimeX;
float m_flGoalTimeY;
float m_flGoalTimeZ;
float m_flCurrentScale[3];
bool m_bRunningScale[3];
float m_flTargetScale[3];
private:
void CalculateScale( void );
float m_nCalcFrame; // Frame the last calculation was made at
};
void RecvProxy_ScaleX( const CRecvProxyData *pData, void *pStruct, void *pOut )
{
C_PropScalable *pCoreData = (C_PropScalable *) pStruct;
pCoreData->m_flScaleX = pData->m_Value.m_Float;
if ( pCoreData->m_bRunningScale[0] == true )
{
pCoreData->m_flTargetScale[0] = pCoreData->m_flCurrentScale[0];
}
}
void RecvProxy_ScaleY( const CRecvProxyData *pData, void *pStruct, void *pOut )
{
C_PropScalable *pCoreData = (C_PropScalable *) pStruct;
pCoreData->m_flScaleY = pData->m_Value.m_Float;
if ( pCoreData->m_bRunningScale[1] == true )
{
pCoreData->m_flTargetScale[1] = pCoreData->m_flCurrentScale[1];
}
}
void RecvProxy_ScaleZ( const CRecvProxyData *pData, void *pStruct, void *pOut )
{
C_PropScalable *pCoreData = (C_PropScalable *) pStruct;
pCoreData->m_flScaleZ = pData->m_Value.m_Float;
if ( pCoreData->m_bRunningScale[2] == true )
{
pCoreData->m_flTargetScale[2] = pCoreData->m_flCurrentScale[2];
}
}
IMPLEMENT_CLIENTCLASS_DT( C_PropScalable, DT_PropScalable, CPropScalable )
RecvPropFloat( RECVINFO( m_flScaleX ), 0, RecvProxy_ScaleX ),
RecvPropFloat( RECVINFO( m_flScaleY ), 0, RecvProxy_ScaleY ),
RecvPropFloat( RECVINFO( m_flScaleZ ), 0, RecvProxy_ScaleZ ),
RecvPropFloat( RECVINFO( m_flLerpTimeX ) ),
RecvPropFloat( RECVINFO( m_flLerpTimeY ) ),
RecvPropFloat( RECVINFO( m_flLerpTimeZ ) ),
RecvPropFloat( RECVINFO( m_flGoalTimeX ) ),
RecvPropFloat( RECVINFO( m_flGoalTimeY ) ),
RecvPropFloat( RECVINFO( m_flGoalTimeZ ) ),
END_RECV_TABLE()
BEGIN_DATADESC( C_PropScalable )
DEFINE_AUTO_ARRAY( m_flTargetScale, FIELD_FLOAT ),
DEFINE_AUTO_ARRAY( m_bRunningScale, FIELD_BOOLEAN ),
END_DATADESC()
C_PropScalable::C_PropScalable( void )
{
m_flTargetScale[0] = 1.0f;
m_flTargetScale[1] = 1.0f;
m_flTargetScale[2] = 1.0f;
m_bRunningScale[0] = false;
m_bRunningScale[1] = false;
m_bRunningScale[2] = false;
m_nCalcFrame = 0;
}
//-----------------------------------------------------------------------------
// Purpose: Calculates the scake of the object once per frame
//-----------------------------------------------------------------------------
void C_PropScalable::CalculateScale( void )
{
// Don't bother to calculate this for a second time in the same frame
if ( m_nCalcFrame == gpGlobals->framecount )
return;
// Mark that we cached this value for the frame
m_nCalcFrame = gpGlobals->framecount;
float flVal[3] = { m_flTargetScale[0], m_flTargetScale[1], m_flTargetScale[2] };
float *flTargetScale[3] = { &m_flTargetScale[0], &m_flTargetScale[1], &m_flTargetScale[2] };
float flScale[3] = { m_flScaleX, m_flScaleY, m_flScaleZ };
float flLerpTime[3] = { m_flLerpTimeX, m_flLerpTimeY, m_flLerpTimeZ };
float flGoalTime[3] = { m_flGoalTimeX, m_flGoalTimeY, m_flGoalTimeZ };
bool *bRunning[3] = { &m_bRunningScale[0], &m_bRunningScale[1], &m_bRunningScale[2] };
for ( int i = 0; i < 3; i++ )
{
if ( *flTargetScale[i] != flScale[i] )
{
float deltaTime = (float)( gpGlobals->curtime - flGoalTime[i]) / flLerpTime[i];
float flRemapVal = SimpleSplineRemapValClamped( deltaTime, 0.0f, 1.0f, *flTargetScale[i], flScale[i] );
*bRunning[i] = true;
if ( deltaTime >= 1.0f )
{
*flTargetScale[i] = flScale[i];
*bRunning[i] = false;
}
flVal[i] = flRemapVal;
m_flCurrentScale[i] = flVal[i];
}
else
{
m_flCurrentScale[i] = m_flTargetScale[i];
}
}
}
//-----------------------------------------------------------------------------
// Purpose: Scales the bones based on the current scales
//-----------------------------------------------------------------------------
void C_PropScalable::ApplyBoneMatrixTransform( matrix3x4_t& transform )
{
BaseClass::ApplyBoneMatrixTransform( transform );
// Find the scale for this frame
CalculateScale();
VectorScale( transform[0], m_flCurrentScale[0], transform[0] );
VectorScale( transform[1], m_flCurrentScale[1], transform[1] );
VectorScale( transform[2], m_flCurrentScale[2], transform[2] );
UpdateVisibility();
}
//-----------------------------------------------------------------------------
// Purpose: Ensures the render bounds match the scales
//-----------------------------------------------------------------------------
void C_PropScalable::GetRenderBounds( Vector &theMins, Vector &theMaxs )
{
BaseClass::GetRenderBounds( theMins, theMaxs );
// Find the scale for this frame
CalculateScale();
// Extend our render bounds to encompass the scaled object
theMins.x *= m_flCurrentScale[0];
theMins.y *= m_flCurrentScale[1];
theMins.z *= m_flCurrentScale[2];
theMaxs.x *= m_flCurrentScale[0];
theMaxs.y *= m_flCurrentScale[1];
theMaxs.z *= m_flCurrentScale[2];
Assert( theMins.IsValid() && theMaxs.IsValid() );
}
@@ -0,0 +1,133 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
//=============================================================================//
#include "cbase.h"
#include "c_prop_vehicle.h"
#include "c_vehicle_jeep.h"
#include "movevars_shared.h"
#include "view.h"
#include "flashlighteffect.h"
#include "c_baseplayer.h"
#include "c_te_effect_dispatch.h"
#include "hl2_vehicle_radar.h"
#include "usermessages.h"
#include "hud_radar.h"
// memdbgon must be the last include file in a .cpp file!!!
#include "tier0/memdbgon.h"
//=============================================================================
//
// Client-side Episodic Jeep (Jalopy) Class
//
class C_PropJeepEpisodic : public C_PropJeep
{
DECLARE_CLASS( C_PropJeepEpisodic, C_PropJeep );
public:
DECLARE_CLIENTCLASS();
public:
C_PropJeepEpisodic();
void OnEnteredVehicle( C_BasePlayer *pPlayer );
void Simulate( void );
public:
int m_iNumRadarContacts;
Vector m_vecRadarContactPos[ RADAR_MAX_CONTACTS ];
int m_iRadarContactType[ RADAR_MAX_CONTACTS ];
};
C_PropJeepEpisodic *g_pJalopy = NULL;
IMPLEMENT_CLIENTCLASS_DT( C_PropJeepEpisodic, DT_CPropJeepEpisodic, CPropJeepEpisodic )
//CNetworkVar( int, m_iNumRadarContacts );
RecvPropInt( RECVINFO(m_iNumRadarContacts) ),
//CNetworkArray( Vector, m_vecRadarContactPos, RADAR_MAX_CONTACTS );
RecvPropArray( RecvPropVector(RECVINFO(m_vecRadarContactPos[0])), m_vecRadarContactPos ),
//CNetworkArray( int, m_iRadarContactType, RADAR_MAX_CONTACTS );
RecvPropArray( RecvPropInt( RECVINFO(m_iRadarContactType[0] ) ), m_iRadarContactType ),
END_RECV_TABLE()
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void __MsgFunc_UpdateJalopyRadar(bf_read &msg)
{
// Radar code here!
if( !GetHudRadar() )
return;
// Sometimes we update more quickly when we need to track something in high resolution.
// Usually we do not, so default to false.
GetHudRadar()->m_bUseFastUpdate = false;
for( int i = 0 ; i < g_pJalopy->m_iNumRadarContacts ; i++ )
{
if( g_pJalopy->m_iRadarContactType[i] == RADAR_CONTACT_DOG )
{
GetHudRadar()->m_bUseFastUpdate = true;
break;
}
}
float flContactTimeToLive;
if( GetHudRadar()->m_bUseFastUpdate )
{
flContactTimeToLive = RADAR_UPDATE_FREQUENCY_FAST;
}
else
{
flContactTimeToLive = RADAR_UPDATE_FREQUENCY;
}
for( int i = 0 ; i < g_pJalopy->m_iNumRadarContacts ; i++ )
{
GetHudRadar()->AddRadarContact( g_pJalopy->m_vecRadarContactPos[i], g_pJalopy->m_iRadarContactType[i], flContactTimeToLive );
}
}
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
C_PropJeepEpisodic::C_PropJeepEpisodic()
{
if( g_pJalopy == NULL )
{
usermessages->HookMessage( "UpdateJalopyRadar", __MsgFunc_UpdateJalopyRadar );
}
g_pJalopy = this;
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void C_PropJeepEpisodic::Simulate( void )
{
// Keep trying to hook to the radar.
if( GetHudRadar() != NULL )
{
// This is not our ideal long-term solution. This will only work if you only have
// one jalopy in a given level. The Jalopy and the Radar Screen are currently both
// assumed to be singletons. This is appropriate for EP2, however. (sjb)
GetHudRadar()->SetVehicle( this );
}
BaseClass::Simulate();
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void C_PropJeepEpisodic::OnEnteredVehicle( C_BasePlayer *pPlayer )
{
BaseClass::OnEnteredVehicle( pPlayer );
}
@@ -0,0 +1,600 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
//=====================================================================================//
#include "cbase.h"
#include "particles_simple.h"
#include "citadel_effects_shared.h"
#include "particles_attractor.h"
#include "iefx.h"
#include "dlight.h"
#include "clienteffectprecachesystem.h"
#include "c_te_effect_dispatch.h"
#include "fx_quad.h"
#include "c_ai_basenpc.h"
// For material proxy
#include "proxyentity.h"
#include "materialsystem/imaterial.h"
#include "materialsystem/imaterialvar.h"
#define NUM_INTERIOR_PARTICLES 8
#define DLIGHT_RADIUS (150.0f)
#define DLIGHT_MINLIGHT (40.0f/255.0f)
class C_NPC_Vortigaunt : public C_AI_BaseNPC
{
DECLARE_CLASS( C_NPC_Vortigaunt, C_AI_BaseNPC );
DECLARE_CLIENTCLASS();
public:
virtual void OnDataChanged( DataUpdateType_t updateType );
virtual void ClientThink( void );
virtual void ReceiveMessage( int classID, bf_read &msg );
public:
bool m_bIsBlue; ///< wants to fade to blue
float m_flBlueEndFadeTime; ///< when to end fading from one skin to another
bool m_bIsBlack; ///< wants to fade to black (networked)
float m_flBlackFade; ///< [0.00 .. 1.00] where 1.00 is all black. Locally interpolated.
};
IMPLEMENT_CLIENTCLASS_DT( C_NPC_Vortigaunt, DT_NPC_Vortigaunt, CNPC_Vortigaunt )
RecvPropTime( RECVINFO(m_flBlueEndFadeTime ) ),
RecvPropBool( RECVINFO(m_bIsBlue) ),
RecvPropBool( RECVINFO(m_bIsBlack) ),
END_RECV_TABLE()
#define VORTIGAUNT_BLUE_FADE_TIME 2.25f // takes this long to fade from green to blue or back
#define VORT_BLACK_FADE_TIME 2.2f // time to interpolate up or down in fading to black
//-----------------------------------------------------------------------------
// Purpose:
// Input : updateType -
//-----------------------------------------------------------------------------
void C_NPC_Vortigaunt::OnDataChanged( DataUpdateType_t updateType )
{
BaseClass::OnDataChanged( updateType );
// start thinking if we need to fade.
if ( m_flBlackFade != (m_bIsBlack ? 1.0f : 0.0f) )
{
SetNextClientThink( CLIENT_THINK_ALWAYS );
}
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void C_NPC_Vortigaunt::ClientThink( void )
{
// Don't update if our frame hasn't moved forward (paused)
if ( gpGlobals->frametime <= 0.0f )
return;
if ( m_bIsBlack )
{
// are we done?
if ( m_flBlackFade >= 1.0f )
{
m_flBlackFade = 1.0f;
SetNextClientThink( CLIENT_THINK_NEVER );
}
else // interpolate there
{
float lerpQuant = gpGlobals->frametime / VORT_BLACK_FADE_TIME;
m_flBlackFade += lerpQuant;
if ( m_flBlackFade > 1.0f )
{
m_flBlackFade = 1.0f;
}
}
}
else
{
// are we done?
if ( m_flBlackFade <= 0.0f )
{
m_flBlackFade = 0.0f;
SetNextClientThink( CLIENT_THINK_NEVER );
}
else // interpolate there
{
float lerpQuant = gpGlobals->frametime / VORT_BLACK_FADE_TIME;
m_flBlackFade -= lerpQuant;
if ( m_flBlackFade < 0.0f )
{
m_flBlackFade = 0.0f;
}
}
}
}
// FIXME: Move to shared code!
#define VORTFX_ZAPBEAM 0
#define VORTFX_ARMBEAM 1
//-----------------------------------------------------------------------------
// Purpose: Receive messages from the server
//-----------------------------------------------------------------------------
void C_NPC_Vortigaunt::ReceiveMessage( int classID, bf_read &msg )
{
// Is the message for a sub-class?
if ( classID != GetClientClass()->m_ClassID )
{
BaseClass::ReceiveMessage( classID, msg );
return;
}
int messageType = msg.ReadByte();
switch( messageType )
{
case VORTFX_ZAPBEAM:
{
// Find our attachment point
unsigned char nAttachment = msg.ReadByte();
// Get our attachment position
Vector vecStart;
QAngle vecAngles;
GetAttachment( nAttachment, vecStart, vecAngles );
// Get the final position we'll strike
Vector vecEndPos;
msg.ReadBitVec3Coord( vecEndPos );
// Place a beam between the two points
CNewParticleEffect *pEffect = ParticleProp()->Create( "vortigaunt_beam", PATTACH_POINT_FOLLOW, nAttachment );
if ( pEffect )
{
pEffect->SetControlPoint( 0, vecStart );
pEffect->SetControlPoint( 1, vecEndPos );
}
}
break;
case VORTFX_ARMBEAM:
{
int nIndex = msg.ReadLong();
C_BaseEntity *pEnt = ClientEntityList().GetBaseEntityFromHandle( ClientEntityList().EntIndexToHandle( nIndex ) );
if ( pEnt )
{
unsigned char nAttachment = msg.ReadByte();
Vector vecEndPos;
msg.ReadBitVec3Coord( vecEndPos );
Vector vecNormal;
msg.ReadBitVec3Normal( vecNormal );
CNewParticleEffect *pEffect = pEnt->ParticleProp()->Create( "vortigaunt_beam_charge", PATTACH_POINT_FOLLOW, nAttachment );
if ( pEffect )
{
// Set the control point's angles to be the surface normal we struct
Vector vecRight, vecUp;
VectorVectors( vecNormal, vecRight, vecUp );
pEffect->SetControlPointOrientation( 1, vecNormal, vecRight, vecUp );
pEffect->SetControlPoint( 1, vecEndPos );
}
}
}
break;
default:
AssertMsg1( false, "Received unknown message %d", messageType);
}
}
class C_VortigauntChargeToken : public C_BaseEntity
{
DECLARE_CLASS( C_VortigauntChargeToken, C_BaseEntity );
DECLARE_CLIENTCLASS();
public:
virtual void UpdateOnRemove( void );
virtual void ClientThink( void );
virtual void NotifyShouldTransmit( ShouldTransmitState_t state );
virtual void OnDataChanged( DataUpdateType_t type );
// For RecvProxy handlers
float m_flFadeOutTime;
float m_flFadeOutStart;
private:
bool SetupEmitters( void );
bool m_bFadeOut;
CNewParticleEffect *m_hEffect;
dlight_t *m_pDLight;
};
void RecvProxy_FadeOutDuration( const CRecvProxyData *pData, void *pStruct, void *pOut )
{
C_VortigauntChargeToken *pVortToken = (C_VortigauntChargeToken *) pStruct;
Assert( pOut == &pVortToken->m_flFadeOutTime );
pVortToken->m_flFadeOutStart = gpGlobals->curtime;
pVortToken->m_flFadeOutTime = ( pData->m_Value.m_Float - gpGlobals->curtime );
}
IMPLEMENT_CLIENTCLASS_DT( C_VortigauntChargeToken, DT_VortigauntChargeToken, CVortigauntChargeToken )
RecvPropBool( RECVINFO( m_bFadeOut ) ),
END_RECV_TABLE()
void C_VortigauntChargeToken::UpdateOnRemove( void )
{
if ( m_hEffect )
{
m_hEffect->StopEmission();
m_hEffect = NULL;
}
if ( m_pDLight != NULL )
{
m_pDLight->die = gpGlobals->curtime;
}
}
//-----------------------------------------------------------------------------
// Purpose: Change our transmission state
//-----------------------------------------------------------------------------
void C_VortigauntChargeToken::NotifyShouldTransmit( ShouldTransmitState_t state )
{
BaseClass::NotifyShouldTransmit( state );
// Turn off
if ( state == SHOULDTRANSMIT_END )
{
if ( m_hEffect )
{
m_hEffect->StopEmission();
m_hEffect = NULL;
}
}
// Turn on
if ( state == SHOULDTRANSMIT_START )
{
m_hEffect = ParticleProp()->Create( "vortigaunt_charge_token", PATTACH_ABSORIGIN_FOLLOW );
m_hEffect->SetControlPointEntity( 0, this );
}
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void C_VortigauntChargeToken::OnDataChanged( DataUpdateType_t type )
{
if ( m_bFadeOut )
{
if ( m_hEffect )
{
m_hEffect->StopEmission();
m_hEffect = NULL;
}
}
BaseClass::OnDataChanged( type );
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void C_VortigauntChargeToken::ClientThink( void )
{
//
// -- DLight
//
if ( m_pDLight != NULL )
{
m_pDLight->origin = GetAbsOrigin();
m_pDLight->radius = DLIGHT_RADIUS;
}
}
//=============================================================================
//
// Dispel Effect
//
//=============================================================================
class C_VortigauntEffectDispel : public C_BaseEntity
{
DECLARE_CLASS( C_VortigauntEffectDispel, C_BaseEntity );
DECLARE_CLIENTCLASS();
public:
virtual void UpdateOnRemove( void );
virtual void ClientThink( void );
virtual void NotifyShouldTransmit( ShouldTransmitState_t state );
virtual void OnDataChanged( DataUpdateType_t type );
// For RecvProxy handlers
float m_flFadeOutTime;
float m_flFadeOutStart;
private:
bool SetupEmitters( void );
CNewParticleEffect *m_hEffect;
bool m_bFadeOut;
dlight_t *m_pDLight;
};
void RecvProxy_DispelFadeOutDuration( const CRecvProxyData *pData, void *pStruct, void *pOut )
{
C_VortigauntEffectDispel *pVortToken = (C_VortigauntEffectDispel *) pStruct;
Assert( pOut == &pVortToken->m_flFadeOutTime );
pVortToken->m_flFadeOutStart = gpGlobals->curtime;
pVortToken->m_flFadeOutTime = ( pData->m_Value.m_Float - gpGlobals->curtime );
}
IMPLEMENT_CLIENTCLASS_DT( C_VortigauntEffectDispel, DT_VortigauntEffectDispel, CVortigauntEffectDispel )
RecvPropBool( RECVINFO( m_bFadeOut ) ),
END_RECV_TABLE()
void C_VortigauntEffectDispel::UpdateOnRemove( void )
{
if ( m_hEffect )
{
m_hEffect->StopEmission();
m_hEffect = NULL;
}
if ( m_pDLight != NULL )
{
m_pDLight->die = gpGlobals->curtime;
}
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void C_VortigauntEffectDispel::OnDataChanged( DataUpdateType_t type )
{
if ( m_bFadeOut )
{
if ( m_hEffect )
{
m_hEffect->StopEmission();
m_hEffect = NULL;
}
}
BaseClass::OnDataChanged( type );
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void C_VortigauntEffectDispel::NotifyShouldTransmit( ShouldTransmitState_t state )
{
BaseClass::NotifyShouldTransmit( state );
// Turn off
if ( state == SHOULDTRANSMIT_END )
{
if ( m_hEffect )
{
m_hEffect->StopEmission();
m_hEffect = NULL;
}
}
// Turn on
if ( state == SHOULDTRANSMIT_START )
{
m_hEffect = ParticleProp()->Create( "vortigaunt_hand_glow", PATTACH_ABSORIGIN_FOLLOW );
m_hEffect->SetControlPointEntity( 0, this );
}
}
//-----------------------------------------------------------------------------
// Purpose: Create our emitter
//-----------------------------------------------------------------------------
bool C_VortigauntEffectDispel::SetupEmitters( void )
{
m_pDLight = NULL;
#ifndef _X360
m_pDLight = effects->CL_AllocDlight ( index );
m_pDLight->origin = GetAbsOrigin();
m_pDLight->color.r = 64;
m_pDLight->color.g = 255;
m_pDLight->color.b = 64;
m_pDLight->radius = 0;
m_pDLight->minlight = DLIGHT_MINLIGHT;
m_pDLight->die = FLT_MAX;
#endif // _X360
return true;
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void C_VortigauntEffectDispel::ClientThink( void )
{
if ( m_pDLight != NULL )
{
m_pDLight->origin = GetAbsOrigin();
m_pDLight->radius = DLIGHT_RADIUS;
}
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void DispelCallback( const CEffectData &data )
{
// Kaboom!
Vector startPos = data.m_vOrigin + Vector(0,0,16);
Vector endPos = data.m_vOrigin + Vector(0,0,-64);
trace_t tr;
UTIL_TraceLine( startPos, endPos, MASK_SOLID_BRUSHONLY, NULL, COLLISION_GROUP_NONE, &tr );
if ( tr.fraction < 1.0f )
{
//Add a ripple quad to the surface
FX_AddQuad( tr.endpos + ( tr.plane.normal * 8.0f ),
Vector( 0, 0, 1 ),
64.0f,
600.0f,
0.8f,
1.0f, // start alpha
0.0f, // end alpha
0.3f,
random->RandomFloat( 0, 360 ),
0.0f,
Vector( 0.5f, 1.0f, 0.5f ),
0.75f,
"effects/ar2_altfire1b",
(FXQUAD_BIAS_SCALE|FXQUAD_BIAS_ALPHA|FXQUAD_COLOR_FADE) );
//Add a ripple quad to the surface
FX_AddQuad( tr.endpos + ( tr.plane.normal * 8.0f ),
Vector( 0, 0, 1 ),
16.0f,
300.0f,
0.9f,
1.0f, // start alpha
0.0f, // end alpha
0.9f,
random->RandomFloat( 0, 360 ),
0.0f,
Vector( 0.5f, 1.0f, 0.5f ),
1.25f,
"effects/rollerglow",
(FXQUAD_BIAS_SCALE|FXQUAD_BIAS_ALPHA) );
}
}
DECLARE_CLIENT_EFFECT( "VortDispel", DispelCallback );
//-----------------------------------------------------------------------------
// Purpose: Used for emissive lightning layer on vort
//-----------------------------------------------------------------------------
class CVortEmissiveProxy : public CEntityMaterialProxy
{
public:
CVortEmissiveProxy( void );
virtual ~CVortEmissiveProxy( void );
virtual bool Init( IMaterial *pMaterial, KeyValues* pKeyValues );
virtual void OnBind( C_BaseEntity *pC_BaseEntity );
virtual IMaterial * GetMaterial();
private:
IMaterialVar *m_pMatEmissiveStrength;
IMaterialVar *m_pMatDetailBlendStrength;
};
//-----------------------------------------------------------------------------
CVortEmissiveProxy::CVortEmissiveProxy( void )
{
m_pMatEmissiveStrength = NULL;
m_pMatDetailBlendStrength = NULL;
}
CVortEmissiveProxy::~CVortEmissiveProxy( void )
{
// Do nothing
}
//-----------------------------------------------------------------------------
bool CVortEmissiveProxy::Init( IMaterial *pMaterial, KeyValues* pKeyValues )
{
Assert( pMaterial );
// Need to get the material var
bool bFound;
m_pMatEmissiveStrength = pMaterial->FindVar( "$emissiveblendstrength", &bFound );
if ( bFound )
{
// Optional
bool bFound2;
m_pMatDetailBlendStrength = pMaterial->FindVar( "$detailblendfactor", &bFound2 );
}
return bFound;
}
//-----------------------------------------------------------------------------
void CVortEmissiveProxy::OnBind( C_BaseEntity *pEnt )
{
C_NPC_Vortigaunt *pVort = dynamic_cast<C_NPC_Vortigaunt *>(pEnt);
float flBlendValue;
if (pVort)
{
// do we need to crossfade?
if (gpGlobals->curtime < pVort->m_flBlueEndFadeTime)
{
// will be 0 when fully faded and 1 when not faded at all:
float fadeRatio = (pVort->m_flBlueEndFadeTime - gpGlobals->curtime) / VORTIGAUNT_BLUE_FADE_TIME;
if (pVort->m_bIsBlue)
{
fadeRatio = 1.0f - fadeRatio;
}
flBlendValue = clamp( fadeRatio, 0.0f, 1.0f );
}
else // no crossfade
{
flBlendValue = pVort->m_bIsBlue ? 1.0f : 0.0f;
}
// ALEX VLACHOS:
// The following variable varies on [0 .. 1]. 0.0 means the vort wants to be his normal
// color. 1.0 means he wants to be all black. It is interpolated in the
// C_NPC_Vortigaunt::ClientThink() function.
//
// pVort->m_flBlackFade
}
else
{ // if you bind this proxy to anything non-vort (eg a ragdoll) it's always green
flBlendValue = 0.0f;
}
/*
// !!! Change me !!! I'm using a clamped sin wave for debugging
float flBlendValue = sinf( gpGlobals->curtime * 4.0f ) * 0.75f + 0.25f;
// Clamp 0-1
flBlendValue = ( flBlendValue < 0.0f ) ? 0.0f : ( flBlendValue > 1.0f ) ? 1.0f : flBlendValue;
*/
if( m_pMatEmissiveStrength != NULL )
{
m_pMatEmissiveStrength->SetFloatValue( flBlendValue );
}
if( m_pMatDetailBlendStrength != NULL )
{
m_pMatDetailBlendStrength->SetFloatValue( flBlendValue );
}
}
//-----------------------------------------------------------------------------
IMaterial *CVortEmissiveProxy::GetMaterial()
{
if ( m_pMatEmissiveStrength != NULL )
return m_pMatEmissiveStrength->GetOwningMaterial();
else if ( m_pMatDetailBlendStrength != NULL )
return m_pMatDetailBlendStrength->GetOwningMaterial();
else
return NULL;
}
EXPOSE_INTERFACE( CVortEmissiveProxy, IMaterialProxy, "VortEmissive" IMATERIAL_PROXY_INTERFACE_VERSION );
+421
View File
@@ -0,0 +1,421 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
//=============================================================================
#include "cbase.h"
#include "basegrenade_shared.h"
#include "fx_interpvalue.h"
#include "fx_envelope.h"
#include "materialsystem/imaterialvar.h"
#include "particles_simple.h"
#include "particles_attractor.h"
// FIXME: Move out
extern void DrawSpriteTangentSpace( const Vector &vecOrigin, float flWidth, float flHeight, color32 color );
#define EXPLOSION_DURATION 3.0f
//-----------------------------------------------------------------------------
// Explosion effect for hopwire
//-----------------------------------------------------------------------------
class C_HopwireExplosion : public C_EnvelopeFX
{
typedef C_EnvelopeFX BaseClass;
public:
C_HopwireExplosion( void ) :
m_hOwner( NULL )
{
m_FXCoreScale.SetAbsolute( 0.0f );
m_FXCoreAlpha.SetAbsolute( 0.0f );
}
virtual void Update( void );
virtual int DrawModel( int flags );
virtual void GetRenderBounds( Vector& mins, Vector& maxs );
bool SetupEmitters( void );
void AddParticles( void );
void SetOwner( C_BaseEntity *pOwner );
void StartExplosion( void );
void StopExplosion( void );
void StartPreExplosion( void );
private:
CInterpolatedValue m_FXCoreScale;
CInterpolatedValue m_FXCoreAlpha;
CSmartPtr<CSimpleEmitter> m_pSimpleEmitter;
CSmartPtr<CParticleAttractor> m_pAttractorEmitter;
TimedEvent m_ParticleTimer;
CHandle<C_BaseEntity> m_hOwner;
};
//-----------------------------------------------------------------------------
// Purpose: Setup the emitters we'll be using
//-----------------------------------------------------------------------------
bool C_HopwireExplosion::SetupEmitters( void )
{
// Setup the basic core emitter
if ( m_pSimpleEmitter.IsValid() == false )
{
m_pSimpleEmitter = CSimpleEmitter::Create( "hopwirecore" );
if ( m_pSimpleEmitter.IsValid() == false )
return false;
}
// Setup the attractor emitter
if ( m_pAttractorEmitter.IsValid() == false )
{
m_pAttractorEmitter = CParticleAttractor::Create( GetRenderOrigin(), "hopwireattractor" );
if ( m_pAttractorEmitter.IsValid() == false )
return false;
}
return true;
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void C_HopwireExplosion::AddParticles( void )
{
// Make sure the emitters are setup properly
if ( SetupEmitters() == false )
return;
float tempDelta = gpGlobals->frametime;
while( m_ParticleTimer.NextEvent( tempDelta ) )
{
// ========================
// Attracted dust particles
// ========================
// Update our attractor point
m_pAttractorEmitter->SetAttractorOrigin( GetRenderOrigin() );
Vector offset;
SimpleParticle *sParticle;
offset = GetRenderOrigin() + RandomVector( -256.0f, 256.0f );
sParticle = (SimpleParticle *) m_pAttractorEmitter->AddParticle( sizeof(SimpleParticle), g_Mat_Fleck_Cement[0], offset );
if ( sParticle == NULL )
return;
sParticle->m_vecVelocity = Vector(0,0,8);
sParticle->m_flDieTime = 0.5f;
sParticle->m_flLifetime = 0.0f;
sParticle->m_flRoll = Helper_RandomInt( 0, 360 );
sParticle->m_flRollDelta = 1.0f;
float alpha = random->RandomFloat( 128.0f, 200.0f );
sParticle->m_uchColor[0] = alpha;
sParticle->m_uchColor[1] = alpha;
sParticle->m_uchColor[2] = alpha;
sParticle->m_uchStartAlpha = alpha;
sParticle->m_uchEndAlpha = alpha;
sParticle->m_uchStartSize = random->RandomInt( 1, 4 );
sParticle->m_uchEndSize = 0;
// ========================
// Core effects
// ========================
// Reset our sort origin
m_pSimpleEmitter->SetSortOrigin( GetRenderOrigin() );
// Base of the core effect
sParticle = (SimpleParticle *) m_pSimpleEmitter->AddParticle( sizeof(SimpleParticle), m_pSimpleEmitter->GetPMaterial( "effects/strider_muzzle" ), GetRenderOrigin() );
if ( sParticle == NULL )
return;
sParticle->m_vecVelocity = vec3_origin;
sParticle->m_flDieTime = 0.2f;
sParticle->m_flLifetime = 0.0f;
sParticle->m_flRoll = Helper_RandomInt( 0, 360 );
sParticle->m_flRollDelta = 4.0f;
alpha = random->RandomInt( 32, 200 );
sParticle->m_uchColor[0] = alpha;
sParticle->m_uchColor[1] = alpha;
sParticle->m_uchColor[2] = alpha;
sParticle->m_uchStartAlpha = 0;
sParticle->m_uchEndAlpha = alpha;
sParticle->m_uchStartSize = 255;
sParticle->m_uchEndSize = 0;
// Make sure we encompass the complete particle here!
m_pSimpleEmitter->SetParticleCullRadius( sParticle->m_uchEndSize );
// =========================
// Dust ring effect
// =========================
if ( random->RandomInt( 0, 5 ) != 1 )
return;
Vector vecDustColor;
vecDustColor.x = 0.35f;
vecDustColor.y = 0.3f;
vecDustColor.z = 0.25f;
Vector color;
int numRingSprites = 8;
float yaw;
Vector forward, vRight, vForward;
vForward = Vector( 0, 1, 0 );
vRight = Vector( 1, 0, 0 );
float yawOfs = random->RandomFloat( 0, 359 );
for ( int i = 0; i < numRingSprites; i++ )
{
yaw = ( (float) i / (float) numRingSprites ) * 360.0f;
yaw += yawOfs;
forward = ( vRight * sin( DEG2RAD( yaw) ) ) + ( vForward * cos( DEG2RAD( yaw ) ) );
VectorNormalize( forward );
trace_t tr;
UTIL_TraceLine( GetRenderOrigin(), GetRenderOrigin()+(Vector(0, 0, -1024)), MASK_SOLID_BRUSHONLY, NULL, COLLISION_GROUP_NONE, &tr );
offset = ( RandomVector( -4.0f, 4.0f ) + tr.endpos ) + ( forward * 512.0f );
sParticle = (SimpleParticle *) m_pSimpleEmitter->AddParticle( sizeof(SimpleParticle), g_Mat_DustPuff[random->RandomInt(0,1)], offset );
if ( sParticle != NULL )
{
sParticle->m_flLifetime = 0.0f;
sParticle->m_flDieTime = random->RandomFloat( 0.25f, 0.5f );
sParticle->m_vecVelocity = forward * -random->RandomFloat( 1000, 1500 );
sParticle->m_vecVelocity[2] += 128.0f;
#if __EXPLOSION_DEBUG
debugoverlay->AddLineOverlay( m_vecOrigin, m_vecOrigin + sParticle->m_vecVelocity, 255, 0, 0, false, 3 );
#endif
sParticle->m_uchColor[0] = vecDustColor.x * 255.0f;
sParticle->m_uchColor[1] = vecDustColor.y * 255.0f;
sParticle->m_uchColor[2] = vecDustColor.z * 255.0f;
sParticle->m_uchStartSize = random->RandomInt( 32, 128 );
sParticle->m_uchEndSize = 200;
sParticle->m_uchStartAlpha = random->RandomFloat( 16, 64 );
sParticle->m_uchEndAlpha = 0;
sParticle->m_flRoll = random->RandomInt( 0, 360 );
sParticle->m_flRollDelta = random->RandomFloat( -16.0f, 16.0f );
}
}
}
}
//-----------------------------------------------------------------------------
// Purpose:
// Input : *pOwner -
//-----------------------------------------------------------------------------
void C_HopwireExplosion::SetOwner( C_BaseEntity *pOwner )
{
m_hOwner = pOwner;
}
//-----------------------------------------------------------------------------
// Purpose: Updates the internal values for the effect
//-----------------------------------------------------------------------------
void C_HopwireExplosion::Update( void )
{
if ( m_hOwner )
{
SetRenderOrigin( m_hOwner->GetRenderOrigin() );
}
BaseClass::Update();
}
//-----------------------------------------------------------------------------
// Purpose: Updates and renders all effects
//-----------------------------------------------------------------------------
int C_HopwireExplosion::DrawModel( int flags )
{
AddParticles();
CMatRenderContextPtr pRenderContext( materials );
pRenderContext->Flush();
UpdateRefractTexture();
IMaterial *pMat = materials->FindMaterial( "effects/strider_pinch_dudv", TEXTURE_GROUP_CLIENT_EFFECTS );
float refract = m_FXCoreAlpha.Interp( gpGlobals->curtime );
float scale = m_FXCoreScale.Interp( gpGlobals->curtime );
IMaterialVar *pVar = pMat->FindVar( "$refractamount", NULL );
pVar->SetFloatValue( refract );
pRenderContext->Bind( pMat, (IClientRenderable*)this );
float sin1 = sinf( gpGlobals->curtime * 10 );
float sin2 = sinf( gpGlobals->curtime );
float scaleY = ( sin1 * sin2 ) * 32.0f;
float scaleX = (sin2 * sin2) * 32.0f;
// FIXME: The ball needs to sort properly at all times
static color32 white = {255,255,255,255};
DrawSpriteTangentSpace( GetRenderOrigin() + ( CurrentViewForward() * 128.0f ), scale+scaleX, scale+scaleY, white );
return 1;
}
//-----------------------------------------------------------------------------
// Purpose: Returns the bounds relative to the origin (render bounds)
//-----------------------------------------------------------------------------
void C_HopwireExplosion::GetRenderBounds( Vector& mins, Vector& maxs )
{
float scale = m_FXCoreScale.Interp( gpGlobals->curtime );
mins.Init( -scale, -scale, -scale );
maxs.Init( scale, scale, scale );
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void C_HopwireExplosion::StartExplosion( void )
{
m_FXCoreScale.Init( 300.0f, 500.0f, 2.0f, INTERP_SPLINE );
m_FXCoreAlpha.Init( 0.0f, 0.1f, 1.5f, INTERP_SPLINE );
// Particle timer
m_ParticleTimer.Init( 60 );
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void C_HopwireExplosion::StopExplosion( void )
{
m_FXCoreAlpha.InitFromCurrent( 0.0f, 1.0f, INTERP_SPLINE );
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void C_HopwireExplosion::StartPreExplosion( void )
{
}
//-----------------------------------------------------------------------------
// Hopwire client class
//-----------------------------------------------------------------------------
class C_GrenadeHopwire : public C_BaseGrenade
{
DECLARE_CLASS( C_GrenadeHopwire, C_BaseGrenade );
DECLARE_CLIENTCLASS();
public:
C_GrenadeHopwire( void );
virtual int DrawModel( int flags );
virtual void OnDataChanged( DataUpdateType_t updateType );
virtual void ReceiveMessage( int classID, bf_read &msg );
private:
C_HopwireExplosion m_ExplosionEffect; // Explosion effect information and drawing
};
IMPLEMENT_CLIENTCLASS_DT( C_GrenadeHopwire, DT_GrenadeHopwire, CGrenadeHopwire )
END_RECV_TABLE()
#define HOPWIRE_START_EXPLOSION 0
#define HOPWIRE_STOP_EXPLOSION 1
#define HOPWIRE_START_PRE_EXPLOSION 2
//-----------------------------------------------------------------------------
// Constructor
//-----------------------------------------------------------------------------
C_GrenadeHopwire::C_GrenadeHopwire( void )
{
m_ExplosionEffect.SetActive( false );
}
//-----------------------------------------------------------------------------
// Purpose: Receive messages from the server
// Input : classID - class to receive the message
// &msg - message in question
//-----------------------------------------------------------------------------
void C_GrenadeHopwire::ReceiveMessage( int classID, bf_read &msg )
{
if ( classID != GetClientClass()->m_ClassID )
{
// Message is for subclass
BaseClass::ReceiveMessage( classID, msg );
return;
}
int messageType = msg.ReadByte();
switch( messageType )
{
case HOPWIRE_START_EXPLOSION:
{
m_ExplosionEffect.SetActive();
m_ExplosionEffect.SetOwner( this );
m_ExplosionEffect.StartExplosion();
}
break;
case HOPWIRE_STOP_EXPLOSION:
{
m_ExplosionEffect.StopExplosion();
}
break;
default:
break;
}
}
//-----------------------------------------------------------------------------
// Purpose:
// Input : updateType -
//-----------------------------------------------------------------------------
void C_GrenadeHopwire::OnDataChanged( DataUpdateType_t updateType )
{
BaseClass::OnDataChanged( updateType );
m_ExplosionEffect.Update();
}
//-----------------------------------------------------------------------------
// Purpose:
// Input : flags -
//-----------------------------------------------------------------------------
int C_GrenadeHopwire::DrawModel( int flags )
{
if ( m_ExplosionEffect.IsActive() )
return 1;
return BaseClass::DrawModel( flags );
}
@@ -0,0 +1,464 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Episodic screen-space effects
//
#include "cbase.h"
#include "ScreenSpaceEffects.h"
#include "rendertexture.h"
#include "materialsystem/imaterialsystemhardwareconfig.h"
#include "materialsystem/imaterialsystem.h"
#include "materialsystem/imaterialvar.h"
#include "cdll_client_int.h"
#include "materialsystem/itexture.h"
#include "KeyValues.h"
#include "clienteffectprecachesystem.h"
#include "episodic_screenspaceeffects.h"
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
#ifdef _X360
#define STUN_TEXTURE "_rt_FullFrameFB2"
#else
#define STUN_TEXTURE "_rt_WaterRefraction"
#endif
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CStunEffect::Init( void )
{
m_flDuration = 0.0f;
m_flFinishTime = 0.0f;
m_bUpdateView = true;
KeyValues *pVMTKeyValues = new KeyValues( "UnlitGeneric" );
pVMTKeyValues->SetString( "$basetexture", STUN_TEXTURE );
m_EffectMaterial.Init( "__stuneffect", TEXTURE_GROUP_CLIENT_EFFECTS, pVMTKeyValues );
m_StunTexture.Init( STUN_TEXTURE, TEXTURE_GROUP_CLIENT_EFFECTS );
}
void CStunEffect::Shutdown( void )
{
m_EffectMaterial.Shutdown();
m_StunTexture.Shutdown();
}
//------------------------------------------------------------------------------
// Purpose: Pick up changes in our parameters
//------------------------------------------------------------------------------
void CStunEffect::SetParameters( KeyValues *params )
{
if( params->FindKey( "duration" ) )
{
m_flDuration = params->GetFloat( "duration" );
m_flFinishTime = gpGlobals->curtime + m_flDuration;
m_bUpdateView = true;
}
}
//-----------------------------------------------------------------------------
// Purpose: Render the effect
//-----------------------------------------------------------------------------
void CStunEffect::Render( int x, int y, int w, int h )
{
// Make sure we're ready to play this effect
if ( m_flFinishTime < gpGlobals->curtime )
return;
CMatRenderContextPtr pRenderContext( materials );
// Set ourselves to the proper rendermode
pRenderContext->MatrixMode( MATERIAL_VIEW );
pRenderContext->PushMatrix();
pRenderContext->LoadIdentity();
pRenderContext->MatrixMode( MATERIAL_PROJECTION );
pRenderContext->PushMatrix();
pRenderContext->LoadIdentity();
// Draw the texture if we're using it
if ( m_bUpdateView )
{
// Save off this pass
Rect_t srcRect;
srcRect.x = x;
srcRect.y = y;
srcRect.width = w;
srcRect.height = h;
pRenderContext->CopyRenderTargetToTextureEx( m_StunTexture, 0, &srcRect, NULL );
m_bUpdateView = false;
}
float flEffectPerc = ( m_flFinishTime - gpGlobals->curtime ) / m_flDuration;
float viewOffs = ( flEffectPerc * 32.0f ) * ( cos( gpGlobals->curtime * 40.0f ) * sin( gpGlobals->curtime * 17.0f ) );
float vX = x + viewOffs;
if ( g_pMaterialSystemHardwareConfig->GetDXSupportLevel() >= 80 )
{
if ( g_pMaterialSystemHardwareConfig->GetHDRType() == HDR_TYPE_NONE )
{
m_EffectMaterial->ColorModulate( 1.0f, 1.0f, 1.0f );
}
else
{
// This is a stupid fix, but I don't have time to do a cleaner implementation. Since
// the introblur.vmt material uses unlit generic, it will tone map, so I need to undo the tone mapping
// using color modulate. The proper fix would be to use a different material type that
// supports alpha blending but not tone mapping, which I don't think exists. Whatever. This works when
// the tone mapping scalar is less than 1.0, which it is in the cases it's used in game.
float flUnTonemap = pow( 1.0f / pRenderContext->GetToneMappingScaleLinear().x, 1.0f / 2.2f );
m_EffectMaterial->ColorModulate( flUnTonemap, flUnTonemap, flUnTonemap );
}
// Set alpha blend value
float flOverlayAlpha = clamp( ( 150.0f / 255.0f ) * flEffectPerc, 0.0f, 1.0f );
m_EffectMaterial->AlphaModulate( flOverlayAlpha );
// Draw full screen alpha-blended quad
pRenderContext->DrawScreenSpaceRectangle( m_EffectMaterial, 0, 0, w, h,
vX, 0, (m_StunTexture->GetActualWidth()-1)+vX, (m_StunTexture->GetActualHeight()-1),
m_StunTexture->GetActualWidth(), m_StunTexture->GetActualHeight() );
}
// Save off this pass
Rect_t srcRect;
srcRect.x = x;
srcRect.y = y;
srcRect.width = w;
srcRect.height = h;
pRenderContext->CopyRenderTargetToTextureEx( m_StunTexture, 0, &srcRect, NULL );
// Restore our state
pRenderContext->MatrixMode( MATERIAL_VIEW );
pRenderContext->PopMatrix();
pRenderContext->MatrixMode( MATERIAL_PROJECTION );
pRenderContext->PopMatrix();
}
// ================================================================================================================
//
// Ep 1. Intro blur
//
// ================================================================================================================
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CEP1IntroEffect::Init( void )
{
m_flDuration = 0.0f;
m_flFinishTime = 0.0f;
m_bUpdateView = true;
m_bFadeOut = false;
KeyValues *pVMTKeyValues = new KeyValues( "UnlitGeneric" );
pVMTKeyValues->SetString( "$basetexture", STUN_TEXTURE );
m_EffectMaterial.Init( "__ep1introeffect", TEXTURE_GROUP_CLIENT_EFFECTS, pVMTKeyValues );
m_StunTexture.Init( STUN_TEXTURE, TEXTURE_GROUP_CLIENT_EFFECTS );
}
void CEP1IntroEffect::Shutdown( void )
{
m_EffectMaterial.Shutdown();
m_StunTexture.Shutdown();
}
//------------------------------------------------------------------------------
// Purpose: Pick up changes in our parameters
//------------------------------------------------------------------------------
void CEP1IntroEffect::SetParameters( KeyValues *params )
{
if( params->FindKey( "duration" ) )
{
m_flDuration = params->GetFloat( "duration" );
m_flFinishTime = gpGlobals->curtime + m_flDuration;
}
if( params->FindKey( "fadeout" ) )
{
m_bFadeOut = ( params->GetInt( "fadeout" ) == 1 );
}
}
//-----------------------------------------------------------------------------
// Purpose: Get the alpha value depending on various factors and time
//-----------------------------------------------------------------------------
inline unsigned char CEP1IntroEffect::GetFadeAlpha( void )
{
// Find our percentage between fully "on" and "off" in the pulse range
float flEffectPerc = ( m_flDuration == 0.0f ) ? 0.0f : ( m_flFinishTime - gpGlobals->curtime ) / m_flDuration;
flEffectPerc = clamp( flEffectPerc, 0.0f, 1.0f );
if ( m_bFadeOut )
{
// HDR requires us to be more subtle, or we get uber-brightening
if ( g_pMaterialSystemHardwareConfig->GetHDRType() != HDR_TYPE_NONE )
return (unsigned char) clamp( 50.0f * flEffectPerc, 0.0f, 50.0f );
// Non-HDR
return (unsigned char) clamp( 64.0f * flEffectPerc, 0.0f, 64.0f );
}
else
{
// HDR requires us to be more subtle, or we get uber-brightening
if ( g_pMaterialSystemHardwareConfig->GetHDRType() != HDR_TYPE_NONE )
return (unsigned char) clamp( 64.0f * flEffectPerc, 50.0f, 64.0f );
// Non-HDR
return (unsigned char) clamp( 128.0f * flEffectPerc, 64.0f, 128.0f );
}
}
//-----------------------------------------------------------------------------
// Purpose: Render the effect
//-----------------------------------------------------------------------------
void CEP1IntroEffect::Render( int x, int y, int w, int h )
{
if ( ( m_flFinishTime == 0 ) || ( IsEnabled() == false ) )
return;
CMatRenderContextPtr pRenderContext( materials );
// Set ourselves to the proper rendermode
pRenderContext->MatrixMode( MATERIAL_VIEW );
pRenderContext->PushMatrix();
pRenderContext->LoadIdentity();
pRenderContext->MatrixMode( MATERIAL_PROJECTION );
pRenderContext->PushMatrix();
pRenderContext->LoadIdentity();
// Draw the texture if we're using it
if ( m_bUpdateView )
{
// Save off this pass
Rect_t srcRect;
srcRect.x = x;
srcRect.y = y;
srcRect.width = w;
srcRect.height = h;
pRenderContext->CopyRenderTargetToTextureEx( m_StunTexture, 0, &srcRect, NULL );
m_bUpdateView = false;
}
byte overlaycolor[4] = { 255, 255, 255, 0 };
// Get our fade value depending on our fade duration
overlaycolor[3] = GetFadeAlpha();
if ( g_pMaterialSystemHardwareConfig->UsesSRGBCorrectBlending() )
{
// For DX10 cards, alpha blending happens in linear space, so try to adjust by hacking alpha to 50%
overlaycolor[3] *= 0.7f;
}
// Disable overself if we're done fading out
if ( m_bFadeOut && overlaycolor[3] == 0 )
{
// Takes effect next frame (we don't want to hose our matrix stacks here)
g_pScreenSpaceEffects->DisableScreenSpaceEffect( "episodic_intro" );
m_bUpdateView = true;
}
// Calculate some wavey noise to jitter the view by
float vX = 2.0f * -fabs( cosf( gpGlobals->curtime ) * cosf( gpGlobals->curtime * 6.0 ) );
float vY = 2.0f * cosf( gpGlobals->curtime ) * cosf( gpGlobals->curtime * 5.0 );
// Scale percentage
float flScalePerc = 0.02f + ( 0.01f * cosf( gpGlobals->curtime * 2.0f ) * cosf( gpGlobals->curtime * 0.5f ) );
// Scaled offsets for the UVs (as texels)
float flUOffset = ( m_StunTexture->GetActualWidth() - 1 ) * flScalePerc * 0.5f;
float flVOffset = ( m_StunTexture->GetActualHeight() - 1 ) * flScalePerc * 0.5f;
// New UVs with scaling offsets
float flU1 = flUOffset;
float flU2 = ( m_StunTexture->GetActualWidth() - 1 ) - flUOffset;
float flV1 = flVOffset;
float flV2 = ( m_StunTexture->GetActualHeight() - 1 ) - flVOffset;
// Draw the "zoomed" overlay
pRenderContext->DrawScreenSpaceRectangle( m_EffectMaterial, vX, vY, w, h,
flU1, flV1,
flU2, flV2,
m_StunTexture->GetActualWidth(), m_StunTexture->GetActualHeight() );
render->ViewDrawFade( overlaycolor, m_EffectMaterial );
// Save off this pass
Rect_t srcRect;
srcRect.x = x;
srcRect.y = y;
srcRect.width = w;
srcRect.height = h;
pRenderContext->CopyRenderTargetToTextureEx( m_StunTexture, 0, &srcRect, NULL );
// Restore our state
pRenderContext->MatrixMode( MATERIAL_VIEW );
pRenderContext->PopMatrix();
pRenderContext->MatrixMode( MATERIAL_PROJECTION );
pRenderContext->PopMatrix();
}
// ================================================================================================================
//
// Ep 2. Groggy-player view
//
// ================================================================================================================
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CEP2StunEffect::Init( void )
{
m_flDuration = 0.0f;
m_flFinishTime = 0.0f;
m_bUpdateView = true;
m_bFadeOut = false;
KeyValues *pVMTKeyValues = new KeyValues( "UnlitGeneric" );
pVMTKeyValues->SetString( "$basetexture", STUN_TEXTURE );
m_EffectMaterial.Init( "__ep2stuneffect", TEXTURE_GROUP_CLIENT_EFFECTS, pVMTKeyValues );
m_StunTexture.Init( STUN_TEXTURE, TEXTURE_GROUP_CLIENT_EFFECTS );
}
void CEP2StunEffect::Shutdown( void )
{
m_EffectMaterial.Shutdown();
m_StunTexture.Shutdown();
}
//------------------------------------------------------------------------------
// Purpose: Pick up changes in our parameters
//------------------------------------------------------------------------------
void CEP2StunEffect::SetParameters( KeyValues *params )
{
if( params->FindKey( "duration" ) )
{
m_flDuration = params->GetFloat( "duration" );
m_flFinishTime = gpGlobals->curtime + m_flDuration;
}
if( params->FindKey( "fadeout" ) )
{
m_bFadeOut = ( params->GetInt( "fadeout" ) == 1 );
}
}
//-----------------------------------------------------------------------------
// Purpose: Get the alpha value depending on various factors and time
//-----------------------------------------------------------------------------
inline unsigned char CEP2StunEffect::GetFadeAlpha( void )
{
// Find our percentage between fully "on" and "off" in the pulse range
float flEffectPerc = ( m_flDuration == 0.0f ) ? 0.0f : ( m_flFinishTime - gpGlobals->curtime ) / m_flDuration;
flEffectPerc = clamp( flEffectPerc, 0.0f, 1.0f );
if ( m_bFadeOut )
{
// HDR requires us to be more subtle, or we get uber-brightening
if ( g_pMaterialSystemHardwareConfig->GetHDRType() != HDR_TYPE_NONE )
return (unsigned char) clamp( 50.0f * flEffectPerc, 0.0f, 50.0f );
// Non-HDR
return (unsigned char) clamp( 64.0f * flEffectPerc, 0.0f, 64.0f );
}
else
{
// HDR requires us to be more subtle, or we get uber-brightening
if ( g_pMaterialSystemHardwareConfig->GetHDRType() != HDR_TYPE_NONE )
return (unsigned char) clamp( 164.0f * flEffectPerc, 128.0f, 164.0f );
// Non-HDR
return (unsigned char) clamp( 164.0f * flEffectPerc, 128.0f, 164.0f );
}
}
//-----------------------------------------------------------------------------
// Purpose: Render the effect
//-----------------------------------------------------------------------------
void CEP2StunEffect::Render( int x, int y, int w, int h )
{
if ( ( m_flFinishTime == 0 ) || ( IsEnabled() == false ) )
return;
CMatRenderContextPtr pRenderContext( materials );
// Set ourselves to the proper rendermode
pRenderContext->MatrixMode( MATERIAL_VIEW );
pRenderContext->PushMatrix();
pRenderContext->LoadIdentity();
pRenderContext->MatrixMode( MATERIAL_PROJECTION );
pRenderContext->PushMatrix();
pRenderContext->LoadIdentity();
if ( m_bUpdateView )
{
// Save off this pass
Rect_t srcRect;
srcRect.x = x;
srcRect.y = y;
srcRect.width = w;
srcRect.height = h;
pRenderContext->CopyRenderTargetToTextureEx( m_StunTexture, 0, &srcRect, NULL );
m_bUpdateView = false;
}
byte overlaycolor[4] = { 255, 255, 255, 0 };
// Get our fade value depending on our fade duration
overlaycolor[3] = GetFadeAlpha();
// Disable overself if we're done fading out
if ( m_bFadeOut && overlaycolor[3] == 0 )
{
// Takes effect next frame (we don't want to hose our matrix stacks here)
g_pScreenSpaceEffects->DisableScreenSpaceEffect( "ep2_groggy" );
m_bUpdateView = true;
}
// Calculate some wavey noise to jitter the view by
float vX = 4.0f * cosf( gpGlobals->curtime ) * cosf( gpGlobals->curtime * 6.0 );
float vY = 2.0f * cosf( gpGlobals->curtime ) * cosf( gpGlobals->curtime * 5.0 );
float flBaseScale = 0.2f + 0.005f * sinf( gpGlobals->curtime * 4.0f );
// Scale percentage
float flScalePerc = flBaseScale + ( 0.01f * cosf( gpGlobals->curtime * 2.0f ) * cosf( gpGlobals->curtime * 0.5f ) );
// Scaled offsets for the UVs (as texels)
float flUOffset = ( m_StunTexture->GetActualWidth() - 1 ) * flScalePerc * 0.5f;
float flVOffset = ( m_StunTexture->GetActualHeight() - 1 ) * flScalePerc * 0.5f;
// New UVs with scaling offsets
float flU1 = flUOffset;
float flU2 = ( m_StunTexture->GetActualWidth() - 1 ) - flUOffset;
float flV1 = flVOffset;
float flV2 = ( m_StunTexture->GetActualHeight() - 1 ) - flVOffset;
// Draw the "zoomed" overlay
pRenderContext->DrawScreenSpaceRectangle( m_EffectMaterial, vX, vY, w, h,
flU1, flV1,
flU2, flV2,
m_StunTexture->GetActualWidth(), m_StunTexture->GetActualHeight() );
render->ViewDrawFade( overlaycolor, m_EffectMaterial );
// Save off this pass
Rect_t srcRect;
srcRect.x = x;
srcRect.y = y;
srcRect.width = w;
srcRect.height = h;
pRenderContext->CopyRenderTargetToTextureEx( m_StunTexture, 0, &srcRect, NULL );
// Restore our state
pRenderContext->MatrixMode( MATERIAL_VIEW );
pRenderContext->PopMatrix();
pRenderContext->MatrixMode( MATERIAL_PROJECTION );
pRenderContext->PopMatrix();
}
@@ -0,0 +1,119 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
//=============================================================================
#ifndef EPISODIC_SCREENSPACEEFFECTS_H
#define EPISODIC_SCREENSPACEEFFECTS_H
#ifdef _WIN32
#pragma once
#endif
#include "ScreenSpaceEffects.h"
class CStunEffect : public IScreenSpaceEffect
{
public:
CStunEffect( void ) :
m_flDuration( 0.0f ),
m_flFinishTime( 0.0f ),
m_bUpdateView( true ) {}
virtual void Init( void );
virtual void Shutdown( void );
virtual void SetParameters( KeyValues *params );
virtual void Enable( bool bEnable ) {};
virtual bool IsEnabled( ) { return true; }
virtual void Render( int x, int y, int w, int h );
private:
CTextureReference m_StunTexture;
CMaterialReference m_EffectMaterial;
float m_flDuration;
float m_flFinishTime;
bool m_bUpdateView;
};
ADD_SCREENSPACE_EFFECT( CStunEffect, episodic_stun );
//
// EP1 Intro Blur
//
class CEP1IntroEffect : public IScreenSpaceEffect
{
public:
CEP1IntroEffect( void ) :
m_flDuration( 0.0f ),
m_flFinishTime( 0.0f ),
m_bUpdateView( true ),
m_bEnabled( false ),
m_bFadeOut( false ) {}
virtual void Init( void );
virtual void Shutdown( void );
virtual void SetParameters( KeyValues *params );
virtual void Enable( bool bEnable ) { m_bEnabled = bEnable; }
virtual bool IsEnabled( ) { return m_bEnabled; }
virtual void Render( int x, int y, int w, int h );
private:
inline unsigned char GetFadeAlpha( void );
CTextureReference m_StunTexture;
CMaterialReference m_EffectMaterial;
float m_flDuration;
float m_flFinishTime;
bool m_bUpdateView;
bool m_bEnabled;
bool m_bFadeOut;
};
ADD_SCREENSPACE_EFFECT( CEP1IntroEffect, episodic_intro );
//
// EP2 Player Stunned Effect
//
//
// EP1 Intro Blur
//
class CEP2StunEffect : public IScreenSpaceEffect
{
public:
CEP2StunEffect( void ) :
m_flDuration( 0.0f ),
m_flFinishTime( 0.0f ),
m_bUpdateView( true ),
m_bEnabled( false ),
m_bFadeOut( false ) {}
virtual void Init( void );
virtual void Shutdown( void );
virtual void SetParameters( KeyValues *params );
virtual void Enable( bool bEnable ) { m_bEnabled = bEnable; }
virtual bool IsEnabled( ) { return m_bEnabled; }
virtual void Render( int x, int y, int w, int h );
private:
inline unsigned char GetFadeAlpha( void );
CTextureReference m_StunTexture;
CMaterialReference m_EffectMaterial;
float m_flDuration;
float m_flFinishTime;
bool m_bUpdateView;
bool m_bEnabled;
bool m_bFadeOut;
};
ADD_SCREENSPACE_EFFECT( CEP2StunEffect, ep2_groggy );
#endif // EPISODIC_SCREENSPACEEFFECTS_H
@@ -0,0 +1,225 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
// Purpose:
//
// $NoKeywords: $
//=====================================================================================//
#include "cbase.h"
#include "proxyentity.h"
#include "materialsystem/imaterial.h"
#include "materialsystem/imaterialvar.h"
#include "debugoverlay_shared.h"
// memdbgon must be the last include file in a .cpp file!!!
#include "tier0/memdbgon.h"
class C_FleshEffectTarget;
void AddFleshProxyTarget( C_FleshEffectTarget *pTarget );
void RemoveFleshProxy( C_FleshEffectTarget *pTarget );
//=============================================================================
//
// Flesh effect target (used for orchestrating the "Invisible Alyx" moment
//
//=============================================================================
class C_FleshEffectTarget : public C_BaseEntity
{
DECLARE_CLASS( C_FleshEffectTarget, C_BaseEntity );
public:
float GetRadius( void )
{
if ( m_flScaleTime <= 0.0f )
return m_flRadius;
float dt = ( gpGlobals->curtime - m_flScaleStartTime );
if ( dt >= m_flScaleTime )
return m_flRadius;
return SimpleSplineRemapVal( ( dt / m_flScaleTime ), 0.0f, 1.0f, m_flStartRadius, m_flRadius );
}
virtual void Release( void )
{
// Remove us from the list of targets
RemoveFleshProxy( this );
}
virtual void OnDataChanged( DataUpdateType_t updateType )
{
BaseClass::OnDataChanged( updateType );
if ( updateType == DATA_UPDATE_CREATED )
{
// Add us to the list of flesh proxy targets
AddFleshProxyTarget( this );
}
}
float m_flRadius;
float m_flStartRadius;
float m_flScaleStartTime;
float m_flScaleTime;
DECLARE_CLIENTCLASS();
};
void RecvProxy_FleshEffect_Radius( const CRecvProxyData *pData, void *pStruct, void *pOut )
{
C_FleshEffectTarget *pTarget = (C_FleshEffectTarget *) pStruct;
float flRadius = pData->m_Value.m_Float;
//If changed, update our internal information
if ( pTarget->m_flRadius != flRadius )
{
pTarget->m_flStartRadius = pTarget->m_flRadius;
pTarget->m_flScaleStartTime = gpGlobals->curtime;
}
pTarget->m_flRadius = flRadius;
}
IMPLEMENT_CLIENTCLASS_DT( C_FleshEffectTarget, DT_FleshEffectTarget, CFleshEffectTarget )
RecvPropFloat( RECVINFO(m_flRadius), 0, RecvProxy_FleshEffect_Radius ),
RecvPropFloat( RECVINFO(m_flScaleTime) ),
END_RECV_TABLE()
CUtlVector< C_FleshEffectTarget * > g_FleshProxyTargets;
void AddFleshProxyTarget( C_FleshEffectTarget *pTarget )
{
// Take it!
g_FleshProxyTargets.AddToTail( pTarget );
}
void RemoveFleshProxy( C_FleshEffectTarget *pTarget )
{
int nIndex = g_FleshProxyTargets.Find( pTarget );
if ( nIndex != g_FleshProxyTargets.InvalidIndex() )
{
g_FleshProxyTargets.Remove( nIndex );
}
}
// $sineVar : name of variable that controls the FleshInterior level (float)
class CFleshInteriorMaterialProxy : public CEntityMaterialProxy
{
public:
CFleshInteriorMaterialProxy();
virtual ~CFleshInteriorMaterialProxy();
virtual bool Init( IMaterial *pMaterial, KeyValues *pKeyValues );
virtual void OnBind( C_BaseEntity *pEntity );
virtual IMaterial *GetMaterial();
private:
IMaterialVar *m_pMaterialParamFleshEffectCenterRadius1;
IMaterialVar *m_pMaterialParamFleshEffectCenterRadius2;
IMaterialVar *m_pMaterialParamFleshEffectCenterRadius3;
IMaterialVar *m_pMaterialParamFleshEffectCenterRadius4;
IMaterialVar *m_pMaterialParamFleshGlobalOpacity;
IMaterialVar *m_pMaterialParamFleshSubsurfaceTint;
};
CFleshInteriorMaterialProxy::CFleshInteriorMaterialProxy()
{
m_pMaterialParamFleshEffectCenterRadius1 = NULL;
m_pMaterialParamFleshEffectCenterRadius2 = NULL;
m_pMaterialParamFleshEffectCenterRadius3 = NULL;
m_pMaterialParamFleshEffectCenterRadius4 = NULL;
m_pMaterialParamFleshGlobalOpacity = NULL;
m_pMaterialParamFleshSubsurfaceTint = NULL;
}
CFleshInteriorMaterialProxy::~CFleshInteriorMaterialProxy()
{
// Do nothing
}
bool CFleshInteriorMaterialProxy::Init( IMaterial *pMaterial, KeyValues *pKeyValues )
{
bool bFoundVar = false;
m_pMaterialParamFleshEffectCenterRadius1 = pMaterial->FindVar( "$FleshEffectCenterRadius1", &bFoundVar, false );
if ( bFoundVar == false)
return false;
m_pMaterialParamFleshEffectCenterRadius2 = pMaterial->FindVar( "$FleshEffectCenterRadius2", &bFoundVar, false );
if ( bFoundVar == false)
return false;
m_pMaterialParamFleshEffectCenterRadius3 = pMaterial->FindVar( "$FleshEffectCenterRadius3", &bFoundVar, false );
if ( bFoundVar == false)
return false;
m_pMaterialParamFleshEffectCenterRadius4 = pMaterial->FindVar( "$FleshEffectCenterRadius4", &bFoundVar, false );
if ( bFoundVar == false)
return false;
m_pMaterialParamFleshGlobalOpacity = pMaterial->FindVar( "$FleshGlobalOpacity", &bFoundVar, false );
if ( bFoundVar == false)
return false;
m_pMaterialParamFleshSubsurfaceTint = pMaterial->FindVar( "$FleshSubsurfaceTint", &bFoundVar, false );
if ( bFoundVar == false)
return false;
return true;
}
void CFleshInteriorMaterialProxy::OnBind( C_BaseEntity *pEnt )
{
IMaterialVar *pParams[] =
{
m_pMaterialParamFleshEffectCenterRadius1,
m_pMaterialParamFleshEffectCenterRadius2,
m_pMaterialParamFleshEffectCenterRadius3,
m_pMaterialParamFleshEffectCenterRadius4
};
float vEffectCenterRadius[4];
for ( int i = 0; i < ARRAYSIZE( pParams ); i++ )
{
if ( i < g_FleshProxyTargets.Count() )
{
// Setup the target
if ( g_FleshProxyTargets[i]->IsAbsQueriesValid() == false )
continue;
Vector vecAbsOrigin = g_FleshProxyTargets[i]->GetAbsOrigin();
vEffectCenterRadius[0] = vecAbsOrigin.x;
vEffectCenterRadius[1] = vecAbsOrigin.y;
vEffectCenterRadius[2] = vecAbsOrigin.z;
vEffectCenterRadius[3] = g_FleshProxyTargets[i]->GetRadius();
}
else
{
// Clear the target
vEffectCenterRadius[0] = vEffectCenterRadius[1] = vEffectCenterRadius[2] = vEffectCenterRadius[3] = 0.0f;
}
// Set the value either way
pParams[i]->SetVecValue( vEffectCenterRadius, 4 );
}
// Subsurface texture. NOTE: This texture bleeds through the color of the flesh texture so expect
// to have to set this brighter than white to really see the subsurface texture glow through.
if ( m_pMaterialParamFleshSubsurfaceTint != NULL )
{
float vSubsurfaceTintColor[4] = { 0.0f, 0.0f, 0.0f, 0.0f };
// !!! Test code. REPLACE ME!
// vSubsurfaceTintColor[0] = vSubsurfaceTintColor[1] = vSubsurfaceTintColor[2] = sinf( gpGlobals->curtime * 3.0f ) + 1.0f; // * 0.5f + 0.5f;
m_pMaterialParamFleshSubsurfaceTint->SetVecValue( vSubsurfaceTintColor, 4 );
}
}
IMaterial *CFleshInteriorMaterialProxy::GetMaterial()
{
if ( m_pMaterialParamFleshEffectCenterRadius1 == NULL)
return NULL;
return m_pMaterialParamFleshEffectCenterRadius1->GetOwningMaterial();
}
EXPOSE_INTERFACE( CFleshInteriorMaterialProxy, IMaterialProxy, "FleshInterior" IMATERIAL_PROXY_INTERFACE_VERSION );