mirror of
https://github.com/nillerusr/source-engine.git
synced 2026-08-07 17:29:36 +00:00
1
This commit is contained in:
@@ -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. *
|
||||
******************************************************/
|
||||
@@ -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
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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] );
|
||||
}
|
||||
@@ -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 );
|
||||
@@ -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 );
|
||||
Reference in New Issue
Block a user