This commit is contained in:
2022-09-04 13:08:22 +03:00
parent 6849515d14
commit 1e58bd6836
369 changed files with 170930 additions and 0 deletions

View File

@@ -0,0 +1,41 @@
#ifndef IV_SHADEREDITOR_MRENDER
#define IV_SHADEREDITOR_MRENDER
#ifdef _WIN32
#pragma once
#endif // _WIN32
#ifdef SHADER_EDITOR_DLL
#include "../public/tier1/interface.h"
#else
#include "interface.h"
#include "ShaderEditor/ShaderEditorSystem.h"
#endif // NOT SHADER_EDITOR_DLL
class ISEditModelRender
{
public:
virtual bool LoadModel( const char *localPath ) = 0;
virtual void DestroyModel() = 0;
virtual void GetModelCenter( float *pFl3_ViewOffset ) = 0;
virtual int QuerySequences( char ***list ) = 0;
virtual void SetSequence( const char *name ) = 0;
virtual void ExecRender() = 0;
virtual void DoPostProc( int x, int y, int w, int h ) = 0;
virtual int MaterialPicker( char ***szMat ) = 0;
virtual void DestroyCharPtrList( char ***szList ) = 0;
};
#ifdef SHADER_EDITOR_DLL
extern ISEditModelRender *sEditMRender;
#else
class SEditModelRender;
extern SEditModelRender *sEditMRender;
#endif
#endif

View File

@@ -0,0 +1,128 @@
#ifndef IV_SHADEREDITOR
#define IV_SHADEREDITOR
#ifdef _WIN32
#pragma once
#endif // _WIN32
#define pFnClCallback( x ) void(* x )( float *pfl4 )
#define pFnClCallback_Declare( x ) void x( float *pfl4 )
#define pFnVrCallback( x ) void(* x )( bool * const pbOptions, int * const piOptions,\
float * const pflOptions, char ** const pszOptions )
#define pFnVrCallback_Declare( x ) void x( bool * const pbOptions, int * const piOptions,\
float * const pflOptions, char ** const pszOptions )
#ifndef PROCSHADER_DLL
#ifdef SHADER_EDITOR_DLL
#include "../public/tier1/interface.h"
#include "view_shared.h"
#else
#include "interface.h"
#include "ShaderEditor/ShaderEditorSystem.h"
#endif // NOT SHADER_EDITOR_DLL
enum SEDIT_SKYMASK_MODE
{
SKYMASK_OFF = 0,
SKYMASK_QUARTER, // render at 1/4 fb size where possible
SKYMASK_FULL, // render at full fb size
};
class CViewSetup_SEdit_Shared
{
public:
CViewSetup_SEdit_Shared()
{
Q_memset( this, 0, sizeof( CViewSetup_SEdit_Shared ) );
};
CViewSetup_SEdit_Shared( const CViewSetup &o )
{
x = o.x;
y = o.y;
width = o.width;
height = o.height;
fov = o.fov;
fovViewmodel = o.fovViewmodel;
origin = o.origin;
angles = o.angles;
zNear = o.zNear;
zFar = o.zFar;
zNearViewmodel = o.zNearViewmodel;
zFarViewmodel = o.zFarViewmodel;
m_flAspectRatio = o.m_flAspectRatio;
};
int x,y,width,height;
float fov,fovViewmodel;
Vector origin;
QAngle angles;
float zNear,zFar,zNearViewmodel,zFarViewmodel;
float m_flAspectRatio;
};
class IVShaderEditor : public IBaseInterface
{
public:
virtual bool Init( CreateInterfaceFn appSystemFactory, CGlobalVarsBase *pGlobals,
void *pSEditMRender,
bool bCreateEditor, bool bEnablePrimaryDebug, int iSkymaskMode ) = 0;
virtual void Shutdown() = 0;
virtual void PrecacheData() = 0;
// call before Init() to overwrite any paths, pass in NULL for the ones that shouldn't be overwritten
virtual void OverridePaths( const char *pszWorkingDirectory,
const char *pszCompilePath = NULL, // abs path to compiler binaries
const char *pszLocalCompilePath = NULL, // local path to compiler binaries, relative to shader source directory
const char *pszGamePath = NULL,
const char *pszCanvas = NULL, // path to canvas files
const char *pszShaderSource = NULL, // path to shader source files
const char *pszDumps = NULL, // path to shader configuration files
const char *pszUserFunctions = NULL, // path to custom function bodies
const char *pszEditorRoot = NULL ) = 0; // path to 'shadereditorui' home directory
// update the lib
virtual void OnFrame( float frametime ) = 0;
virtual void OnPreRender( void *viewsetup ) = 0;
virtual void OnSceneRender() = 0;
virtual void OnUpdateSkymask(bool bCombineMode, int x, int y, int w, int h) = 0;
virtual void OnPostRender( bool bUpdateFB ) = 0;
// data callbacks for hlsl constants
virtual void RegisterClientCallback( const char *name, pFnClCallback(callback), int numComponents ) = 0;
virtual void LockClientCallbacks() = 0;
// view render callbacks for post processing graphs
virtual void RegisterViewRenderCallback( const char *pszVrCName, pFnVrCallback(callback),
const char **pszBoolNames = NULL, const bool *pBoolDefaults = NULL, const int numBoolParams = 0,
const char **pszIntNames = NULL, const int *pIntDefaults = NULL, const int numIntParams = 0,
const char **pszFloatNames = NULL, const float *pFloatDefaults = NULL, const int numFloatParams = 0,
const char **pszStringNames = NULL, const char **pStringDefaults = NULL, const int numStringParams = 0 ) = 0;
virtual void LockViewRenderCallbacks() = 0;
// post processing effect manipulation (precached effects accessible)
// the index becomes invalid when editing the precache list
virtual int GetPPEIndex( const char *pszName ) = 0; // returns -1 when not found, case insensitive
virtual bool IsPPEEnabled( const int &index ) = 0;
virtual void SetPPEEnabled( const int &index, const bool &bEnabled ) = 0;
virtual IMaterial *GetPPEMaterial( const int &index, const char *pszNodeName ) = 0;
// Draws a PPE graph right now or adds it to the render queue (r_queued_post_processing!)
// Does not push a new RT but uses the current one
// If you have 'during scene' nodes, make sure to call it twice in the appropriate places
virtual void DrawPPEOnDemand( const int &index, const bool bInScene = false ) = 0;
};
#define SHADEREDIT_INTERFACE_VERSION "ShaderEditor005"
#ifdef SHADER_EDITOR_DLL
class ShaderEditorInterface;
extern ShaderEditorInterface *shaderEdit;
#else
extern IVShaderEditor *shaderEdit;
#endif // NOT SHADER_EDITOR_DLL
#endif // NOT PROCSHADER_DLL
#endif // NOT IV_SHADEREDITOR

View File

@@ -0,0 +1,424 @@
// ******************************************************
//
// Purpose:
// - Handles model rendering requests from the
// shader editor library
//
// ******************************************************
#include "cbase.h"
#include "vgui/iinput.h"
#include "vgui_controls/controls.h"
#include "ShaderEditor/SEdit_ModelRender.h"
#include "model_types.h"
#ifndef SOURCE_2006
#include "viewpostprocess.h"
#endif
#include "view.h"
#include "input.h"
#include "beamdraw.h"
#ifdef SOURCE_2006
void ScreenToWorld( int mousex, int mousey, float fov,
const Vector& vecRenderOrigin,
const QAngle& vecRenderAngles,
Vector& vecPickingRay )
{
float dx, dy;
float c_x, c_y;
float dist;
Vector vpn, vup, vright;
float scaled_fov = ScaleFOVByWidthRatio( fov, engine->GetScreenAspectRatio() * 0.75f );
c_x = ScreenWidth() / 2;
c_y = ScreenHeight() / 2;
dx = (float)mousex - c_x;
dy = c_y - (float)mousey;
float dist_denom = tan(M_PI * scaled_fov / 360.0f);
dist = c_x / dist_denom;
AngleVectors( vecRenderAngles, &vpn, &vright, &vup );
vecPickingRay = vpn * dist + vright * ( dx ) + vup * ( dy );
VectorNormalize( vecPickingRay );
}
#else
extern void ScreenToWorld( int mousex, int mousey, float fov,
const Vector& vecRenderOrigin,
const QAngle& vecRenderAngles,
Vector& vecPickingRay );
#endif
SEditModelRender __g_ShaderEditorMReder( "ShEditMRender" );
SEditModelRender *sEditMRender = &__g_ShaderEditorMReder;
SEditModelRender::SEditModelRender( char const *name ) : CAutoGameSystemPerFrame( name )
{
pModelInstance = NULL;
m_iNumPoseParams = 0;
DestroyModel();
}
SEditModelRender::~SEditModelRender()
{
DestroyModel();
}
bool SEditModelRender::Init()
{
return true;
}
void SEditModelRender::Shutdown()
{
}
void SEditModelRender::Update( float frametime )
{
if ( !IsModelReady() )
return;
pModelInstance->StudioFrameAdvance();
if ( pModelInstance->GetCycle() >= 1.0f )
pModelInstance->SetCycle( pModelInstance->GetCycle() - 1.0f );
}
void SEditModelRender::LevelInitPostEntity()
{
ResetModel();
}
void SEditModelRender::LevelShutdownPostEntity()
{
ResetModel();
}
void SEditModelRender::ResetModel()
{
if ( !IsModelReady() )
return;
pModelInstance->m_flAnimTime = gpGlobals->curtime;
pModelInstance->m_flOldAnimTime = gpGlobals->curtime;
}
bool SEditModelRender::IsModelReady()
{
if ( !pModelInstance )
return false;
bool bValid = !!pModelInstance->GetModel();
if ( bValid && Q_strlen( m_szModelPath ) )
{
const model_t *pMdl = modelinfo ? modelinfo->FindOrLoadModel( m_szModelPath ) : NULL;
if ( pMdl )
pModelInstance->SetModelPointer( pMdl );
bValid = !!pMdl;
}
if ( !bValid )
DestroyModel();
return bValid;
}
bool SEditModelRender::LoadModel( const char *localPath )
{
DestroyModel();
const model_t *mdl = modelinfo->FindOrLoadModel( localPath );
if ( !mdl )
return false;
Q_strcpy( m_szModelPath, localPath );
C_BaseFlex *pEnt = new C_BaseFlex();
pEnt->InitializeAsClientEntity( NULL,
#if SWARM_DLL
false
#else
RENDER_GROUP_OPAQUE_ENTITY
#endif
);
MDLCACHE_CRITICAL_SECTION();
pEnt->SetModelPointer( mdl );
pEnt->Spawn();
pEnt->SetAbsAngles( vec3_angle );
pEnt->SetAbsOrigin( vec3_origin );
pEnt->AddEffects( EF_NODRAW | EF_NOINTERP );
pEnt->m_EntClientFlags |= ENTCLIENTFLAG_DONTUSEIK;
// leave it alone.
pEnt->RemoveFromLeafSystem();
cl_entitylist->RemoveEntity( pEnt->GetRefEHandle() );
pEnt->CollisionProp()->DestroyPartitionHandle();
CStudioHdr *pHdr = pEnt->GetModelPtr();
m_iNumPoseParams = pHdr ? pHdr->GetNumPoseParameters() : 0;
pModelInstance = pEnt;
return true;
}
void SEditModelRender::DestroyModel()
{
if ( pModelInstance )
pModelInstance->Remove();
pModelInstance = NULL;
m_szModelPath[0] = '\0';
m_iNumPoseParams = 0;
}
void SEditModelRender::GetModelCenter( float *pFl3_ViewOffset )
{
Q_memset( pFl3_ViewOffset, 0, sizeof(float) * 3 );
if ( IsModelReady() )
{
MDLCACHE_CRITICAL_SECTION();
if ( pModelInstance->GetModelPtr() )
{
const Vector &vecMin = pModelInstance->GetModelPtr()->hull_min();
const Vector &vecMax = pModelInstance->GetModelPtr()->hull_max();
Vector vecPos = ( vecMin + ( vecMax - vecMin ) * 0.5f );
if ( pFl3_ViewOffset )
Q_memcpy( pFl3_ViewOffset, vecPos.Base(), sizeof(float) * 3 );
}
}
}
void SEditModelRender::DestroyCharPtrList( char ***szList )
{
Assert( szList );
if ( *szList )
{
delete [] (**szList);
delete [] (*szList);
*szList = NULL;
}
}
int SequenceSort( mstudioseqdesc_t *const *seq1, mstudioseqdesc_t *const *seq2 )
{
return Q_stricmp( ( *seq1 )->pszLabel(), ( *seq2 )->pszLabel() );
}
int SEditModelRender::QuerySequences( char ***list )
{
if ( !IsModelReady() )
return 0;
MDLCACHE_CRITICAL_SECTION();
CStudioHdr *pHdr = pModelInstance->GetModelPtr();
if ( !pHdr )
return 0;
CUtlVector< mstudioseqdesc_t* >hSeqs;
for ( int i = 0; i < pHdr->GetNumSeq(); i++ )
if ( !( pHdr->pSeqdesc( i ).flags & STUDIO_HIDDEN ) )
hSeqs.AddToTail( &pHdr->pSeqdesc( i ) );
int numSequences = hSeqs.Count();
if ( !numSequences )
return 0;
hSeqs.Sort( SequenceSort );
CUtlVector< const char* >hNameList;
for ( int i = 0; i < numSequences; i++ )
{
const char *seqName = NULL;
const mstudioseqdesc_t &seqPtr = *hSeqs[ i ];
if ( seqPtr.pszLabel() )
seqName = seqPtr.pszLabel();
else
seqName = "Unknown Sequence";
hNameList.AddToTail( seqName );
}
*list = new char*[numSequences];
int iTotalLength = 0;
for ( int i = 0; i < numSequences; i++ )
iTotalLength += Q_strlen( hNameList[i] ) + 1;
**list = new char[ iTotalLength ];
int curpos = 0;
for ( int i = 0; i < numSequences; i++ )
{
int curLength = Q_strlen( hNameList[i] ) + 1;
(*list)[ i ] = **list + curpos;
Q_strcpy( (*list)[ i ], hNameList[i] );
curpos += curLength;
}
hNameList.Purge();
hSeqs.Purge();
return numSequences;
}
void SEditModelRender::SetSequence( const char *name )
{
if ( !IsModelReady() )
return;
MDLCACHE_CRITICAL_SECTION();
pModelInstance->ResetSequence( pModelInstance->LookupSequence( name ) );
}
void SEditModelRender::ExecRender()
{
if ( !IsModelReady() )
return;
MDLCACHE_CRITICAL_SECTION();
for ( int i = 0; i < m_iNumPoseParams; i++ )
pModelInstance->SetPoseParameter( i, 0 );
#if SWARM_DLL
RenderableInstance_t instance;
instance.m_nAlpha = 255;
#endif
pModelInstance->DrawModel( STUDIO_RENDER
#if SWARM_DLL
, instance
#endif
);
}
void SEditModelRender::DoPostProc( int x, int y, int w, int h )
{
#ifndef SOURCE_2006
if ( view && view->GetPlayerViewSetup()->m_bDoBloomAndToneMapping )
DoEnginePostProcessing( x, y, w, h, false, false );
#endif
}
int SEditModelRender::MaterialPicker( char ***szMat )
{
int mx, my;
#ifdef SOURCE_2006
vgui::input()->GetCursorPos( mx, my );
#else
vgui::input()->GetCursorPosition( mx, my );
#endif
Vector ray;
const CViewSetup *pViewSetup = view->GetPlayerViewSetup();
float ratio =engine->GetScreenAspectRatio(
#if SWARM_DLL
pViewSetup->width, pViewSetup->height
#endif
);
ratio = ( 1.0f / ratio ) * (4.0f/3.0f);
float flFov = ScaleFOVByWidthRatio( pViewSetup->fov, ratio );
ScreenToWorld( mx, my, flFov, pViewSetup->origin, pViewSetup->angles, ray );
Vector start = pViewSetup->origin;
Vector end = start + ray * MAX_TRACE_LENGTH;
trace_t tr;
C_BaseEntity *pIgnore = input->CAM_IsThirdPerson() ? NULL : C_BasePlayer::GetLocalPlayer();
UTIL_TraceLine( start, end, MASK_SOLID, pIgnore, COLLISION_GROUP_NONE, &tr );
if ( !tr.DidHit() )
return 0;
int numMaterials = 0;
IMaterial **MatList = NULL;
studiohdr_t *pSHdr = NULL;
if ( tr.DidHitWorld() )
{
if ( tr.hitbox == 0 )
{
Vector dummy;
IMaterial *pMat = engine->TraceLineMaterialAndLighting( start, end, dummy, dummy );
if ( pMat )
{
numMaterials = 1;
MatList = new IMaterial*[1];
MatList[0] = pMat;
}
}
else
{
ICollideable *prop = staticpropmgr->GetStaticPropByIndex( tr.hitbox - 1 );
if ( prop )
{
IClientRenderable *pRenderProp = prop->GetIClientUnknown()->GetClientRenderable();
if ( pRenderProp )
{
const model_t *pModel = pRenderProp->GetModel();
if ( pModel )
pSHdr = modelinfo->GetStudiomodel( pModel );
}
}
}
}
else if ( tr.m_pEnt )
{
const model_t *pModel = tr.m_pEnt->GetModel();
if ( pModel )
pSHdr = modelinfo->GetStudiomodel( pModel );
}
if ( pSHdr )
{
Assert( !numMaterials && !MatList );
numMaterials = pSHdr->numtextures;
const int numPaths = pSHdr->numcdtextures;
if ( numMaterials )
{
CUtlVector< IMaterial* >hValidMaterials;
for ( int i = 0; i < numMaterials; i++ )
{
mstudiotexture_t *pStudioTex = pSHdr->pTexture( i );
const char *matName = pStudioTex->pszName();
for ( int p = 0; p < numPaths; p++ )
{
char tmpPath[MAX_PATH];
Q_snprintf( tmpPath, MAX_PATH, "%s%s\0", pSHdr->pCdtexture( p ), matName );
Q_FixSlashes( tmpPath );
IMaterial *pTempMat = materials->FindMaterial( tmpPath, TEXTURE_GROUP_MODEL );
if ( !IsErrorMaterial( pTempMat ) )
{
hValidMaterials.AddToTail( pTempMat );
break;
}
}
}
numMaterials = hValidMaterials.Count();
if ( numMaterials )
{
MatList = new IMaterial*[ numMaterials ];
for ( int i = 0; i < numMaterials; i++ )
MatList[i] = hValidMaterials[i];
}
hValidMaterials.Purge();
}
}
*szMat = new char*[ numMaterials ];
int iTotalLength = 0;
for ( int i = 0; i < numMaterials; i++ )
iTotalLength += Q_strlen( MatList[i]->GetName() ) + 1;
**szMat = new char[ iTotalLength ];
int curpos = 0;
for ( int i = 0; i < numMaterials; i++ )
{
const char *pszName = MatList[i]->GetName();
int curLength = Q_strlen( pszName ) + 1;
(*szMat)[ i ] = **szMat + curpos;
Q_strcpy( (*szMat)[ i ], pszName );
curpos += curLength;
}
if ( MatList )
delete [] MatList;
return numMaterials;
}

View File

@@ -0,0 +1,48 @@
#ifndef SHEDITMRENDER_H
#define SHEDITMRENDER_H
#include "cbase.h"
#include "ShaderEditor/ISEdit_ModelRender.h"
class C_BaseFlex_OverrideLod;
class SEditModelRender : public ISEditModelRender, public CAutoGameSystemPerFrame
{
public:
SEditModelRender( char const *name );
~SEditModelRender();
// autogamesystem
virtual bool Init();
virtual void Shutdown();
virtual void Update( float frametime );
virtual void LevelInitPostEntity();
virtual void LevelShutdownPostEntity();
// interface
virtual bool LoadModel( const char *localPath );
virtual void DestroyModel();
virtual void GetModelCenter( float *pFl3_ViewOffset );
virtual int QuerySequences( char ***list );
virtual void SetSequence( const char *name );
virtual void ExecRender();
virtual void DoPostProc( int x, int y, int w, int h );
virtual int MaterialPicker( char ***szMat );
virtual void DestroyCharPtrList( char ***szList );
private:
bool IsModelReady();
void ResetModel();
C_BaseFlex *pModelInstance;
char m_szModelPath[MAX_PATH];
int m_iNumPoseParams;
};
#endif

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,59 @@
#ifndef SHEDITSYSTEM_H
#define SHEDITSYSTEM_H
#include "cbase.h"
#include "datacache/imdlcache.h"
#include "iviewrender.h"
#include "view_shared.h"
#include "viewrender.h"
class ShaderEditorHandler : public CAutoGameSystemPerFrame
{
public:
ShaderEditorHandler( char const *name );
~ShaderEditorHandler();
virtual bool Init();
virtual void Shutdown();
virtual void Update( float frametime );
virtual void PreRender();
virtual void PostRender();
#ifdef SOURCE_2006
void CustomViewRender( int *viewId, const VisibleFogVolumeInfo_t &fogVolumeInfo );
#else
void CustomViewRender( int *viewId, const VisibleFogVolumeInfo_t &fogVolumeInfo, const WaterRenderInfo_t &waterRenderInfo );
#endif
void CustomPostRender();
void UpdateSkymask(bool bCombineMode, int x, int y, int w, int h);
const bool IsReady();
int &GetViewIdForModify();
const VisibleFogVolumeInfo_t &GetFogVolumeInfo();
#ifndef SOURCE_2006
const WaterRenderInfo_t &GetWaterRenderInfo();
#endif
private:
bool m_bReady;
void RegisterCallbacks();
void PrepareCallbackData();
void RegisterViewRenderCallbacks();
int *m_piCurrentViewId;
VisibleFogVolumeInfo_t m_tFogVolumeInfo;
#ifndef SOURCE_2006
WaterRenderInfo_t m_tWaterRenderInfo;
#endif
};
extern ShaderEditorHandler *g_ShaderEditorSystem;
#endif

View File

@@ -0,0 +1,251 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose: Definition for client-side advisor.
//
//=====================================================================================//
#include "cbase.h"
// this file contains the definitions for the message ID constants (eg ADVISOR_MSG_START_BEAM etc)
#include "npc_advisor_shared.h"
#if NPC_ADVISOR_HAS_BEHAVIOR
#include "particles_simple.h"
#include "citadel_effects_shared.h"
#include "particles_attractor.h"
#include "clienteffectprecachesystem.h"
#include "c_te_effect_dispatch.h"
#include "c_ai_basenpc.h"
#include "dlight.h"
#include "iefx.h"
//-----------------------------------------------------------------------------
// Purpose: unpack a networked entity index into a basehandle.
//-----------------------------------------------------------------------------
inline C_BaseEntity *IndexToEntity( int eindex )
{
return ClientEntityList().GetBaseEntityFromHandle(ClientEntityList().EntIndexToHandle(eindex));
}
#define ADVISOR_ELIGHT_CVARS 1 // enable/disable tuning advisor elight with console variables
#if ADVISOR_ELIGHT_CVARS
ConVar advisor_elight_e("advisor_elight_e","3");
ConVar advisor_elight_rfeet("advisor_elight_rfeet","52");
#endif
/*! Client-side reflection of the advisor class.
*/
class C_NPC_Advisor : public C_AI_BaseNPC
{
DECLARE_CLASS( C_NPC_Advisor, C_AI_BaseNPC );
DECLARE_CLIENTCLASS();
public:
// Server to client message received
virtual void ReceiveMessage( int classID, bf_read &msg );
virtual void ClientThink( void );
private:
/*
// broken into its own function so I can move it if necesasry
void Initialize();
*/
// start/stop beam particle effect from me to a pelting object
void StartBeamFX( C_BaseEntity *pOnEntity );
void StopBeamFX( C_BaseEntity *pOnEntity );
void StartElight();
void StopElight();
int m_ElightKey; // test using an elight to make the escape sequence more visible. 0 is invalid.
};
IMPLEMENT_CLIENTCLASS_DT( C_NPC_Advisor, DT_NPC_Advisor, CNPC_Advisor )
END_RECV_TABLE()
// Server to client message received
void C_NPC_Advisor::ReceiveMessage( int classID, bf_read &msg )
{
if ( classID != GetClientClass()->m_ClassID )
{
// message is for subclass
BaseClass::ReceiveMessage( classID, msg );
return;
}
int messageType = msg.ReadByte();
switch( messageType )
{
case ADVISOR_MSG_START_BEAM:
{
int eindex = msg.ReadLong();
StartBeamFX(IndexToEntity(eindex));
}
break;
case ADVISOR_MSG_STOP_BEAM:
{
int eindex = msg.ReadLong();
StopBeamFX(IndexToEntity(eindex));
}
break;
case ADVISOR_MSG_STOP_ALL_BEAMS:
{
ParticleProp()->StopEmission();
}
break;
case ADVISOR_MSG_START_ELIGHT:
{
StartElight();
}
break;
case ADVISOR_MSG_STOP_ELIGHT:
{
StopElight();
}
break;
default:
AssertMsg1( false, "Received unknown message %d", messageType);
}
}
/// only use of the clientthink on the advisor is to update the elight
void C_NPC_Advisor::ClientThink( void )
{
// if the elight has gone away, bail out
if (m_ElightKey == 0)
{
SetNextClientThink( CLIENT_THINK_NEVER );
return;
}
// get the elight
dlight_t * el = effects->GetElightByKey(m_ElightKey);
if (!el)
{
// the elight has been invalidated. bail out.
m_ElightKey = 0;
SetNextClientThink( CLIENT_THINK_NEVER );
return;
}
else
{
el->origin = WorldSpaceCenter();
#if ADVISOR_ELIGHT_CVARS
el->color.exponent = advisor_elight_e.GetFloat();
el->radius = advisor_elight_rfeet.GetFloat() * 12.0f;
#endif
}
}
//-----------------------------------------------------------------------------
// Create a telekinetic beam effect from my head to an object
// TODO: use a point attachment.
//-----------------------------------------------------------------------------
void C_NPC_Advisor::StartBeamFX( C_BaseEntity *pOnEntity )
{
Assert(pOnEntity);
if (!pOnEntity)
return;
CNewParticleEffect *pEffect = ParticleProp()->Create( "Advisor_Psychic_Beam", PATTACH_ABSORIGIN_FOLLOW );
Assert(pEffect);
if (!pEffect) return;
ParticleProp()->AddControlPoint( pEffect, 1, pOnEntity, PATTACH_ABSORIGIN_FOLLOW );
}
//-----------------------------------------------------------------------------
// terminate a telekinetic beam effect from my head to an object
//-----------------------------------------------------------------------------
void C_NPC_Advisor::StopBeamFX( C_BaseEntity *pOnEntity )
{
Assert(pOnEntity);
if (!pOnEntity)
return;
ParticleProp()->StopParticlesInvolving( pOnEntity );
}
void C_NPC_Advisor::StartElight()
{
AssertMsg(m_ElightKey == 0 , "Advisor trying to create new elight on top of old one!");
if ( m_ElightKey != 0 )
{
Warning("Advisor tried to start his elight when it was already one.\n");
}
else
{
m_ElightKey = LIGHT_INDEX_TE_DYNAMIC + this->entindex();
dlight_t * el = effects->CL_AllocElight( m_ElightKey );
if ( el )
{
// create an elight on top of me
el->origin = this->WorldSpaceCenter();
el->color.r = 235;
el->color.g = 255;
el->color.b = 255;
el->color.exponent = 3;
el->radius = 52*12;
el->decay = 0.0f;
el->die = gpGlobals->curtime + 2000.0f; // 1000 just means " a long time "
SetNextClientThink( CLIENT_THINK_ALWAYS );
}
else
{ // null out the light value
m_ElightKey = 0;
}
}
}
void C_NPC_Advisor::StopElight()
{
AssertMsg( m_ElightKey != 0, "Advisor tried to stop elight when none existed!");
dlight_t * el;
// note: the following conditional sets el if not short-circuited
if ( m_ElightKey == 0 || (el = effects->GetElightByKey(m_ElightKey)) == NULL )
{
Warning("Advisor tried to stop its elight when it had none.\n");
}
else
{
// kill the elight by setting the die value to now
el->die = gpGlobals->curtime;
}
}
#endif
/******************************************************
* Tenser, said the Tensor. *
* Tenser, said the Tensor. *
* Tension, apprehension and dissension have begun. *
******************************************************/

View File

@@ -0,0 +1,167 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
//=============================================================================
#include "cbase.h"
#include "c_ai_basenpc.h"
#include "bone_setup.h"
// Must be the last file included
#include "memdbgon.h"
extern ConVar r_sequence_debug;
class C_NPC_Puppet : public C_AI_BaseNPC
{
DECLARE_CLASS( C_NPC_Puppet, C_AI_BaseNPC );
public:
virtual void ClientThink( void );
virtual void OnDataChanged( DataUpdateType_t updateType );
virtual void BuildTransformations( CStudioHdr *pStudioHdr, Vector *pos, Quaternion q[], const matrix3x4_t& cameraTransform, int boneMask, CBoneBitList &boneComputed );
virtual void AccumulateLayers( IBoneSetup &boneSetup, Vector pos[], Quaternion q[], float currentTime );
EHANDLE m_hAnimationTarget;
int m_nTargetAttachment;
DECLARE_CLIENTCLASS();
};
IMPLEMENT_CLIENTCLASS_DT( C_NPC_Puppet, DT_NPC_Puppet, CNPC_Puppet )
RecvPropEHandle( RECVINFO(m_hAnimationTarget) ),
RecvPropInt( RECVINFO(m_nTargetAttachment) ),
END_RECV_TABLE()
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void C_NPC_Puppet::OnDataChanged( DataUpdateType_t updateType )
{
BaseClass::OnDataChanged( updateType );
if ( updateType == DATA_UPDATE_CREATED )
{
SetNextClientThink( CLIENT_THINK_ALWAYS );
}
}
//-----------------------------------------------------------------------------
// Purpose: We need to slam our position!
//-----------------------------------------------------------------------------
void C_NPC_Puppet::BuildTransformations( CStudioHdr *pStudioHdr, Vector *pos, Quaternion q[], const matrix3x4_t& cameraTransform, int boneMask, CBoneBitList &boneComputed )
{
if ( m_hAnimationTarget && m_nTargetAttachment != -1 )
{
C_BaseAnimating *pTarget = m_hAnimationTarget->GetBaseAnimating();
if ( pTarget )
{
matrix3x4_t matTarget;
pTarget->GetAttachment( m_nTargetAttachment, matTarget );
MatrixCopy( matTarget, GetBoneForWrite( 0 ) );
boneComputed.ClearAll(); // FIXME: Why is this calculated already?
boneComputed.MarkBone( 0 );
}
}
// Call the baseclass
BaseClass::BuildTransformations( pStudioHdr, pos, q, cameraTransform, boneMask, boneComputed );
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void C_NPC_Puppet::ClientThink( void )
{
if ( m_hAnimationTarget == NULL )
return;
C_BaseAnimating *pTarget = m_hAnimationTarget->GetBaseAnimating();
if ( pTarget == NULL )
return;
int nTargetSequence = pTarget->GetSequence();
const char *pSequenceName = pTarget->GetSequenceName( nTargetSequence );
int nSequence = LookupSequence( pSequenceName );
if ( nSequence >= 0 )
{
if ( nSequence != GetSequence() )
{
SetSequence( nSequence );
UpdateVisibility();
}
SetCycle( pTarget->GetCycle() );
SetPlaybackRate( pTarget->GetPlaybackRate() );
}
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void C_NPC_Puppet::AccumulateLayers( IBoneSetup &boneSetup, Vector pos[], Quaternion q[], float currentTime )
{
if ( m_hAnimationTarget == NULL )
return;
C_BaseAnimatingOverlay *pTarget = dynamic_cast<C_BaseAnimatingOverlay *>( m_hAnimationTarget->GetBaseAnimating() );
if ( pTarget == NULL )
return;
// resort the layers
int layer[MAX_OVERLAYS];
int i;
for (i = 0; i < MAX_OVERLAYS; i++)
{
layer[i] = MAX_OVERLAYS;
}
for (i = 0; i < pTarget->m_AnimOverlay.Count(); i++)
{
if (pTarget->m_AnimOverlay[i].m_nOrder < MAX_OVERLAYS)
{
layer[pTarget->m_AnimOverlay[i].m_nOrder] = i;
}
}
int j;
for (j = 0; j < MAX_OVERLAYS; j++)
{
i = layer[ j ];
if (i < pTarget->m_AnimOverlay.Count())
{
float fWeight = pTarget->m_AnimOverlay[i].m_flWeight;
if (fWeight > 0)
{
const char *pSequenceName = pTarget->GetSequenceName( pTarget->m_AnimOverlay[i].m_nSequence );
int nSequence = LookupSequence( pSequenceName );
if ( nSequence >= 0 )
{
float fCycle = pTarget->m_AnimOverlay[ i ].m_flCycle;
fCycle = ClampCycle( fCycle, IsSequenceLooping( nSequence ) );
if (fWeight > 1)
fWeight = 1;
boneSetup.AccumulatePose( pos, q, nSequence, fCycle, fWeight, currentTime, NULL );
#if _DEBUG
if (Q_stristr( boneSetup.GetStudioHdr()->pszName(), r_sequence_debug.GetString()) != NULL)
{
DevMsgRT( "%6.2f : %30s : %5.3f : %4.2f : %1d\n", currentTime, boneSetup.GetStudioHdr()->pSeqdesc( nSequence ).pszLabel(), fCycle, fWeight, i );
}
#endif
}
}
}
}
}

View File

@@ -0,0 +1,142 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
//=============================================================================
#include "cbase.h"
class C_PropCoreBall : public C_BaseAnimating
{
DECLARE_CLASS( C_PropCoreBall, C_BaseAnimating );
DECLARE_CLIENTCLASS();
DECLARE_DATADESC();
public:
C_PropCoreBall();
void ApplyBoneMatrixTransform( matrix3x4_t& transform );
float m_flScaleX;
float m_flScaleY;
float m_flScaleZ;
float m_flLerpTimeX;
float m_flLerpTimeY;
float m_flLerpTimeZ;
float m_flGoalTimeX;
float m_flGoalTimeY;
float m_flGoalTimeZ;
float m_flCurrentScale[3];
bool m_bRunningScale[3];
float m_flTargetScale[3];
private:
};
void RecvProxy_ScaleX( const CRecvProxyData *pData, void *pStruct, void *pOut )
{
C_PropCoreBall *pCoreData = (C_PropCoreBall *) pStruct;
pCoreData->m_flScaleX = pData->m_Value.m_Float;
if ( pCoreData->m_bRunningScale[0] == true )
{
pCoreData->m_flTargetScale[0] = pCoreData->m_flCurrentScale[0];
}
}
void RecvProxy_ScaleY( const CRecvProxyData *pData, void *pStruct, void *pOut )
{
C_PropCoreBall *pCoreData = (C_PropCoreBall *) pStruct;
pCoreData->m_flScaleY = pData->m_Value.m_Float;
if ( pCoreData->m_bRunningScale[1] == true )
{
pCoreData->m_flTargetScale[1] = pCoreData->m_flCurrentScale[1];
}
}
void RecvProxy_ScaleZ( const CRecvProxyData *pData, void *pStruct, void *pOut )
{
C_PropCoreBall *pCoreData = (C_PropCoreBall *) pStruct;
pCoreData->m_flScaleZ = pData->m_Value.m_Float;
if ( pCoreData->m_bRunningScale[2] == true )
{
pCoreData->m_flTargetScale[2] = pCoreData->m_flCurrentScale[2];
}
}
IMPLEMENT_CLIENTCLASS_DT( C_PropCoreBall, DT_PropCoreBall, CPropCoreBall )
RecvPropFloat( RECVINFO( m_flScaleX ), 0, RecvProxy_ScaleX ),
RecvPropFloat( RECVINFO( m_flScaleY ), 0, RecvProxy_ScaleY ),
RecvPropFloat( RECVINFO( m_flScaleZ ), 0, RecvProxy_ScaleZ ),
RecvPropFloat( RECVINFO( m_flLerpTimeX ) ),
RecvPropFloat( RECVINFO( m_flLerpTimeY ) ),
RecvPropFloat( RECVINFO( m_flLerpTimeZ ) ),
RecvPropFloat( RECVINFO( m_flGoalTimeX ) ),
RecvPropFloat( RECVINFO( m_flGoalTimeY ) ),
RecvPropFloat( RECVINFO( m_flGoalTimeZ ) ),
END_RECV_TABLE()
BEGIN_DATADESC( C_PropCoreBall )
DEFINE_AUTO_ARRAY( m_flTargetScale, FIELD_FLOAT ),
DEFINE_AUTO_ARRAY( m_bRunningScale, FIELD_BOOLEAN ),
END_DATADESC()
C_PropCoreBall::C_PropCoreBall( void )
{
m_flTargetScale[0] = 1.0f;
m_flTargetScale[1] = 1.0f;
m_flTargetScale[2] = 1.0f;
m_bRunningScale[0] = false;
m_bRunningScale[1] = false;
m_bRunningScale[2] = false;
}
void C_PropCoreBall::ApplyBoneMatrixTransform( matrix3x4_t& transform )
{
BaseClass::ApplyBoneMatrixTransform( transform );
float flVal[3] = { m_flTargetScale[0], m_flTargetScale[1], m_flTargetScale[2] };
float *flTargetScale[3] = { &m_flTargetScale[0], &m_flTargetScale[1], &m_flTargetScale[2] };
float flScale[3] = { m_flScaleX, m_flScaleY, m_flScaleZ };
float flLerpTime[3] = { m_flLerpTimeX, m_flLerpTimeY, m_flLerpTimeZ };
float flGoalTime[3] = { m_flGoalTimeX, m_flGoalTimeY, m_flGoalTimeZ };
bool *bRunning[3] = { &m_bRunningScale[0], &m_bRunningScale[1], &m_bRunningScale[2] };
for ( int i = 0; i < 3; i++ )
{
if ( *flTargetScale[i] != flScale[i] )
{
float deltaTime = (float)( gpGlobals->curtime - flGoalTime[i]) / flLerpTime[i];
float flRemapVal = SimpleSplineRemapVal( deltaTime, 0.0f, 1.0f, *flTargetScale[i], flScale[i] );
*bRunning[i] = true;
if ( deltaTime >= 1.0f )
{
*flTargetScale[i] = flScale[i];
*bRunning[i] = false;
}
flVal[i] = flRemapVal;
m_flCurrentScale[i] = flVal[i];
}
}
VectorScale( transform[0], flVal[0], transform[0] );
VectorScale( transform[1], flVal[1], transform[1] );
VectorScale( transform[2], flVal[2], transform[2] );
}

View File

@@ -0,0 +1,196 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
//=============================================================================
#include "cbase.h"
class C_PropScalable : public C_BaseAnimating
{
DECLARE_CLASS( C_PropScalable, C_BaseAnimating );
DECLARE_CLIENTCLASS();
DECLARE_DATADESC();
public:
C_PropScalable();
virtual void ApplyBoneMatrixTransform( matrix3x4_t& transform );
virtual void GetRenderBounds( Vector &theMins, Vector &theMaxs );
// Must be available to proxy functions
float m_flScaleX;
float m_flScaleY;
float m_flScaleZ;
float m_flLerpTimeX;
float m_flLerpTimeY;
float m_flLerpTimeZ;
float m_flGoalTimeX;
float m_flGoalTimeY;
float m_flGoalTimeZ;
float m_flCurrentScale[3];
bool m_bRunningScale[3];
float m_flTargetScale[3];
private:
void CalculateScale( void );
float m_nCalcFrame; // Frame the last calculation was made at
};
void RecvProxy_ScaleX( const CRecvProxyData *pData, void *pStruct, void *pOut )
{
C_PropScalable *pCoreData = (C_PropScalable *) pStruct;
pCoreData->m_flScaleX = pData->m_Value.m_Float;
if ( pCoreData->m_bRunningScale[0] == true )
{
pCoreData->m_flTargetScale[0] = pCoreData->m_flCurrentScale[0];
}
}
void RecvProxy_ScaleY( const CRecvProxyData *pData, void *pStruct, void *pOut )
{
C_PropScalable *pCoreData = (C_PropScalable *) pStruct;
pCoreData->m_flScaleY = pData->m_Value.m_Float;
if ( pCoreData->m_bRunningScale[1] == true )
{
pCoreData->m_flTargetScale[1] = pCoreData->m_flCurrentScale[1];
}
}
void RecvProxy_ScaleZ( const CRecvProxyData *pData, void *pStruct, void *pOut )
{
C_PropScalable *pCoreData = (C_PropScalable *) pStruct;
pCoreData->m_flScaleZ = pData->m_Value.m_Float;
if ( pCoreData->m_bRunningScale[2] == true )
{
pCoreData->m_flTargetScale[2] = pCoreData->m_flCurrentScale[2];
}
}
IMPLEMENT_CLIENTCLASS_DT( C_PropScalable, DT_PropScalable, CPropScalable )
RecvPropFloat( RECVINFO( m_flScaleX ), 0, RecvProxy_ScaleX ),
RecvPropFloat( RECVINFO( m_flScaleY ), 0, RecvProxy_ScaleY ),
RecvPropFloat( RECVINFO( m_flScaleZ ), 0, RecvProxy_ScaleZ ),
RecvPropFloat( RECVINFO( m_flLerpTimeX ) ),
RecvPropFloat( RECVINFO( m_flLerpTimeY ) ),
RecvPropFloat( RECVINFO( m_flLerpTimeZ ) ),
RecvPropFloat( RECVINFO( m_flGoalTimeX ) ),
RecvPropFloat( RECVINFO( m_flGoalTimeY ) ),
RecvPropFloat( RECVINFO( m_flGoalTimeZ ) ),
END_RECV_TABLE()
BEGIN_DATADESC( C_PropScalable )
DEFINE_AUTO_ARRAY( m_flTargetScale, FIELD_FLOAT ),
DEFINE_AUTO_ARRAY( m_bRunningScale, FIELD_BOOLEAN ),
END_DATADESC()
C_PropScalable::C_PropScalable( void )
{
m_flTargetScale[0] = 1.0f;
m_flTargetScale[1] = 1.0f;
m_flTargetScale[2] = 1.0f;
m_bRunningScale[0] = false;
m_bRunningScale[1] = false;
m_bRunningScale[2] = false;
m_nCalcFrame = 0;
}
//-----------------------------------------------------------------------------
// Purpose: Calculates the scake of the object once per frame
//-----------------------------------------------------------------------------
void C_PropScalable::CalculateScale( void )
{
// Don't bother to calculate this for a second time in the same frame
if ( m_nCalcFrame == gpGlobals->framecount )
return;
// Mark that we cached this value for the frame
m_nCalcFrame = gpGlobals->framecount;
float flVal[3] = { m_flTargetScale[0], m_flTargetScale[1], m_flTargetScale[2] };
float *flTargetScale[3] = { &m_flTargetScale[0], &m_flTargetScale[1], &m_flTargetScale[2] };
float flScale[3] = { m_flScaleX, m_flScaleY, m_flScaleZ };
float flLerpTime[3] = { m_flLerpTimeX, m_flLerpTimeY, m_flLerpTimeZ };
float flGoalTime[3] = { m_flGoalTimeX, m_flGoalTimeY, m_flGoalTimeZ };
bool *bRunning[3] = { &m_bRunningScale[0], &m_bRunningScale[1], &m_bRunningScale[2] };
for ( int i = 0; i < 3; i++ )
{
if ( *flTargetScale[i] != flScale[i] )
{
float deltaTime = (float)( gpGlobals->curtime - flGoalTime[i]) / flLerpTime[i];
float flRemapVal = SimpleSplineRemapValClamped( deltaTime, 0.0f, 1.0f, *flTargetScale[i], flScale[i] );
*bRunning[i] = true;
if ( deltaTime >= 1.0f )
{
*flTargetScale[i] = flScale[i];
*bRunning[i] = false;
}
flVal[i] = flRemapVal;
m_flCurrentScale[i] = flVal[i];
}
else
{
m_flCurrentScale[i] = m_flTargetScale[i];
}
}
}
//-----------------------------------------------------------------------------
// Purpose: Scales the bones based on the current scales
//-----------------------------------------------------------------------------
void C_PropScalable::ApplyBoneMatrixTransform( matrix3x4_t& transform )
{
BaseClass::ApplyBoneMatrixTransform( transform );
// Find the scale for this frame
CalculateScale();
VectorScale( transform[0], m_flCurrentScale[0], transform[0] );
VectorScale( transform[1], m_flCurrentScale[1], transform[1] );
VectorScale( transform[2], m_flCurrentScale[2], transform[2] );
UpdateVisibility();
}
//-----------------------------------------------------------------------------
// Purpose: Ensures the render bounds match the scales
//-----------------------------------------------------------------------------
void C_PropScalable::GetRenderBounds( Vector &theMins, Vector &theMaxs )
{
BaseClass::GetRenderBounds( theMins, theMaxs );
// Find the scale for this frame
CalculateScale();
// Extend our render bounds to encompass the scaled object
theMins.x *= m_flCurrentScale[0];
theMins.y *= m_flCurrentScale[1];
theMins.z *= m_flCurrentScale[2];
theMaxs.x *= m_flCurrentScale[0];
theMaxs.y *= m_flCurrentScale[1];
theMaxs.z *= m_flCurrentScale[2];
Assert( theMins.IsValid() && theMaxs.IsValid() );
}

View File

@@ -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 );
}

View File

@@ -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 );

View File

@@ -0,0 +1,421 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
//=============================================================================
#include "cbase.h"
#include "basegrenade_shared.h"
#include "fx_interpvalue.h"
#include "fx_envelope.h"
#include "materialsystem/imaterialvar.h"
#include "particles_simple.h"
#include "particles_attractor.h"
// FIXME: Move out
extern void DrawSpriteTangentSpace( const Vector &vecOrigin, float flWidth, float flHeight, color32 color );
#define EXPLOSION_DURATION 3.0f
//-----------------------------------------------------------------------------
// Explosion effect for hopwire
//-----------------------------------------------------------------------------
class C_HopwireExplosion : public C_EnvelopeFX
{
typedef C_EnvelopeFX BaseClass;
public:
C_HopwireExplosion( void ) :
m_hOwner( NULL )
{
m_FXCoreScale.SetAbsolute( 0.0f );
m_FXCoreAlpha.SetAbsolute( 0.0f );
}
virtual void Update( void );
virtual int DrawModel( int flags );
virtual void GetRenderBounds( Vector& mins, Vector& maxs );
bool SetupEmitters( void );
void AddParticles( void );
void SetOwner( C_BaseEntity *pOwner );
void StartExplosion( void );
void StopExplosion( void );
void StartPreExplosion( void );
private:
CInterpolatedValue m_FXCoreScale;
CInterpolatedValue m_FXCoreAlpha;
CSmartPtr<CSimpleEmitter> m_pSimpleEmitter;
CSmartPtr<CParticleAttractor> m_pAttractorEmitter;
TimedEvent m_ParticleTimer;
CHandle<C_BaseEntity> m_hOwner;
};
//-----------------------------------------------------------------------------
// Purpose: Setup the emitters we'll be using
//-----------------------------------------------------------------------------
bool C_HopwireExplosion::SetupEmitters( void )
{
// Setup the basic core emitter
if ( m_pSimpleEmitter.IsValid() == false )
{
m_pSimpleEmitter = CSimpleEmitter::Create( "hopwirecore" );
if ( m_pSimpleEmitter.IsValid() == false )
return false;
}
// Setup the attractor emitter
if ( m_pAttractorEmitter.IsValid() == false )
{
m_pAttractorEmitter = CParticleAttractor::Create( GetRenderOrigin(), "hopwireattractor" );
if ( m_pAttractorEmitter.IsValid() == false )
return false;
}
return true;
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void C_HopwireExplosion::AddParticles( void )
{
// Make sure the emitters are setup properly
if ( SetupEmitters() == false )
return;
float tempDelta = gpGlobals->frametime;
while( m_ParticleTimer.NextEvent( tempDelta ) )
{
// ========================
// Attracted dust particles
// ========================
// Update our attractor point
m_pAttractorEmitter->SetAttractorOrigin( GetRenderOrigin() );
Vector offset;
SimpleParticle *sParticle;
offset = GetRenderOrigin() + RandomVector( -256.0f, 256.0f );
sParticle = (SimpleParticle *) m_pAttractorEmitter->AddParticle( sizeof(SimpleParticle), g_Mat_Fleck_Cement[0], offset );
if ( sParticle == NULL )
return;
sParticle->m_vecVelocity = Vector(0,0,8);
sParticle->m_flDieTime = 0.5f;
sParticle->m_flLifetime = 0.0f;
sParticle->m_flRoll = Helper_RandomInt( 0, 360 );
sParticle->m_flRollDelta = 1.0f;
float alpha = random->RandomFloat( 128.0f, 200.0f );
sParticle->m_uchColor[0] = alpha;
sParticle->m_uchColor[1] = alpha;
sParticle->m_uchColor[2] = alpha;
sParticle->m_uchStartAlpha = alpha;
sParticle->m_uchEndAlpha = alpha;
sParticle->m_uchStartSize = random->RandomInt( 1, 4 );
sParticle->m_uchEndSize = 0;
// ========================
// Core effects
// ========================
// Reset our sort origin
m_pSimpleEmitter->SetSortOrigin( GetRenderOrigin() );
// Base of the core effect
sParticle = (SimpleParticle *) m_pSimpleEmitter->AddParticle( sizeof(SimpleParticle), m_pSimpleEmitter->GetPMaterial( "effects/strider_muzzle" ), GetRenderOrigin() );
if ( sParticle == NULL )
return;
sParticle->m_vecVelocity = vec3_origin;
sParticle->m_flDieTime = 0.2f;
sParticle->m_flLifetime = 0.0f;
sParticle->m_flRoll = Helper_RandomInt( 0, 360 );
sParticle->m_flRollDelta = 4.0f;
alpha = random->RandomInt( 32, 200 );
sParticle->m_uchColor[0] = alpha;
sParticle->m_uchColor[1] = alpha;
sParticle->m_uchColor[2] = alpha;
sParticle->m_uchStartAlpha = 0;
sParticle->m_uchEndAlpha = alpha;
sParticle->m_uchStartSize = 255;
sParticle->m_uchEndSize = 0;
// Make sure we encompass the complete particle here!
m_pSimpleEmitter->SetParticleCullRadius( sParticle->m_uchEndSize );
// =========================
// Dust ring effect
// =========================
if ( random->RandomInt( 0, 5 ) != 1 )
return;
Vector vecDustColor;
vecDustColor.x = 0.35f;
vecDustColor.y = 0.3f;
vecDustColor.z = 0.25f;
Vector color;
int numRingSprites = 8;
float yaw;
Vector forward, vRight, vForward;
vForward = Vector( 0, 1, 0 );
vRight = Vector( 1, 0, 0 );
float yawOfs = random->RandomFloat( 0, 359 );
for ( int i = 0; i < numRingSprites; i++ )
{
yaw = ( (float) i / (float) numRingSprites ) * 360.0f;
yaw += yawOfs;
forward = ( vRight * sin( DEG2RAD( yaw) ) ) + ( vForward * cos( DEG2RAD( yaw ) ) );
VectorNormalize( forward );
trace_t tr;
UTIL_TraceLine( GetRenderOrigin(), GetRenderOrigin()+(Vector(0, 0, -1024)), MASK_SOLID_BRUSHONLY, NULL, COLLISION_GROUP_NONE, &tr );
offset = ( RandomVector( -4.0f, 4.0f ) + tr.endpos ) + ( forward * 512.0f );
sParticle = (SimpleParticle *) m_pSimpleEmitter->AddParticle( sizeof(SimpleParticle), g_Mat_DustPuff[random->RandomInt(0,1)], offset );
if ( sParticle != NULL )
{
sParticle->m_flLifetime = 0.0f;
sParticle->m_flDieTime = random->RandomFloat( 0.25f, 0.5f );
sParticle->m_vecVelocity = forward * -random->RandomFloat( 1000, 1500 );
sParticle->m_vecVelocity[2] += 128.0f;
#if __EXPLOSION_DEBUG
debugoverlay->AddLineOverlay( m_vecOrigin, m_vecOrigin + sParticle->m_vecVelocity, 255, 0, 0, false, 3 );
#endif
sParticle->m_uchColor[0] = vecDustColor.x * 255.0f;
sParticle->m_uchColor[1] = vecDustColor.y * 255.0f;
sParticle->m_uchColor[2] = vecDustColor.z * 255.0f;
sParticle->m_uchStartSize = random->RandomInt( 32, 128 );
sParticle->m_uchEndSize = 200;
sParticle->m_uchStartAlpha = random->RandomFloat( 16, 64 );
sParticle->m_uchEndAlpha = 0;
sParticle->m_flRoll = random->RandomInt( 0, 360 );
sParticle->m_flRollDelta = random->RandomFloat( -16.0f, 16.0f );
}
}
}
}
//-----------------------------------------------------------------------------
// Purpose:
// Input : *pOwner -
//-----------------------------------------------------------------------------
void C_HopwireExplosion::SetOwner( C_BaseEntity *pOwner )
{
m_hOwner = pOwner;
}
//-----------------------------------------------------------------------------
// Purpose: Updates the internal values for the effect
//-----------------------------------------------------------------------------
void C_HopwireExplosion::Update( void )
{
if ( m_hOwner )
{
SetRenderOrigin( m_hOwner->GetRenderOrigin() );
}
BaseClass::Update();
}
//-----------------------------------------------------------------------------
// Purpose: Updates and renders all effects
//-----------------------------------------------------------------------------
int C_HopwireExplosion::DrawModel( int flags )
{
AddParticles();
CMatRenderContextPtr pRenderContext( materials );
pRenderContext->Flush();
UpdateRefractTexture();
IMaterial *pMat = materials->FindMaterial( "effects/strider_pinch_dudv", TEXTURE_GROUP_CLIENT_EFFECTS );
float refract = m_FXCoreAlpha.Interp( gpGlobals->curtime );
float scale = m_FXCoreScale.Interp( gpGlobals->curtime );
IMaterialVar *pVar = pMat->FindVar( "$refractamount", NULL );
pVar->SetFloatValue( refract );
pRenderContext->Bind( pMat, (IClientRenderable*)this );
float sin1 = sinf( gpGlobals->curtime * 10 );
float sin2 = sinf( gpGlobals->curtime );
float scaleY = ( sin1 * sin2 ) * 32.0f;
float scaleX = (sin2 * sin2) * 32.0f;
// FIXME: The ball needs to sort properly at all times
static color32 white = {255,255,255,255};
DrawSpriteTangentSpace( GetRenderOrigin() + ( CurrentViewForward() * 128.0f ), scale+scaleX, scale+scaleY, white );
return 1;
}
//-----------------------------------------------------------------------------
// Purpose: Returns the bounds relative to the origin (render bounds)
//-----------------------------------------------------------------------------
void C_HopwireExplosion::GetRenderBounds( Vector& mins, Vector& maxs )
{
float scale = m_FXCoreScale.Interp( gpGlobals->curtime );
mins.Init( -scale, -scale, -scale );
maxs.Init( scale, scale, scale );
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void C_HopwireExplosion::StartExplosion( void )
{
m_FXCoreScale.Init( 300.0f, 500.0f, 2.0f, INTERP_SPLINE );
m_FXCoreAlpha.Init( 0.0f, 0.1f, 1.5f, INTERP_SPLINE );
// Particle timer
m_ParticleTimer.Init( 60 );
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void C_HopwireExplosion::StopExplosion( void )
{
m_FXCoreAlpha.InitFromCurrent( 0.0f, 1.0f, INTERP_SPLINE );
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void C_HopwireExplosion::StartPreExplosion( void )
{
}
//-----------------------------------------------------------------------------
// Hopwire client class
//-----------------------------------------------------------------------------
class C_GrenadeHopwire : public C_BaseGrenade
{
DECLARE_CLASS( C_GrenadeHopwire, C_BaseGrenade );
DECLARE_CLIENTCLASS();
public:
C_GrenadeHopwire( void );
virtual int DrawModel( int flags );
virtual void OnDataChanged( DataUpdateType_t updateType );
virtual void ReceiveMessage( int classID, bf_read &msg );
private:
C_HopwireExplosion m_ExplosionEffect; // Explosion effect information and drawing
};
IMPLEMENT_CLIENTCLASS_DT( C_GrenadeHopwire, DT_GrenadeHopwire, CGrenadeHopwire )
END_RECV_TABLE()
#define HOPWIRE_START_EXPLOSION 0
#define HOPWIRE_STOP_EXPLOSION 1
#define HOPWIRE_START_PRE_EXPLOSION 2
//-----------------------------------------------------------------------------
// Constructor
//-----------------------------------------------------------------------------
C_GrenadeHopwire::C_GrenadeHopwire( void )
{
m_ExplosionEffect.SetActive( false );
}
//-----------------------------------------------------------------------------
// Purpose: Receive messages from the server
// Input : classID - class to receive the message
// &msg - message in question
//-----------------------------------------------------------------------------
void C_GrenadeHopwire::ReceiveMessage( int classID, bf_read &msg )
{
if ( classID != GetClientClass()->m_ClassID )
{
// Message is for subclass
BaseClass::ReceiveMessage( classID, msg );
return;
}
int messageType = msg.ReadByte();
switch( messageType )
{
case HOPWIRE_START_EXPLOSION:
{
m_ExplosionEffect.SetActive();
m_ExplosionEffect.SetOwner( this );
m_ExplosionEffect.StartExplosion();
}
break;
case HOPWIRE_STOP_EXPLOSION:
{
m_ExplosionEffect.StopExplosion();
}
break;
default:
break;
}
}
//-----------------------------------------------------------------------------
// Purpose:
// Input : updateType -
//-----------------------------------------------------------------------------
void C_GrenadeHopwire::OnDataChanged( DataUpdateType_t updateType )
{
BaseClass::OnDataChanged( updateType );
m_ExplosionEffect.Update();
}
//-----------------------------------------------------------------------------
// Purpose:
// Input : flags -
//-----------------------------------------------------------------------------
int C_GrenadeHopwire::DrawModel( int flags )
{
if ( m_ExplosionEffect.IsActive() )
return 1;
return BaseClass::DrawModel( flags );
}

View File

@@ -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();
}

View File

@@ -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

View File

@@ -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 );

View File

@@ -0,0 +1,580 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
// $NoKeywords: $
//===========================================================================//
#include "cbase.h"
#include <stdio.h>
#include <cdll_client_int.h>
#include <cdll_util.h>
#include <globalvars_base.h>
#include <igameresources.h>
#include "IGameUIFuncs.h" // for key bindings
#include "inputsystem/iinputsystem.h"
#include "clientscoreboarddialog.h"
#include <voice_status.h>
#include <vgui/IScheme.h>
#include <vgui/ILocalize.h>
#include <vgui/ISurface.h>
#include <vgui/IVGui.h>
#include <vstdlib/IKeyValuesSystem.h>
#include <KeyValues.h>
#include <vgui_controls/ImageList.h>
#include <vgui_controls/Label.h>
#include <vgui_controls/SectionedListPanel.h>
#include <game/client/iviewport.h>
#include <igameresources.h>
#include "vgui_avatarimage.h"
// memdbgon must be the last include file in a .cpp file!!!
#include "tier0/memdbgon.h"
using namespace vgui;
bool AvatarIndexLessFunc( const int &lhs, const int &rhs )
{
return lhs < rhs;
}
//-----------------------------------------------------------------------------
// Purpose: Constructor
//-----------------------------------------------------------------------------
CClientScoreBoardDialog::CClientScoreBoardDialog(IViewPort *pViewPort) : EditablePanel( NULL, PANEL_SCOREBOARD )
{
m_iPlayerIndexSymbol = KeyValuesSystem()->GetSymbolForString("playerIndex");
m_nCloseKey = BUTTON_CODE_INVALID;
//memset(s_VoiceImage, 0x0, sizeof( s_VoiceImage ));
TrackerImage = 0;
m_pViewPort = pViewPort;
// initialize dialog
SetProportional(true);
SetKeyBoardInputEnabled(false);
SetMouseInputEnabled(false);
// set the scheme before any child control is created
SetScheme("ClientScheme");
m_pPlayerList = new SectionedListPanel(this, "PlayerList");
m_pPlayerList->SetVerticalScrollbar(false);
LoadControlSettings("Resource/UI/ScoreBoard.res");
m_iDesiredHeight = GetTall();
m_pPlayerList->SetVisible( false ); // hide this until we load the images in applyschemesettings
m_HLTVSpectators = 0;
m_ReplaySpectators = 0;
// update scoreboard instantly if on of these events occure
ListenForGameEvent( "hltv_status" );
ListenForGameEvent( "server_spawn" );
m_pImageList = NULL;
m_mapAvatarsToImageList.SetLessFunc( DefLessFunc( CSteamID ) );
m_mapAvatarsToImageList.RemoveAll();
}
//-----------------------------------------------------------------------------
// Purpose: Constructor
//-----------------------------------------------------------------------------
CClientScoreBoardDialog::~CClientScoreBoardDialog()
{
if ( NULL != m_pImageList )
{
delete m_pImageList;
m_pImageList = NULL;
}
}
//-----------------------------------------------------------------------------
// Call every frame
//-----------------------------------------------------------------------------
void CClientScoreBoardDialog::OnThink()
{
BaseClass::OnThink();
// NOTE: this is necessary because of the way input works.
// If a key down message is sent to vgui, then it will get the key up message
// Sometimes the scoreboard is activated by other vgui menus,
// sometimes by console commands. In the case where it's activated by
// other vgui menus, we lose the key up message because this panel
// doesn't accept keyboard input. It *can't* accept keyboard input
// because another feature of the dialog is that if it's triggered
// from within the game, you should be able to still run around while
// the scoreboard is up. That feature is impossible if this panel accepts input.
// because if a vgui panel is up that accepts input, it prevents the engine from
// receiving that input. So, I'm stuck with a polling solution.
//
// Close key is set to non-invalid when something other than a keybind
// brings the scoreboard up, and it's set to invalid as soon as the
// dialog becomes hidden.
if ( m_nCloseKey != BUTTON_CODE_INVALID )
{
if ( !g_pInputSystem->IsButtonDown( m_nCloseKey ) )
{
m_nCloseKey = BUTTON_CODE_INVALID;
gViewPortInterface->ShowPanel( PANEL_SCOREBOARD, false );
GetClientVoiceMgr()->StopSquelchMode();
}
}
}
//-----------------------------------------------------------------------------
// Called by vgui panels that activate the client scoreboard
//-----------------------------------------------------------------------------
void CClientScoreBoardDialog::OnPollHideCode( int code )
{
m_nCloseKey = (ButtonCode_t)code;
}
//-----------------------------------------------------------------------------
// Purpose: clears everything in the scoreboard and all it's state
//-----------------------------------------------------------------------------
void CClientScoreBoardDialog::Reset()
{
// clear
m_pPlayerList->DeleteAllItems();
m_pPlayerList->RemoveAllSections();
m_iSectionId = 0;
m_fNextUpdateTime = 0;
// add all the sections
InitScoreboardSections();
}
//-----------------------------------------------------------------------------
// Purpose: adds all the team sections to the scoreboard
//-----------------------------------------------------------------------------
void CClientScoreBoardDialog::InitScoreboardSections()
{
}
//-----------------------------------------------------------------------------
// Purpose: sets up screen
//-----------------------------------------------------------------------------
void CClientScoreBoardDialog::ApplySchemeSettings( IScheme *pScheme )
{
BaseClass::ApplySchemeSettings( pScheme );
if ( m_pImageList )
delete m_pImageList;
m_pImageList = new ImageList( false );
m_mapAvatarsToImageList.RemoveAll();
PostApplySchemeSettings( pScheme );
}
//-----------------------------------------------------------------------------
// Purpose: Does dialog-specific customization after applying scheme settings.
//-----------------------------------------------------------------------------
void CClientScoreBoardDialog::PostApplySchemeSettings( vgui::IScheme *pScheme )
{
// resize the images to our resolution
for (int i = 0; i < m_pImageList->GetImageCount(); i++ )
{
int wide, tall;
m_pImageList->GetImage(i)->GetSize(wide, tall);
m_pImageList->GetImage(i)->SetSize(scheme()->GetProportionalScaledValueEx( GetScheme(),wide), scheme()->GetProportionalScaledValueEx( GetScheme(),tall));
}
m_pPlayerList->SetImageList( m_pImageList, false );
m_pPlayerList->SetVisible( true );
// light up scoreboard a bit
SetBgColor( Color( 0,0,0,0) );
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CClientScoreBoardDialog::ShowPanel(bool bShow)
{
// Catch the case where we call ShowPanel before ApplySchemeSettings, eg when
// going from windowed <-> fullscreen
if ( m_pImageList == NULL )
{
InvalidateLayout( true, true );
}
if ( !bShow )
{
m_nCloseKey = BUTTON_CODE_INVALID;
}
if ( BaseClass::IsVisible() == bShow )
return;
if ( bShow )
{
Reset();
Update();
SetVisible( true );
MoveToFront();
}
else
{
BaseClass::SetVisible( false );
SetMouseInputEnabled( false );
SetKeyBoardInputEnabled( false );
}
}
void CClientScoreBoardDialog::FireGameEvent( IGameEvent *event )
{
const char * type = event->GetName();
if ( Q_strcmp(type, "hltv_status") == 0 )
{
// spectators = clients - proxies
m_HLTVSpectators = event->GetInt( "clients" );
m_HLTVSpectators -= event->GetInt( "proxies" );
}
else if ( Q_strcmp(type, "server_spawn") == 0 )
{
// We'll post the message ourselves instead of using SetControlString()
// so we don't try to translate the hostname.
const char *hostname = event->GetString( "hostname" );
Panel *control = FindChildByName( "ServerName" );
if ( control )
{
PostMessage( control, new KeyValues( "SetText", "text", hostname ) );
control->MoveToFront();
}
}
if( IsVisible() )
Update();
}
bool CClientScoreBoardDialog::NeedsUpdate( void )
{
return (m_fNextUpdateTime < gpGlobals->curtime);
}
//-----------------------------------------------------------------------------
// Purpose: Recalculate the internal scoreboard data
//-----------------------------------------------------------------------------
void CClientScoreBoardDialog::Update( void )
{
// Set the title
// Reset();
m_pPlayerList->DeleteAllItems();
FillScoreBoard();
// grow the scoreboard to fit all the players
int wide, tall;
m_pPlayerList->GetContentSize(wide, tall);
tall += GetAdditionalHeight();
wide = GetWide();
if (m_iDesiredHeight < tall)
{
SetSize(wide, tall);
m_pPlayerList->SetSize(wide, tall);
}
else
{
SetSize(wide, m_iDesiredHeight);
m_pPlayerList->SetSize(wide, m_iDesiredHeight);
}
MoveToCenterOfScreen();
// update every second
m_fNextUpdateTime = gpGlobals->curtime + 1.0f;
}
//-----------------------------------------------------------------------------
// Purpose: Sort all the teams
//-----------------------------------------------------------------------------
void CClientScoreBoardDialog::UpdateTeamInfo()
{
// TODO: work out a sorting algorithm for team display for TF2
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CClientScoreBoardDialog::UpdatePlayerInfo()
{
m_iSectionId = 0; // 0'th row is a header
int selectedRow = -1;
// walk all the players and make sure they're in the scoreboard
for ( int i = 1; i <= gpGlobals->maxClients; ++i )
{
IGameResources *gr = GameResources();
if ( gr && gr->IsConnected( i ) )
{
// add the player to the list
KeyValues *playerData = new KeyValues("data");
GetPlayerScoreInfo( i, playerData );
UpdatePlayerAvatar( i, playerData );
const char *oldName = playerData->GetString("name","");
char newName[MAX_PLAYER_NAME_LENGTH];
UTIL_MakeSafeName( oldName, newName, MAX_PLAYER_NAME_LENGTH );
playerData->SetString("name", newName);
int itemID = FindItemIDForPlayerIndex( i );
int sectionID = gr->GetTeam( i );
if ( gr->IsLocalPlayer( i ) )
{
selectedRow = itemID;
}
if (itemID == -1)
{
// add a new row
itemID = m_pPlayerList->AddItem( sectionID, playerData );
}
else
{
// modify the current row
m_pPlayerList->ModifyItem( itemID, sectionID, playerData );
}
// set the row color based on the players team
m_pPlayerList->SetItemFgColor( itemID, gr->GetTeamColor( sectionID ) );
playerData->deleteThis();
}
else
{
// remove the player
int itemID = FindItemIDForPlayerIndex( i );
if (itemID != -1)
{
m_pPlayerList->RemoveItem(itemID);
}
}
}
if ( selectedRow != -1 )
{
m_pPlayerList->SetSelectedItem(selectedRow);
}
}
//-----------------------------------------------------------------------------
// Purpose: adds the top header of the scoreboars
//-----------------------------------------------------------------------------
void CClientScoreBoardDialog::AddHeader()
{
// add the top header
m_pPlayerList->AddSection(m_iSectionId, "");
m_pPlayerList->SetSectionAlwaysVisible(m_iSectionId);
m_pPlayerList->AddColumnToSection(m_iSectionId, "name", "#PlayerName", 0, scheme()->GetProportionalScaledValueEx( GetScheme(),NAME_WIDTH) );
m_pPlayerList->AddColumnToSection(m_iSectionId, "frags", "#PlayerScore", 0, scheme()->GetProportionalScaledValueEx( GetScheme(),SCORE_WIDTH) );
m_pPlayerList->AddColumnToSection(m_iSectionId, "deaths", "#PlayerDeath", 0, scheme()->GetProportionalScaledValueEx( GetScheme(),DEATH_WIDTH) );
m_pPlayerList->AddColumnToSection(m_iSectionId, "ping", "#PlayerPing", 0, scheme()->GetProportionalScaledValueEx( GetScheme(),PING_WIDTH) );
}
//-----------------------------------------------------------------------------
// Purpose: Adds a new section to the scoreboard (i.e the team header)
//-----------------------------------------------------------------------------
void CClientScoreBoardDialog::AddSection(int teamType, int teamNumber)
{
if ( teamType == TYPE_TEAM )
{
IGameResources *gr = GameResources();
if ( !gr )
return;
// setup the team name
wchar_t *teamName = g_pVGuiLocalize->Find( gr->GetTeamName(teamNumber) );
wchar_t name[64];
wchar_t string1[1024];
if (!teamName)
{
g_pVGuiLocalize->ConvertANSIToUnicode(gr->GetTeamName(teamNumber), name, sizeof(name));
teamName = name;
}
g_pVGuiLocalize->ConstructString( string1, sizeof( string1 ), g_pVGuiLocalize->Find("#Player"), 2, teamName );
m_pPlayerList->AddSection(m_iSectionId, "", StaticPlayerSortFunc);
// Avatars are always displayed at 32x32 regardless of resolution
if ( ShowAvatars() )
{
m_pPlayerList->AddColumnToSection( m_iSectionId, "avatar", "", SectionedListPanel::COLUMN_IMAGE | SectionedListPanel::COLUMN_RIGHT, m_iAvatarWidth );
}
m_pPlayerList->AddColumnToSection(m_iSectionId, "name", string1, 0, scheme()->GetProportionalScaledValueEx( GetScheme(),NAME_WIDTH) - m_iAvatarWidth );
m_pPlayerList->AddColumnToSection(m_iSectionId, "frags", "", 0, scheme()->GetProportionalScaledValueEx( GetScheme(),SCORE_WIDTH) );
m_pPlayerList->AddColumnToSection(m_iSectionId, "deaths", "", 0, scheme()->GetProportionalScaledValueEx( GetScheme(),DEATH_WIDTH) );
m_pPlayerList->AddColumnToSection(m_iSectionId, "ping", "", 0, scheme()->GetProportionalScaledValueEx( GetScheme(),PING_WIDTH) );
}
else if ( teamType == TYPE_SPECTATORS )
{
m_pPlayerList->AddSection(m_iSectionId, "");
// Avatars are always displayed at 32x32 regardless of resolution
if ( ShowAvatars() )
{
m_pPlayerList->AddColumnToSection( m_iSectionId, "avatar", "", SectionedListPanel::COLUMN_IMAGE | SectionedListPanel::COLUMN_RIGHT, m_iAvatarWidth );
}
m_pPlayerList->AddColumnToSection(m_iSectionId, "name", "#Spectators", 0, scheme()->GetProportionalScaledValueEx( GetScheme(),NAME_WIDTH) - m_iAvatarWidth );
m_pPlayerList->AddColumnToSection(m_iSectionId, "frags", "", 0, scheme()->GetProportionalScaledValueEx( GetScheme(),SCORE_WIDTH) );
}
}
//-----------------------------------------------------------------------------
// Purpose: Used for sorting players
//-----------------------------------------------------------------------------
bool CClientScoreBoardDialog::StaticPlayerSortFunc(vgui::SectionedListPanel *list, int itemID1, int itemID2)
{
KeyValues *it1 = list->GetItemData(itemID1);
KeyValues *it2 = list->GetItemData(itemID2);
Assert(it1 && it2);
// first compare frags
int v1 = it1->GetInt("frags");
int v2 = it2->GetInt("frags");
if (v1 > v2)
return true;
else if (v1 < v2)
return false;
// next compare deaths
v1 = it1->GetInt("deaths");
v2 = it2->GetInt("deaths");
if (v1 > v2)
return false;
else if (v1 < v2)
return true;
// the same, so compare itemID's (as a sentinel value to get deterministic sorts)
return itemID1 < itemID2;
}
//-----------------------------------------------------------------------------
// Purpose: Adds a new row to the scoreboard, from the playerinfo structure
//-----------------------------------------------------------------------------
bool CClientScoreBoardDialog::GetPlayerScoreInfo(int playerIndex, KeyValues *kv)
{
IGameResources *gr = GameResources();
if (!gr )
return false;
kv->SetInt("deaths", gr->GetDeaths( playerIndex ) );
kv->SetInt("frags", gr->GetFrags( playerIndex ) );
kv->SetInt("ping", gr->GetPing( playerIndex ) ) ;
kv->SetString("name", gr->GetPlayerName( playerIndex ) );
kv->SetInt("playerIndex", playerIndex);
return true;
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CClientScoreBoardDialog::UpdatePlayerAvatar( int playerIndex, KeyValues *kv )
{
// Update their avatar
if ( kv && ShowAvatars() && steamapicontext->SteamFriends() && steamapicontext->SteamUtils() )
{
player_info_t pi;
if ( engine->GetPlayerInfo( playerIndex, &pi ) )
{
if ( pi.friendsID )
{
CSteamID steamIDForPlayer( pi.friendsID, 1, steamapicontext->SteamUtils()->GetConnectedUniverse(), k_EAccountTypeIndividual );
// See if we already have that avatar in our list
int iMapIndex = m_mapAvatarsToImageList.Find( steamIDForPlayer );
int iImageIndex;
if ( iMapIndex == m_mapAvatarsToImageList.InvalidIndex() )
{
CAvatarImage *pImage = new CAvatarImage();
pImage->SetAvatarSteamID( steamIDForPlayer );
pImage->SetAvatarSize( 32, 32 ); // Deliberately non scaling
iImageIndex = m_pImageList->AddImage( pImage );
m_mapAvatarsToImageList.Insert( steamIDForPlayer, iImageIndex );
}
else
{
iImageIndex = m_mapAvatarsToImageList[ iMapIndex ];
}
kv->SetInt( "avatar", iImageIndex );
CAvatarImage *pAvIm = (CAvatarImage *)m_pImageList->GetImage( iImageIndex );
pAvIm->UpdateFriendStatus();
}
}
}
}
//-----------------------------------------------------------------------------
// Purpose: reload the player list on the scoreboard
//-----------------------------------------------------------------------------
void CClientScoreBoardDialog::FillScoreBoard()
{
// update totals information
UpdateTeamInfo();
// update player info
UpdatePlayerInfo();
}
//-----------------------------------------------------------------------------
// Purpose: searches for the player in the scoreboard
//-----------------------------------------------------------------------------
int CClientScoreBoardDialog::FindItemIDForPlayerIndex(int playerIndex)
{
for (int i = 0; i <= m_pPlayerList->GetHighestItemID(); i++)
{
if (m_pPlayerList->IsItemIDValid(i))
{
KeyValues *kv = m_pPlayerList->GetItemData(i);
kv = kv->FindKey(m_iPlayerIndexSymbol);
if (kv && kv->GetInt() == playerIndex)
return i;
}
}
return -1;
}
//-----------------------------------------------------------------------------
// Purpose: Sets the text of a control by name
//-----------------------------------------------------------------------------
void CClientScoreBoardDialog::MoveLabelToFront(const char *textEntryName)
{
Label *entry = dynamic_cast<Label *>(FindChildByName(textEntryName));
if (entry)
{
entry->MoveToFront();
}
}
//-----------------------------------------------------------------------------
// Purpose: Center the dialog on the screen. (vgui has this method on
// Frame, but we're an EditablePanel, need to roll our own.)
//-----------------------------------------------------------------------------
void CClientScoreBoardDialog::MoveToCenterOfScreen()
{
int wx, wy, ww, wt;
surface()->GetWorkspaceBounds(wx, wy, ww, wt);
SetPos((ww - GetWide()) / 2, (wt - GetTall()) / 2);
}

View File

@@ -0,0 +1,68 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
//=============================================================================//
#include "cbase.h"
#include "IconPanel.h"
#include "KeyValues.h"
DECLARE_BUILD_FACTORY( CIconPanel );
CIconPanel::CIconPanel( vgui::Panel *parent, const char *name ) : vgui::Panel( parent, name )
{
m_szIcon[0] = '\0';
m_icon = NULL;
m_bScaleImage = false;
}
void CIconPanel::ApplySettings( KeyValues *inResourceData )
{
Q_strncpy( m_szIcon, inResourceData->GetString( "icon", "" ), sizeof( m_szIcon ) );
m_icon = gHUD.GetIcon( m_szIcon );
m_bScaleImage = inResourceData->GetInt("scaleImage", 0);
BaseClass::ApplySettings( inResourceData );
}
void CIconPanel::SetIcon( const char *szIcon )
{
Q_strncpy( m_szIcon, szIcon, sizeof(m_szIcon) );
m_icon = gHUD.GetIcon( m_szIcon );
}
void CIconPanel::Paint()
{
BaseClass::Paint();
if ( m_icon )
{
int x, y, w, h;
GetBounds( x, y, w, h );
if ( m_bScaleImage )
{
m_icon->DrawSelf( 0, 0, w, h, m_IconColor );
}
else
{
m_icon->DrawSelf( 0, 0, m_IconColor );
}
}
}
void CIconPanel::ApplySchemeSettings( vgui::IScheme *pScheme )
{
BaseClass::ApplySchemeSettings( pScheme );
if ( m_szIcon[0] != '\0' )
{
m_icon = gHUD.GetIcon( m_szIcon );
}
SetFgColor( pScheme->GetColor( "FgColor", Color( 255, 255, 255, 255 ) ) );
}

View File

@@ -0,0 +1,42 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
// $NoKeywords: $
//=============================================================================//
#ifndef ICONPANEL_H
#define ICONPANEL_H
#ifdef _WIN32
#pragma once
#endif
#include <vgui_controls/Panel.h>
using namespace vgui;
class CIconPanel : public vgui::Panel
{
DECLARE_CLASS_SIMPLE( CIconPanel, vgui::Panel );
public:
CIconPanel( vgui::Panel *parent, const char *name );
void Init( void );
virtual void Paint();
virtual void ApplySettings( KeyValues *inResourceData );
virtual void ApplySchemeSettings( vgui::IScheme *pScheme );
void SetIcon( const char *szIcon );
void SetIconColor( Color cColor ) { m_IconColor = cColor; }
private:
CHudTexture *m_icon;
char m_szIcon[128];
bool m_bScaleImage;
CPanelAnimationVar( Color, m_IconColor, "iconColor", "255 255 255 255" );
};
#endif //ICONPANEL_H

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,137 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
// $NoKeywords: $
//=============================================================================//
#include "cbase.h"
#include "NavProgress.h"
#include <vgui/IScheme.h>
#include <vgui/ILocalize.h>
#include <vgui/ISurface.h>
#include <filesystem.h>
#include <KeyValues.h>
#include <convar.h>
#include <vgui_controls/Label.h>
#include <game/client/iviewport.h>
// memdbgon must be the last include file in a .cpp file!!!
#include "tier0/memdbgon.h"
using namespace vgui;
//--------------------------------------------------------------------------------------------------------------
CNavProgress::CNavProgress( IViewPort *pViewPort ) : Frame( NULL, PANEL_NAV_PROGRESS )
{
// initialize dialog
m_pViewPort = pViewPort;
// load the new scheme early!!
SetScheme("ClientScheme");
SetMoveable(false);
SetSizeable(false);
SetProportional(true);
// hide the system buttons
SetTitleBarVisible( false );
m_pTitle = new Label( this, "TitleLabel", "" );
m_pText = new Label( this, "TextLabel", "" );
m_pProgressBarBorder = new Panel( this, "ProgressBarBorder" );
m_pProgressBar = new Panel( this, "ProgressBar" );
m_pProgressBarSizer = new Panel( this, "ProgressBarSizer" );
LoadControlSettings("Resource/UI/NavProgress.res");
Reset();
}
//--------------------------------------------------------------------------------------------------------------
CNavProgress::~CNavProgress()
{
}
//--------------------------------------------------------------------------------------------------------------
void CNavProgress::ApplySchemeSettings(IScheme *pScheme)
{
BaseClass::ApplySchemeSettings( pScheme );
SetPaintBackgroundType( 2 );
m_pProgressBarSizer->SetVisible( false );
m_pProgressBarBorder->SetBorder( pScheme->GetBorder( "ButtonDepressedBorder" ) );
m_pProgressBarBorder->SetBgColor( Color( 0, 0, 0, 0 ) );
m_pProgressBar->SetBorder( pScheme->GetBorder( "ButtonBorder" ) );
m_pProgressBar->SetBgColor( pScheme->GetColor( "ProgressBar.FgColor", Color( 0, 0, 0, 0 ) ) );
}
//--------------------------------------------------------------------------------------------------------------
void CNavProgress::PerformLayout()
{
BaseClass::PerformLayout();
if ( m_numTicks )
{
int w = m_pProgressBarSizer->GetWide();
w = w * m_currentTick / m_numTicks;
m_pProgressBar->SetWide( w );
}
}
//--------------------------------------------------------------------------------------------------------------
void CNavProgress::Init( const char *title, int numTicks, int startTick )
{
m_pText->SetText( title );
m_numTicks = MAX( 1, numTicks ); // non-zero, since we'll divide by this
m_currentTick = MAX( 0, MIN( m_numTicks, startTick ) );
InvalidateLayout();
}
//--------------------------------------------------------------------------------------------------------------
void CNavProgress::SetData(KeyValues *data)
{
Init( data->GetString( "msg" ),
data->GetInt( "total" ),
data->GetInt( "current" ) );
}
//--------------------------------------------------------------------------------------------------------------
void CNavProgress::ShowPanel( bool bShow )
{
if ( BaseClass::IsVisible() == bShow )
return;
m_pViewPort->ShowBackGround( bShow );
if ( bShow )
{
Activate();
SetMouseInputEnabled( true );
}
else
{
SetVisible( false );
SetMouseInputEnabled( false );
}
}
//--------------------------------------------------------------------------------------------------------------
void CNavProgress::Reset( void )
{
}
//--------------------------------------------------------------------------------------------------------------
void CNavProgress::Update( void )
{
}
//--------------------------------------------------------------------------------------------------------------

View File

@@ -0,0 +1,59 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
//=============================================================================
#ifndef NAVPROGRESS_H
#define NAVPROGRESS_H
#ifdef _WIN32
#pragma once
#endif
#include <vgui_controls/Frame.h>
#include <vgui_controls/ProgressBar.h>
#include <game/client/iviewport.h>
class CNavProgress : public vgui::Frame, public IViewPortPanel
{
private:
DECLARE_CLASS_SIMPLE( CNavProgress, vgui::Frame );
public:
CNavProgress(IViewPort *pViewPort);
virtual ~CNavProgress();
virtual const char *GetName( void ) { return PANEL_NAV_PROGRESS; }
virtual void SetData(KeyValues *data);
virtual void Reset();
virtual void Update();
virtual bool NeedsUpdate( void ) { return false; }
virtual bool HasInputElements( void ) { return true; }
virtual void ShowPanel( bool bShow );
// both vgui::Frame and IViewPortPanel define these, so explicitly define them here as passthroughs to vgui
vgui::VPANEL GetVPanel( void ) { return BaseClass::GetVPanel(); }
virtual bool IsVisible() { return BaseClass::IsVisible(); }
virtual void SetParent( vgui::VPANEL parent ) { BaseClass::SetParent( parent ); }
public:
virtual void ApplySchemeSettings( vgui::IScheme *pScheme );
virtual void PerformLayout();
void Init( const char *title, int numTicks, int currentTick );
protected:
IViewPort *m_pViewPort;
int m_numTicks;
int m_currentTick;
vgui::Label * m_pTitle;
vgui::Label * m_pText;
vgui::Panel * m_pProgressBarBorder;
vgui::Panel * m_pProgressBar;
vgui::Panel * m_pProgressBarSizer;
};
#endif // NAVPROGRESS_H

View File

@@ -0,0 +1,850 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
// $NoKeywords: $
//=============================================================================//
#include "cbase.h"
#include <cdll_client_int.h>
#include <globalvars_base.h>
#include <cdll_util.h>
#include <KeyValues.h>
#include "spectatorgui.h"
#include <vgui/IScheme.h>
#include <vgui/ILocalize.h>
#include <vgui/ISurface.h>
#include <vgui/IPanel.h>
#include <vgui_controls/ImageList.h>
#include <vgui_controls/MenuItem.h>
#include <vgui_controls/TextImage.h>
#include <stdio.h> // _snprintf define
#include <game/client/iviewport.h>
#include "commandmenu.h"
#include "hltvcamera.h"
#if defined( REPLAY_ENABLED )
#include "replay/replaycamera.h"
#endif
#include <vgui_controls/TextEntry.h>
#include <vgui_controls/Panel.h>
#include <vgui_controls/ImagePanel.h>
#include <vgui_controls/Menu.h>
#include "IGameUIFuncs.h" // for key bindings
#include <imapoverview.h>
#include <shareddefs.h>
#include <igameresources.h>
#ifdef TF_CLIENT_DLL
#include "tf_gamerules.h"
void AddSubKeyNamed( KeyValues *pKeys, const char *pszName );
#endif
// memdbgon must be the last include file in a .cpp file!!!
#include "tier0/memdbgon.h"
#ifndef _XBOX
extern IGameUIFuncs *gameuifuncs; // for key binding details
#endif
// void DuckMessage(const char *str); // from vgui_teamfortressviewport.cpp
ConVar spec_scoreboard( "spec_scoreboard", "0", FCVAR_CLIENTDLL | FCVAR_ARCHIVE );
CSpectatorGUI *g_pSpectatorGUI = NULL;
// NB disconnect between localization text and observer mode enums
static const char *s_SpectatorModes[] =
{
"#Spec_Mode0", // OBS_MODE_NONE = 0,
"#Spec_Mode1", // OBS_MODE_DEATHCAM,
"", // OBS_MODE_FREEZECAM,
"#Spec_Mode2", // OBS_MODE_FIXED,
"#Spec_Mode3", // OBS_MODE_IN_EYE,
"#Spec_Mode4", // OBS_MODE_CHASE,
"#Spec_Mode5", // OBS_MODE_ROAMING,
};
using namespace vgui;
ConVar cl_spec_mode(
"cl_spec_mode",
"1",
FCVAR_ARCHIVE | FCVAR_USERINFO | FCVAR_SERVER_CAN_EXECUTE,
"spectator mode" );
//-----------------------------------------------------------------------------
// Purpose: left and right buttons pointing buttons
//-----------------------------------------------------------------------------
class CSpecButton : public Button
{
public:
CSpecButton(Panel *parent, const char *panelName): Button(parent, panelName, "") {}
private:
void ApplySchemeSettings(vgui::IScheme *pScheme)
{
Button::ApplySchemeSettings(pScheme);
SetFont(pScheme->GetFont("Marlett", IsProportional()) );
}
};
//-----------------------------------------------------------------------------
// Purpose: Constructor
//-----------------------------------------------------------------------------
CSpectatorMenu::CSpectatorMenu( IViewPort *pViewPort ) : Frame( NULL, PANEL_SPECMENU )
{
m_iDuckKey = BUTTON_CODE_INVALID;
m_pViewPort = pViewPort;
SetMouseInputEnabled( true );
SetKeyBoardInputEnabled( true );
SetTitleBarVisible( false ); // don't draw a title bar
SetMoveable( false );
SetSizeable( false );
SetProportional(true);
SetScheme("ClientScheme");
m_pPlayerList = new ComboBox(this, "playercombo", 10 , false);
HFont hFallbackFont = scheme()->GetIScheme( GetScheme() )->GetFont( "DefaultVerySmallFallBack", false );
if ( INVALID_FONT != hFallbackFont )
{
m_pPlayerList->SetUseFallbackFont( true, hFallbackFont );
}
m_pViewOptions = new ComboBox(this, "viewcombo", 10 , false );
m_pConfigSettings = new ComboBox(this, "settingscombo", 10 , false );
m_pLeftButton = new CSpecButton( this, "specprev");
m_pLeftButton->SetText("3");
m_pRightButton = new CSpecButton( this, "specnext");
m_pRightButton->SetText("4");
m_pPlayerList->SetText("");
m_pViewOptions->SetText("#Spec_Modes");
m_pConfigSettings->SetText("#Spec_Options");
m_pPlayerList->SetOpenDirection( Menu::UP );
m_pViewOptions->SetOpenDirection( Menu::UP );
m_pConfigSettings->SetOpenDirection( Menu::UP );
// create view config menu
CommandMenu * menu = new CommandMenu(m_pConfigSettings, "spectatormenu", gViewPortInterface);
menu->LoadFromFile( "Resource/spectatormenu.res" );
m_pConfigSettings->SetMenu( menu ); // attach menu to combo box
// create view mode menu
menu = new CommandMenu(m_pViewOptions, "spectatormodes", gViewPortInterface);
menu->LoadFromFile("Resource/spectatormodes.res");
m_pViewOptions->SetMenu( menu ); // attach menu to combo box
LoadControlSettings("Resource/UI/BottomSpectator.res");
ListenForGameEvent( "spec_target_updated" );
}
void CSpectatorMenu::ApplySchemeSettings(IScheme *pScheme)
{
BaseClass::ApplySchemeSettings(pScheme);
// need to MakeReadyForUse() on the menus so we can set their bg color before they are displayed
m_pConfigSettings->GetMenu()->MakeReadyForUse();
m_pViewOptions->GetMenu()->MakeReadyForUse();
m_pPlayerList->GetMenu()->MakeReadyForUse();
if ( g_pSpectatorGUI )
{
m_pConfigSettings->GetMenu()->SetBgColor( g_pSpectatorGUI->GetBlackBarColor() );
m_pViewOptions->GetMenu()->SetBgColor( g_pSpectatorGUI->GetBlackBarColor() );
m_pPlayerList->GetMenu()->SetBgColor( g_pSpectatorGUI->GetBlackBarColor() );
}
}
//-----------------------------------------------------------------------------
// Purpose: makes the GUI fill the screen
//-----------------------------------------------------------------------------
void CSpectatorMenu::PerformLayout()
{
int w,h;
GetHudSize(w, h);
// fill the screen
SetSize(w,GetTall());
}
//-----------------------------------------------------------------------------
// Purpose: Handles changes to combo boxes
//-----------------------------------------------------------------------------
void CSpectatorMenu::OnTextChanged(KeyValues *data)
{
Panel *panel = reinterpret_cast<vgui::Panel *>( data->GetPtr("panel") );
vgui::ComboBox *box = dynamic_cast<vgui::ComboBox *>( panel );
if( box == m_pConfigSettings) // don't change the text in the config setting combo
{
m_pConfigSettings->SetText("#Spec_Options");
}
else if ( box == m_pPlayerList )
{
KeyValues *kv = box->GetActiveItemUserData();
if ( kv && GameResources() )
{
const char *player = kv->GetString("player");
int currentPlayerNum = GetSpectatorTarget();
const char *currentPlayerName = GameResources()->GetPlayerName( currentPlayerNum );
if ( !FStrEq( currentPlayerName, player ) )
{
char command[128];
Q_snprintf( command, sizeof(command), "spec_player \"%s\"", player );
engine->ClientCmd( command );
}
}
}
}
void CSpectatorMenu::OnCommand( const char *command )
{
if (!stricmp(command, "specnext") )
{
engine->ClientCmd("spec_next");
}
else if (!stricmp(command, "specprev") )
{
engine->ClientCmd("spec_prev");
}
}
void CSpectatorMenu::FireGameEvent( IGameEvent * event )
{
const char *pEventName = event->GetName();
if ( Q_strcmp( "spec_target_updated", pEventName ) == 0 )
{
IGameResources *gr = GameResources();
if ( !gr )
return;
// make sure the player combo box is up to date
int playernum = GetSpectatorTarget();
if ( playernum < 1 || playernum > MAX_PLAYERS )
return;
const char *selectedPlayerName = gr->GetPlayerName( playernum );
const char *currentPlayerName = "";
KeyValues *kv = m_pPlayerList->GetActiveItemUserData();
if ( kv )
{
currentPlayerName = kv->GetString( "player" );
}
if ( !FStrEq( currentPlayerName, selectedPlayerName ) )
{
for ( int i=0; i<m_pPlayerList->GetItemCount(); ++i )
{
KeyValues *kv = m_pPlayerList->GetItemUserData( i );
if ( kv && FStrEq( kv->GetString( "player" ), selectedPlayerName ) )
{
m_pPlayerList->ActivateItemByRow( i );
break;
}
}
}
}
}
//-----------------------------------------------------------------------------
// Purpose: when duck is pressed it hides the active part of the GUI
//-----------------------------------------------------------------------------
void CSpectatorMenu::OnKeyCodePressed(KeyCode code)
{
if ( code == m_iDuckKey )
{
// hide if DUCK is pressed again
m_pViewPort->ShowPanel( this, false );
}
}
void CSpectatorMenu::ShowPanel(bool bShow)
{
if ( BaseClass::IsVisible() == bShow )
return;
if ( bShow )
{
Activate();
SetMouseInputEnabled( true );
SetKeyBoardInputEnabled( true );
}
else
{
SetVisible( false );
SetMouseInputEnabled( false );
SetKeyBoardInputEnabled( false );
}
bool bIsEnabled = true;
if ( engine->IsHLTV() && HLTVCamera()->IsPVSLocked() )
{
// when watching HLTV or Replay with a locked PVS, some elements are disabled
bIsEnabled = false;
}
m_pLeftButton->SetVisible( bIsEnabled );
m_pRightButton->SetVisible( bIsEnabled );
m_pPlayerList->SetVisible( bIsEnabled );
m_pViewOptions->SetVisible( bIsEnabled );
}
void CSpectatorMenu::Update( void )
{
IGameResources *gr = GameResources();
Reset();
if ( m_iDuckKey == BUTTON_CODE_INVALID )
{
m_iDuckKey = gameuifuncs->GetButtonCodeForBind( "duck" );
}
if ( !gr )
return;
int iPlayerIndex;
for ( iPlayerIndex = 1 ; iPlayerIndex <= gpGlobals->maxClients; iPlayerIndex++ )
{
// does this slot in the array have a name?
if ( !gr->IsConnected( iPlayerIndex ) )
continue;
if ( gr->IsLocalPlayer( iPlayerIndex ) )
continue;
if ( !gr->IsAlive( iPlayerIndex ) )
continue;
wchar_t playerText[ 80 ], playerName[ 64 ], *team, teamText[ 64 ];
char localizeTeamName[64];
char szPlayerIndex[16];
g_pVGuiLocalize->ConvertANSIToUnicode( UTIL_SafeName( gr->GetPlayerName(iPlayerIndex) ), playerName, sizeof( playerName ) );
const char * teamname = gr->GetTeamName( gr->GetTeam(iPlayerIndex) );
if ( teamname )
{
Q_snprintf( localizeTeamName, sizeof( localizeTeamName ), "#%s", teamname );
team=g_pVGuiLocalize->Find( localizeTeamName );
if ( !team )
{
g_pVGuiLocalize->ConvertANSIToUnicode( teamname , teamText, sizeof( teamText ) );
team = teamText;
}
g_pVGuiLocalize->ConstructString( playerText, sizeof( playerText ), g_pVGuiLocalize->Find( "#Spec_PlayerItem_Team" ), 2, playerName, team );
}
else
{
g_pVGuiLocalize->ConstructString( playerText, sizeof( playerText ), g_pVGuiLocalize->Find( "#Spec_PlayerItem" ), 1, playerName );
}
Q_snprintf( szPlayerIndex, sizeof( szPlayerIndex ), "%d", iPlayerIndex );
KeyValues *kv = new KeyValues( "UserData", "player", gr->GetPlayerName( iPlayerIndex ), "index", szPlayerIndex );
m_pPlayerList->AddItem( playerText, kv );
kv->deleteThis();
}
// make sure the player combo box is up to date
int playernum = GetSpectatorTarget();
const char *selectedPlayerName = gr->GetPlayerName( playernum );
for ( iPlayerIndex=0; iPlayerIndex<m_pPlayerList->GetItemCount(); ++iPlayerIndex )
{
KeyValues *kv = m_pPlayerList->GetItemUserData( iPlayerIndex );
if ( kv && FStrEq( kv->GetString( "player" ), selectedPlayerName ) )
{
m_pPlayerList->ActivateItemByRow( iPlayerIndex );
break;
}
}
//=============================================================================
// HPE_BEGIN:
// [pfreese] make sure the view mode combo box is up to date - the spectator
// mode can be changed multiple ways
//=============================================================================
int specmode = GetSpectatorMode();
m_pViewOptions->SetText(s_SpectatorModes[specmode]);
//=============================================================================
// HPE_END
//=============================================================================
}
//-----------------------------------------------------------------------------
// main spectator panel
//-----------------------------------------------------------------------------
// Purpose: Constructor
//-----------------------------------------------------------------------------
CSpectatorGUI::CSpectatorGUI(IViewPort *pViewPort) : EditablePanel( NULL, PANEL_SPECGUI )
{
// m_bHelpShown = false;
// m_bInsetVisible = false;
// m_iDuckKey = KEY_NONE;
SetSize( 10, 10 ); // Quiet "parent not sized yet" spew
m_bSpecScoreboard = false;
m_pViewPort = pViewPort;
g_pSpectatorGUI = this;
// initialize dialog
SetVisible(false);
SetProportional(true);
// load the new scheme early!!
SetScheme("ClientScheme");
SetMouseInputEnabled( false );
SetKeyBoardInputEnabled( false );
m_pTopBar = new Panel( this, "topbar" );
m_pBottomBarBlank = new Panel( this, "bottombarblank" );
// m_pBannerImage = new ImagePanel( m_pTopBar, NULL );
m_pPlayerLabel = new Label( this, "playerlabel", "" );
m_pPlayerLabel->SetVisible( false );
TextImage *image = m_pPlayerLabel->GetTextImage();
if ( image )
{
HFont hFallbackFont = scheme()->GetIScheme( GetScheme() )->GetFont( "DefaultVerySmallFallBack", false );
if ( INVALID_FONT != hFallbackFont )
{
image->SetUseFallbackFont( true, hFallbackFont );
}
}
SetPaintBorderEnabled(false);
SetPaintBackgroundEnabled(false);
// m_pBannerImage->SetVisible(false);
InvalidateLayout();
}
//-----------------------------------------------------------------------------
// Purpose: Destructor
//-----------------------------------------------------------------------------
CSpectatorGUI::~CSpectatorGUI()
{
g_pSpectatorGUI = NULL;
}
//-----------------------------------------------------------------------------
// Purpose: Sets the colour of the top and bottom bars
//-----------------------------------------------------------------------------
void CSpectatorGUI::ApplySchemeSettings(IScheme *pScheme)
{
KeyValues *pConditions = NULL;
#ifdef TF_CLIENT_DLL
if ( TFGameRules() && TFGameRules()->IsMannVsMachineMode() )
{
pConditions = new KeyValues( "conditions" );
AddSubKeyNamed( pConditions, "if_mvm" );
}
#endif
LoadControlSettings( GetResFile(), NULL, NULL, pConditions );
if ( pConditions )
{
pConditions->deleteThis();
}
m_pBottomBarBlank->SetVisible( true );
m_pTopBar->SetVisible( true );
BaseClass::ApplySchemeSettings( pScheme );
SetBgColor(Color( 0,0,0,0 ) ); // make the background transparent
m_pTopBar->SetBgColor(GetBlackBarColor());
m_pBottomBarBlank->SetBgColor(GetBlackBarColor());
// m_pBottomBar->SetBgColor(Color( 0,0,0,0 ));
SetPaintBorderEnabled(false);
SetBorder( NULL );
#ifdef CSTRIKE_DLL
SetZPos(80); // guarantee it shows above the scope
#endif
}
//-----------------------------------------------------------------------------
// Purpose: makes the GUI fill the screen
//-----------------------------------------------------------------------------
void CSpectatorGUI::PerformLayout()
{
int w,h,x,y;
GetHudSize(w, h);
// fill the screen
SetBounds(0,0,w,h);
// stretch the bottom bar across the screen
m_pBottomBarBlank->GetPos(x,y);
m_pBottomBarBlank->SetSize( w, h - y );
}
//-----------------------------------------------------------------------------
// Purpose: checks spec_scoreboard cvar to see if the scoreboard should be displayed
//-----------------------------------------------------------------------------
void CSpectatorGUI::OnThink()
{
BaseClass::OnThink();
if ( IsVisible() )
{
if ( m_bSpecScoreboard != spec_scoreboard.GetBool() )
{
if ( !spec_scoreboard.GetBool() || !gViewPortInterface->GetActivePanel() )
{
m_bSpecScoreboard = spec_scoreboard.GetBool();
gViewPortInterface->ShowPanel( PANEL_SCOREBOARD, m_bSpecScoreboard );
}
}
}
}
//-----------------------------------------------------------------------------
// Purpose: sets the image to display for the banner in the top right corner
//-----------------------------------------------------------------------------
void CSpectatorGUI::SetLogoImage(const char *image)
{
if ( m_pBannerImage )
{
m_pBannerImage->SetImage( scheme()->GetImage(image, false) );
}
}
//-----------------------------------------------------------------------------
// Purpose: Sets the text of a control by name
//-----------------------------------------------------------------------------
void CSpectatorGUI::SetLabelText(const char *textEntryName, const char *text)
{
Label *entry = dynamic_cast<Label *>(FindChildByName(textEntryName));
if (entry)
{
entry->SetText(text);
}
}
//-----------------------------------------------------------------------------
// Purpose: Sets the text of a control by name
//-----------------------------------------------------------------------------
void CSpectatorGUI::SetLabelText(const char *textEntryName, wchar_t *text)
{
Label *entry = dynamic_cast<Label *>(FindChildByName(textEntryName));
if (entry)
{
entry->SetText(text);
}
}
//-----------------------------------------------------------------------------
// Purpose: Sets the text of a control by name
//-----------------------------------------------------------------------------
void CSpectatorGUI::MoveLabelToFront(const char *textEntryName)
{
Label *entry = dynamic_cast<Label *>(FindChildByName(textEntryName));
if (entry)
{
entry->MoveToFront();
}
}
//-----------------------------------------------------------------------------
// Purpose: shows/hides the buy menu
//-----------------------------------------------------------------------------
void CSpectatorGUI::ShowPanel(bool bShow)
{
if ( bShow && !IsVisible() )
{
m_bSpecScoreboard = false;
}
SetVisible( bShow );
if ( !bShow && m_bSpecScoreboard )
{
gViewPortInterface->ShowPanel( PANEL_SCOREBOARD, false );
}
}
bool CSpectatorGUI::ShouldShowPlayerLabel( int specmode )
{
return ( (specmode == OBS_MODE_IN_EYE) || (specmode == OBS_MODE_CHASE) );
}
//-----------------------------------------------------------------------------
// Purpose: Updates the gui, rearranges elements
//-----------------------------------------------------------------------------
void CSpectatorGUI::Update()
{
int wide, tall;
int bx, by, bwide, btall;
GetHudSize(wide, tall);
m_pTopBar->GetBounds( bx, by, bwide, btall );
IGameResources *gr = GameResources();
int specmode = GetSpectatorMode();
int playernum = GetSpectatorTarget();
IViewPortPanel *overview = gViewPortInterface->FindPanelByName( PANEL_OVERVIEW );
if ( overview && overview->IsVisible() )
{
int mx, my, mwide, mtall;
VPANEL p = overview->GetVPanel();
vgui::ipanel()->GetPos( p, mx, my );
vgui::ipanel()->GetSize( p, mwide, mtall );
if ( my < btall )
{
// reduce to bar
m_pTopBar->SetSize( wide - (mx + mwide), btall );
m_pTopBar->SetPos( (mx + mwide), 0 );
}
else
{
// full top bar
m_pTopBar->SetSize( wide , btall );
m_pTopBar->SetPos( 0, 0 );
}
}
else
{
// full top bar
m_pTopBar->SetSize( wide , btall ); // change width, keep height
m_pTopBar->SetPos( 0, 0 );
}
m_pPlayerLabel->SetVisible( ShouldShowPlayerLabel(specmode) );
// update player name filed, text & color
if ( playernum > 0 && playernum <= gpGlobals->maxClients && gr )
{
Color c = gr->GetTeamColor( gr->GetTeam(playernum) ); // Player's team color
m_pPlayerLabel->SetFgColor( c );
wchar_t playerText[ 80 ], playerName[ 64 ], health[ 10 ];
V_wcsncpy( playerText, L"Unable to find #Spec_PlayerItem*", sizeof( playerText ) );
memset( playerName, 0x0, sizeof( playerName ) );
g_pVGuiLocalize->ConvertANSIToUnicode( UTIL_SafeName(gr->GetPlayerName( playernum )), playerName, sizeof( playerName ) );
int iHealth = gr->GetHealth( playernum );
if ( iHealth > 0 && gr->IsAlive(playernum) )
{
_snwprintf( health, ARRAYSIZE( health ), L"%i", iHealth );
g_pVGuiLocalize->ConstructString( playerText, sizeof( playerText ), g_pVGuiLocalize->Find( "#Spec_PlayerItem_Team" ), 2, playerName, health );
}
else
{
g_pVGuiLocalize->ConstructString( playerText, sizeof( playerText ), g_pVGuiLocalize->Find( "#Spec_PlayerItem" ), 1, playerName );
}
m_pPlayerLabel->SetText( playerText );
}
else
{
m_pPlayerLabel->SetText( L"" );
}
// update extra info field
wchar_t szEtxraInfo[1024];
wchar_t szTitleLabel[1024];
char tempstr[128];
if ( engine->IsHLTV() )
{
// set spectator number and HLTV title
Q_snprintf(tempstr,sizeof(tempstr),"Spectators : %d", HLTVCamera()->GetNumSpectators() );
g_pVGuiLocalize->ConvertANSIToUnicode(tempstr,szEtxraInfo,sizeof(szEtxraInfo));
Q_strncpy( tempstr, HLTVCamera()->GetTitleText(), sizeof(tempstr) );
g_pVGuiLocalize->ConvertANSIToUnicode(tempstr,szTitleLabel,sizeof(szTitleLabel));
}
else
{
// otherwise show map name
Q_FileBase( engine->GetLevelName(), tempstr, sizeof(tempstr) );
wchar_t wMapName[64];
g_pVGuiLocalize->ConvertANSIToUnicode(tempstr,wMapName,sizeof(wMapName));
g_pVGuiLocalize->ConstructString( szEtxraInfo,sizeof( szEtxraInfo ), g_pVGuiLocalize->Find("#Spec_Map" ),1, wMapName );
g_pVGuiLocalize->ConvertANSIToUnicode( "" ,szTitleLabel,sizeof(szTitleLabel));
}
SetLabelText("extrainfo", szEtxraInfo );
SetLabelText("titlelabel", szTitleLabel );
}
//-----------------------------------------------------------------------------
// Purpose: Updates the timer label if one exists
//-----------------------------------------------------------------------------
void CSpectatorGUI::UpdateTimer()
{
wchar_t szText[ 63 ];
int timer = 0;
V_swprintf_safe ( szText, L"%d:%02d\n", (timer / 60), (timer % 60) );
SetLabelText("timerlabel", szText );
}
static void ForwardSpecCmdToServer( const CCommand &args )
{
if ( engine->IsPlayingDemo() )
return;
if ( args.ArgC() == 1 )
{
// just forward the command without parameters
engine->ServerCmd( args[ 0 ] );
}
else if ( args.ArgC() == 2 )
{
// forward the command with parameter
char command[128];
Q_snprintf( command, sizeof(command), "%s \"%s\"", args[ 0 ], args[ 1 ] );
engine->ServerCmd( command );
}
}
CON_COMMAND_F( spec_next, "Spectate next player", FCVAR_CLIENTCMD_CAN_EXECUTE )
{
C_BasePlayer *pPlayer = C_BasePlayer::GetLocalPlayer();
if ( !pPlayer || !pPlayer->IsObserver() )
return;
if ( engine->IsHLTV() )
{
// handle the command clientside
if ( !HLTVCamera()->IsPVSLocked() )
{
HLTVCamera()->SpecNextPlayer( false );
}
}
else
{
ForwardSpecCmdToServer( args );
}
}
CON_COMMAND_F( spec_prev, "Spectate previous player", FCVAR_CLIENTCMD_CAN_EXECUTE )
{
C_BasePlayer *pPlayer = C_BasePlayer::GetLocalPlayer();
if ( !pPlayer || !pPlayer->IsObserver() )
return;
if ( engine->IsHLTV() )
{
// handle the command clientside
if ( !HLTVCamera()->IsPVSLocked() )
{
HLTVCamera()->SpecNextPlayer( true );
}
}
else
{
ForwardSpecCmdToServer( args );
}
}
CON_COMMAND_F( spec_mode, "Set spectator mode", FCVAR_CLIENTCMD_CAN_EXECUTE )
{
C_BasePlayer *pPlayer = C_BasePlayer::GetLocalPlayer();
if ( !pPlayer || !pPlayer->IsObserver() )
return;
if ( engine->IsHLTV() )
{
if ( HLTVCamera()->IsPVSLocked() )
{
// in locked mode we can only switch between first and 3rd person
HLTVCamera()->ToggleChaseAsFirstPerson();
}
else
{
// we can choose any mode, not loked to PVS
int mode;
if ( args.ArgC() == 2 )
{
// set specifc mode
mode = Q_atoi( args[1] );
}
else
{
// set next mode
mode = HLTVCamera()->GetMode()+1;
if ( mode > LAST_PLAYER_OBSERVERMODE )
mode = OBS_MODE_IN_EYE;
}
// handle the command clientside
HLTVCamera()->SetMode( mode );
}
// turn off auto director once user tried to change view settings
HLTVCamera()->SetAutoDirector( false );
}
else
{
// we spectate on a game server, forward command
ForwardSpecCmdToServer( args );
}
}
CON_COMMAND_F( spec_player, "Spectate player by name", FCVAR_CLIENTCMD_CAN_EXECUTE )
{
C_BasePlayer *pPlayer = C_BasePlayer::GetLocalPlayer();
if ( !pPlayer || !pPlayer->IsObserver() )
return;
if ( args.ArgC() != 2 )
return;
if ( engine->IsHLTV() )
{
// we can only switch primary spectator targets is PVS isnt locked by auto-director
if ( !HLTVCamera()->IsPVSLocked() )
{
HLTVCamera()->SpecNamedPlayer( args[1] );
}
}
else
{
ForwardSpecCmdToServer( args );
}
}

View File

@@ -0,0 +1,653 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
//=============================================================================
#include "cbase.h"
#include "basemodel_panel.h"
#include "activitylist.h"
#include "animation.h"
#include "vgui/IInput.h"
#include "matsys_controls/manipulator.h"
using namespace vgui;
DECLARE_BUILD_FACTORY( CBaseModelPanel );
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
CBaseModelPanel::CBaseModelPanel( vgui::Panel *pParent, const char *pName ): BaseClass( pParent, pName )
{
m_bForcePos = false;
m_bMousePressed = false;
m_bAllowRotation = false;
m_bAllowFullManipulation = false;
m_bApplyManipulators = false;
m_bForcedCameraPosition = false;
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
CBaseModelPanel::~CBaseModelPanel()
{
}
//-----------------------------------------------------------------------------
// Purpose: Load in the model portion of the panel's resource file.
//-----------------------------------------------------------------------------
void CBaseModelPanel::ApplySettings( KeyValues *inResourceData )
{
BaseClass::ApplySettings( inResourceData );
// Set whether we render to texture
m_bRenderToTexture = inResourceData->GetBool( "render_texture", true );
// Grab and set the camera FOV.
float flFOV = GetCameraFOV();
m_BMPResData.m_flFOV = inResourceData->GetInt( "fov", flFOV );
SetCameraFOV( m_BMPResData.m_flFOV );
// Do we allow rotation on these panels.
m_bAllowRotation = inResourceData->GetBool( "allow_rot", false );
// Do we allow full manipulation on these panels.
m_bAllowFullManipulation = inResourceData->GetBool( "allow_manip", false );
// Parse our resource file and apply all necessary updates to the MDL.
for ( KeyValues *pData = inResourceData->GetFirstSubKey() ; pData != NULL ; pData = pData->GetNextKey() )
{
if ( !Q_stricmp( pData->GetName(), "model" ) )
{
ParseModelResInfo( pData );
}
}
SetMouseInputEnabled( m_bAllowFullManipulation || m_bAllowRotation );
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CBaseModelPanel::ParseModelResInfo( KeyValues *inResourceData )
{
m_bForcePos = ( inResourceData->GetInt( "force_pos", 0 ) == 1 );
m_BMPResData.m_pszModelName = ReadAndAllocStringValue( inResourceData, "modelname" );
m_BMPResData.m_pszModelName_HWM = ReadAndAllocStringValue( inResourceData, "modelname_hwm" );
m_BMPResData.m_pszVCD = ReadAndAllocStringValue( inResourceData, "vcd" );
m_BMPResData.m_angModelPoseRot.Init( inResourceData->GetFloat( "angles_x", 0.0f ), inResourceData->GetFloat( "angles_y", 0.0f ), inResourceData->GetFloat( "angles_z", 0.0f ) );
m_BMPResData.m_vecOriginOffset.Init( inResourceData->GetFloat( "origin_x", 110.0 ), inResourceData->GetFloat( "origin_y", 5.0 ), inResourceData->GetFloat( "origin_z", 5.0 ) );
m_BMPResData.m_vecFramedOriginOffset.Init( inResourceData->GetFloat( "frame_origin_x", 110.0 ), inResourceData->GetFloat( "frame_origin_y", 5.0 ), inResourceData->GetFloat( "frame_origin_z", 5.0 ) );
m_BMPResData.m_vecViewportOffset.Init();
m_BMPResData.m_nSkin = inResourceData->GetInt( "skin", -1 );
m_BMPResData.m_bUseSpotlight = ( inResourceData->GetInt( "spotlight", 0 ) == 1 );
m_angPlayer = m_BMPResData.m_angModelPoseRot;
m_vecPlayerPos = m_BMPResData.m_vecOriginOffset;
for ( KeyValues *pData = inResourceData->GetFirstSubKey(); pData != NULL; pData = pData->GetNextKey() )
{
if ( !Q_stricmp( pData->GetName(), "animation" ) )
{
ParseModelAnimInfo( pData );
}
else if ( !Q_stricmp( pData->GetName(), "attached_model" ) )
{
ParseModelAttachInfo( pData );
}
}
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CBaseModelPanel::ParseModelAnimInfo( KeyValues *inResourceData )
{
if ( !inResourceData )
return;
int iAnim = m_BMPResData.m_aAnimations.AddToTail();
if ( iAnim == m_BMPResData.m_aAnimations.InvalidIndex() )
return;
m_BMPResData.m_aAnimations[iAnim].m_pszName = ReadAndAllocStringValue( inResourceData, "name" );
m_BMPResData.m_aAnimations[iAnim].m_pszSequence = ReadAndAllocStringValue( inResourceData, "sequence" );
m_BMPResData.m_aAnimations[iAnim].m_pszActivity = ReadAndAllocStringValue( inResourceData, "activity" );
m_BMPResData.m_aAnimations[iAnim].m_bDefault = ( inResourceData->GetInt( "default", 0 ) == 1 );
for ( KeyValues *pAnimData = inResourceData->GetFirstSubKey(); pAnimData != NULL; pAnimData = pAnimData->GetNextKey() )
{
if ( !Q_stricmp( pAnimData->GetName(), "pose_parameters" ) )
{
m_BMPResData.m_aAnimations[iAnim].m_pPoseParameters = pAnimData->MakeCopy();
}
}
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CBaseModelPanel::ParseModelAttachInfo( KeyValues *inResourceData )
{
if ( !inResourceData )
return;
int iAttach = m_BMPResData.m_aAttachModels.AddToTail();
if ( iAttach == m_BMPResData.m_aAttachModels.InvalidIndex() )
return;
m_BMPResData.m_aAttachModels[iAttach].m_pszModelName = ReadAndAllocStringValue( inResourceData, "modelname" );
m_BMPResData.m_aAttachModels[iAttach].m_nSkin = inResourceData->GetInt( "skin", -1 );
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CBaseModelPanel::SetupModelDefaults( void )
{
SetupModelAnimDefaults();
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CBaseModelPanel::SetupModelAnimDefaults( void )
{
// Set the move_x parameter so the run activity works
SetPoseParameterByName( "move_x", 1.0f );
// Verify that we have animations for this model.
int nAnimCount = m_BMPResData.m_aAnimations.Count();
if ( nAnimCount == 0 )
return;
// Find the default animation if one exists.
int iIndex = FindDefaultAnim();
if ( iIndex == -1 )
return;
SetModelAnim( iIndex );
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
int CBaseModelPanel::FindDefaultAnim( void )
{
int iIndex = -1;
int nAnimCount = m_BMPResData.m_aAnimations.Count();
for ( int iAnim = 0; iAnim < nAnimCount; ++iAnim )
{
if ( m_BMPResData.m_aAnimations[iAnim].m_bDefault )
return iAnim;
}
return iIndex;
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
int CBaseModelPanel::FindAnimByName( const char *pszName )
{
int iIndex = -1;
if ( !pszName )
return iIndex;
int nAnimCount = m_BMPResData.m_aAnimations.Count();
for ( int iAnim = 0; iAnim < nAnimCount; ++iAnim )
{
if ( !Q_stricmp( m_BMPResData.m_aAnimations[iAnim].m_pszName, pszName ) )
return iAnim;
}
return iIndex;
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
int CBaseModelPanel::FindSequenceFromActivity( CStudioHdr *pStudioHdr, const char *pszActivity )
{
if ( !pStudioHdr )
return -1;
for ( int iSeq = 0; iSeq < pStudioHdr->GetNumSeq(); ++iSeq )
{
mstudioseqdesc_t &seqDesc = pStudioHdr->pSeqdesc( iSeq );
if ( !V_stricmp( seqDesc.pszActivityName(), pszActivity ) )
{
return iSeq;
}
}
return -1;
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CBaseModelPanel::SetModelAnim( int iAnim )
{
int nAnimCount = m_BMPResData.m_aAnimations.Count();
if ( nAnimCount == 0 || !m_BMPResData.m_aAnimations.IsValidIndex( iAnim ) )
return;
MDLCACHE_CRITICAL_SECTION();
// Get the studio header of the root model.
studiohdr_t *pStudioHdr = m_RootMDL.m_MDL.GetStudioHdr();
if ( !pStudioHdr )
return;
CStudioHdr studioHdr( pStudioHdr, g_pMDLCache );
// Do we have an activity or a sequence?
int iSequence = ACT_INVALID;
if ( m_BMPResData.m_aAnimations[iAnim].m_pszActivity && m_BMPResData.m_aAnimations[iAnim].m_pszActivity[0] )
{
iSequence = FindSequenceFromActivity( &studioHdr, m_BMPResData.m_aAnimations[iAnim].m_pszActivity );
}
else if ( m_BMPResData.m_aAnimations[iAnim].m_pszSequence && m_BMPResData.m_aAnimations[iAnim].m_pszSequence[0] )
{
iSequence = LookupSequence( &studioHdr, m_BMPResData.m_aAnimations[iAnim].m_pszSequence );
}
if ( iSequence != ACT_INVALID )
{
SetSequence( iSequence );
}
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CBaseModelPanel::SetMDL( MDLHandle_t handle, void *pProxyData )
{
MDLCACHE_CRITICAL_SECTION();
studiohdr_t *pHdr = g_pMDLCache->GetStudioHdr( handle );
if ( pHdr )
{
// SetMDL will cause the base CMdl code to set our localtoglobal indices if they aren't set.
// We set them up here so that they're left alone by that code.
CStudioHdr studioHdr( pHdr, g_pMDLCache );
if (studioHdr.numflexcontrollers() > 0 && studioHdr.pFlexcontroller( LocalFlexController_t(0) )->localToGlobal == -1)
{
for (LocalFlexController_t i = LocalFlexController_t(0); i < studioHdr.numflexcontrollers(); i++)
{
int j = C_BaseFlex::AddGlobalFlexController( studioHdr.pFlexcontroller( i )->pszName() );
studioHdr.pFlexcontroller( i )->localToGlobal = j;
}
}
}
else
{
handle = MDLHANDLE_INVALID;
}
// Clear our current sequence
SetSequence( ACT_IDLE );
BaseClass::SetMDL( handle, pProxyData );
SetupModelDefaults();
// Need to invalidate the layout so the panel will adjust is LookAt for the new model.
InvalidateLayout();
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CBaseModelPanel::SetModelAnglesAndPosition( const QAngle &angRot, const Vector &vecPos )
{
BaseClass::SetModelAnglesAndPosition( angRot, vecPos );
// Cache
m_vecPlayerPos = vecPos;
m_angPlayer = angRot;
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CBaseModelPanel::SetMDL( const char *pMDLName, void *pProxyData )
{
BaseClass::SetMDL( pMDLName, pProxyData );
// Need to invalidate the layout so the panel will adjust is LookAt for the new model.
// InvalidateLayout();
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CBaseModelPanel::PerformLayout()
{
BaseClass::PerformLayout();
if ( m_bForcedCameraPosition )
{
return;
}
if ( m_bAllowFullManipulation )
{
// Set this to true if you want to keep the current rotation when changing models or poses
const bool bPreserveManipulation = false;
// Need to look at the target so we can rotate around it
const Vector kVecFocalPoint( 0.0f, 0.0f, 60.0f );
ResetCameraPivot();
SetCameraOffset( -(m_vecPlayerPos + kVecFocalPoint) );
SetCameraPositionAndAngles( kVecFocalPoint, vec3_angle, !bPreserveManipulation );
// We want to move the player to the origin and facing the correct way,
// but don't clobber m_angPlayer and m_vecPlayerPos, so use BaseClass.
BaseClass::SetModelAnglesAndPosition( m_angPlayer, vec3_origin );
// Once a manual transform has been done we want to apply it
if ( m_bApplyManipulators )
{
ApplyManipulation();
}
else
{
SyncManipulation();
}
return;
}
if ( m_bForcePos )
{
ResetCameraPivot();
SetCameraOffset( Vector( 0.0f, 0.0f, 0.0f ) );
SetCameraPositionAndAngles( vec3_origin, vec3_angle );
SetModelAnglesAndPosition( m_angPlayer, m_vecPlayerPos );
}
// Center and fill the frame with the model?
if ( m_bStartFramed )
{
Vector vecBoundsMin, vecBoundsMax;
if ( GetBoundingBox( vecBoundsMin, vecBoundsMax ) )
{
LookAtBounds( vecBoundsMin, vecBoundsMax );
}
}
}
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
void CBaseModelPanel::OnKeyCodePressed ( vgui::KeyCode code )
{
if ( m_bAllowFullManipulation )
{
BaseClass::OnKeyCodePressed( code );
return;
}
}
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
void CBaseModelPanel::OnKeyCodeReleased( vgui::KeyCode code )
{
if ( m_bAllowFullManipulation )
{
BaseClass::OnKeyCodeReleased( code );
return;
}
}
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
void CBaseModelPanel::OnMousePressed ( vgui::MouseCode code )
{
if ( m_bAllowFullManipulation )
{
BaseClass::OnMousePressed( code );
return;
}
if ( !m_bAllowRotation )
return;
RequestFocus();
EnableMouseCapture( true, code );
// Warp the mouse to the center of the screen
int width, height;
GetSize( width, height );
int x = width / 2;
int y = height / 2;
int xpos = x;
int ypos = y;
LocalToScreen( xpos, ypos );
input()->SetCursorPos( xpos, ypos );
m_nManipStartX = xpos;
m_nManipStartY = ypos;
m_bMousePressed = true;
}
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
void CBaseModelPanel::OnMouseReleased( vgui::MouseCode code )
{
if ( m_bAllowFullManipulation )
{
BaseClass::OnMouseReleased( code );
return;
}
if ( !m_bAllowRotation )
return;
EnableMouseCapture( false );
m_bMousePressed = false;
}
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
void CBaseModelPanel::OnCursorMoved( int x, int y )
{
if ( m_bAllowFullManipulation )
{
if ( m_pCurrentManip )
{
m_bApplyManipulators = true;
}
BaseClass::OnCursorMoved( x, y );
return;
}
if ( !m_bAllowRotation )
return;
if ( m_bMousePressed )
{
WarpMouse( x, y );
int xpos, ypos;
input()->GetCursorPos( xpos, ypos );
// Only want the x delta.
float flDelta = xpos - m_nManipStartX;
// Apply the delta and rotate the player.
RotateYaw( flDelta );
}
}
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
void CBaseModelPanel::RotateYaw( float flDelta )
{
m_angPlayer.y += flDelta;
if ( m_angPlayer.y > 360.0f )
{
m_angPlayer.y = m_angPlayer.y - 360.0f;
}
else if ( m_angPlayer.y < -360.0f )
{
m_angPlayer.y = m_angPlayer.y + 360.0f;
}
SetModelAnglesAndPosition( m_angPlayer, m_vecPlayerPos );
}
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
Vector CBaseModelPanel::GetPlayerPos() const
{
return m_vecPlayerPos;
}
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
QAngle CBaseModelPanel::GetPlayerAngles() const
{
return m_angPlayer;
}
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
void CBaseModelPanel::OnMouseWheeled( int delta )
{
if ( m_bAllowFullManipulation )
{
BaseClass::OnMouseWheeled( delta );
return;
}
}
//-----------------------------------------------------------------------------
// Purpose: Set the camera to a distance that allows the object to fill the model panel.
//-----------------------------------------------------------------------------
void CBaseModelPanel::LookAtBounds( const Vector &vecBoundsMin, const Vector &vecBoundsMax )
{
// Get the model space render bounds.
Vector vecMin = vecBoundsMin;
Vector vecMax = vecBoundsMax;
Vector vecCenter = ( vecMax + vecMin ) * 0.5f;
vecMin -= vecCenter;
vecMax -= vecCenter;
// Get the bounds points and transform them by the desired model panel rotation.
Vector aBoundsPoints[8];
aBoundsPoints[0].Init( vecMax.x, vecMax.y, vecMax.z );
aBoundsPoints[1].Init( vecMin.x, vecMax.y, vecMax.z );
aBoundsPoints[2].Init( vecMax.x, vecMin.y, vecMax.z );
aBoundsPoints[3].Init( vecMin.x, vecMin.y, vecMax.z );
aBoundsPoints[4].Init( vecMax.x, vecMax.y, vecMin.z );
aBoundsPoints[5].Init( vecMin.x, vecMax.y, vecMin.z );
aBoundsPoints[6].Init( vecMax.x, vecMin.y, vecMin.z );
aBoundsPoints[7].Init( vecMin.x, vecMin.y, vecMin.z );
// Translated center point (offset from camera center).
Vector vecTranslateCenter = -vecCenter;
// Build the rotation matrix.
matrix3x4_t matRotation;
AngleMatrix( m_BMPResData.m_angModelPoseRot, matRotation );
Vector aXFormPoints[8];
for ( int iPoint = 0; iPoint < 8; ++iPoint )
{
VectorTransform( aBoundsPoints[iPoint], matRotation, aXFormPoints[iPoint] );
}
Vector vecXFormCenter;
VectorTransform( -vecTranslateCenter, matRotation, vecXFormCenter );
int w, h;
GetSize( w, h );
float flW = (float)w;
float flH = (float)h;
float flFOVx = DEG2RAD( m_BMPResData.m_flFOV * 0.5f );
float flFOVy = CalcFovY( ( m_BMPResData.m_flFOV * 0.5f ), flW/flH );
flFOVy = DEG2RAD( flFOVy );
float flTanFOVx = tan( flFOVx );
float flTanFOVy = tan( flFOVy );
// Find the max value of x, y, or z
Vector2D dist[8];
float flDist = 0.0f;
for ( int iPoint = 0; iPoint < 8; ++iPoint )
{
float flDistY = fabs( aXFormPoints[iPoint].y / flTanFOVx ) - aXFormPoints[iPoint].x;
float flDistZ = fabs( aXFormPoints[iPoint].z / flTanFOVy ) - aXFormPoints[iPoint].x;
dist[iPoint].x = flDistY;
dist[iPoint].y = flDistZ;
float flTestDist = MAX( flDistZ, flDistY );
flDist = MAX( flDist, flTestDist );
}
// Screen space points.
Vector2D aScreenPoints[8];
Vector aCameraPoints[8];
for ( int iPoint = 0; iPoint < 8; ++iPoint )
{
aCameraPoints[iPoint] = aXFormPoints[iPoint];
aCameraPoints[iPoint].x += flDist;
aScreenPoints[iPoint].x = aCameraPoints[iPoint].y / ( flTanFOVx * aCameraPoints[iPoint].x );
aScreenPoints[iPoint].y = aCameraPoints[iPoint].z / ( flTanFOVy * aCameraPoints[iPoint].x );
aScreenPoints[iPoint].x = ( aScreenPoints[iPoint].x * 0.5f + 0.5f ) * flW;
aScreenPoints[iPoint].y = ( aScreenPoints[iPoint].y * 0.5f + 0.5f ) * flH;
}
// Find the min/max and center of the 2D bounding box of the object.
Vector2D vecScreenMin( 99999.0f, 99999.0f ), vecScreenMax( -99999.0f, -99999.0f );
for ( int iPoint = 0; iPoint < 8; ++iPoint )
{
vecScreenMin.x = MIN( vecScreenMin.x, aScreenPoints[iPoint].x );
vecScreenMin.y = MIN( vecScreenMin.y, aScreenPoints[iPoint].y );
vecScreenMax.x = MAX( vecScreenMax.x, aScreenPoints[iPoint].x );
vecScreenMax.y = MAX( vecScreenMax.y, aScreenPoints[iPoint].y );
}
// Offset the model to the be the correct distance away from the camera.
Vector vecModelPos;
vecModelPos.x = flDist - vecXFormCenter.x;
vecModelPos.y = -vecXFormCenter.y;
vecModelPos.z = -vecXFormCenter.z;
SetModelAnglesAndPosition( m_BMPResData.m_angModelPoseRot, vecModelPos );
m_vecPlayerPos = vecModelPos;
// Back project to figure out the camera offset to center the model.
Vector2D vecPanelCenter( ( flW * 0.5f ), ( flH * 0.5f ) );
Vector2D vecScreenCenter = ( vecScreenMax + vecScreenMin ) * 0.5f;
Vector2D vecPanelCenterCamera, vecScreenCenterCamera;
vecPanelCenterCamera.x = ( ( vecPanelCenter.x / flW ) * 2.0f ) - 0.5f;
vecPanelCenterCamera.y = ( ( vecPanelCenter.y / flH ) * 2.0f ) - 0.5f;
vecPanelCenterCamera.x *= ( flTanFOVx * flDist );
vecPanelCenterCamera.y *= ( flTanFOVy * flDist );
vecScreenCenterCamera.x = ( ( vecScreenCenter.x / flW ) * 2.0f ) - 0.5f;
vecScreenCenterCamera.y = ( ( vecScreenCenter.y / flH ) * 2.0f ) - 0.5f;
vecScreenCenterCamera.x *= ( flTanFOVx * flDist );
vecScreenCenterCamera.y *= ( flTanFOVy * flDist );
Vector2D vecCameraOffset( 0.0f, 0.0f );
vecCameraOffset.x = vecPanelCenterCamera.x - vecScreenCenterCamera.x;
vecCameraOffset.y = vecPanelCenterCamera.y - vecScreenCenterCamera.y;
// Clear the camera pivot and set position matrix.
ResetCameraPivot();
if (m_bAllowRotation )
{
vecCameraOffset.x = 0.0f;
}
SetCameraOffset( Vector( 0.0f, -vecCameraOffset.x, -vecCameraOffset.y ) );
UpdateCameraTransform();
}

View File

@@ -0,0 +1,225 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
//=============================================================================
#ifndef BASEMODEL_PANEL_H
#define BASEMODEL_PANEL_H
#ifdef _WIN32
#pragma once
#endif
#include "matsys_controls/mdlpanel.h"
//-----------------------------------------------------------------------------
// Resource file data used in posing the model inside of the model panel.
//-----------------------------------------------------------------------------
struct BMPResAnimData_t
{
const char *m_pszName;
const char *m_pszSequence;
const char *m_pszActivity;
KeyValues *m_pPoseParameters;
bool m_bDefault;
BMPResAnimData_t()
{
m_pszName = NULL;
m_pszSequence = NULL;
m_pszActivity = NULL;
m_pPoseParameters = NULL;
m_bDefault = false;
}
~BMPResAnimData_t()
{
if ( m_pszName && m_pszName[0] )
{
delete [] m_pszName;
m_pszName = NULL;
}
if ( m_pszSequence && m_pszSequence[0] )
{
delete [] m_pszSequence;
m_pszSequence = NULL;
}
if ( m_pszActivity && m_pszActivity[0] )
{
delete [] m_pszActivity;
m_pszActivity = NULL;
}
if ( m_pPoseParameters )
{
m_pPoseParameters->deleteThis();
m_pPoseParameters = NULL;
}
}
};
struct BMPResAttachData_t
{
const char *m_pszModelName;
int m_nSkin;
BMPResAttachData_t()
{
m_pszModelName = NULL;
m_nSkin = 0;
}
~BMPResAttachData_t()
{
if ( m_pszModelName && m_pszModelName[0] )
{
delete [] m_pszModelName;
m_pszModelName = NULL;
}
}
};
struct BMPResData_t
{
float m_flFOV;
const char *m_pszModelName;
const char *m_pszModelName_HWM;
const char *m_pszVCD;
QAngle m_angModelPoseRot;
Vector m_vecOriginOffset;
Vector m_vecFramedOriginOffset;
Vector2D m_vecViewportOffset;
int m_nSkin;
bool m_bUseSpotlight;
CUtlVector<BMPResAnimData_t> m_aAnimations;
CUtlVector<BMPResAttachData_t> m_aAttachModels;
BMPResData_t()
{
m_flFOV = 0.0f;
m_pszModelName = NULL;
m_pszModelName_HWM = NULL;
m_pszVCD = NULL;
m_angModelPoseRot.Init();
m_vecOriginOffset.Init();
m_vecFramedOriginOffset.Init();
m_vecViewportOffset.Init();
m_nSkin = 0;
m_bUseSpotlight = false;
}
~BMPResData_t()
{
if ( m_pszModelName && m_pszModelName[0] )
{
delete [] m_pszModelName;
m_pszModelName = NULL;
}
if ( m_pszModelName_HWM && m_pszModelName_HWM[0] )
{
delete [] m_pszModelName_HWM;
m_pszModelName_HWM = NULL;
}
if ( m_pszVCD && m_pszVCD[0] )
{
delete [] m_pszVCD;
m_pszVCD = NULL;
}
m_aAnimations.Purge();
m_aAttachModels.Purge();
}
};
//-----------------------------------------------------------------------------
// Base Model Panel
//
// ...vgui::Panel |--> vgui
// +->vgui::EditablePanel |
// +->PotterWheelPanel |--> matsys_controls
// +->MDLPanel |
// +->BaseModelPanel |--> game_controls, client.dll
//
//-----------------------------------------------------------------------------
class CBaseModelPanel : public CMDLPanel
{
DECLARE_CLASS_SIMPLE( CBaseModelPanel, CMDLPanel );
public:
// Constructor, Destructor.
CBaseModelPanel( vgui::Panel *pParent, const char *pName );
virtual ~CBaseModelPanel();
// Overridden mdlpanel.h
virtual void SetMDL( MDLHandle_t handle, void *pProxyData = NULL );
virtual void SetMDL( const char *pMDLName, void *pProxyData = NULL );
virtual void SetModelAnglesAndPosition( const QAngle &angRot, const Vector &vecPos );
// Overridden methods of vgui::Panel
virtual void ApplySettings( KeyValues *inResourceData );
virtual void PerformLayout();
// Animation.
int FindDefaultAnim( void );
int FindAnimByName( const char *pszName );
void SetModelAnim( int iAnim );
// Manipulation.
virtual void OnKeyCodePressed ( vgui::KeyCode code );
virtual void OnKeyCodeReleased( vgui::KeyCode code );
virtual void OnMousePressed ( vgui::MouseCode code );
virtual void OnMouseReleased( vgui::MouseCode code );
virtual void OnCursorMoved( int x, int y );
virtual void OnMouseWheeled( int delta );
studiohdr_t* GetStudioHdr( void ) { return m_RootMDL.m_MDL.GetStudioHdr(); }
void SetBody( unsigned int nBody ) { m_RootMDL.m_MDL.m_nBody = nBody; }
void RotateYaw( float flDelta );
Vector GetPlayerPos() const;
QAngle GetPlayerAngles() const;
void LookAtBounds( const Vector &vecBoundsMin, const Vector &vecBoundsMax );
// Set to true if external code has set a specific camera position that shouldn't be clobbered by layout
void SetForcedCameraPosition( bool bForcedCameraPosition ) { m_bForcedCameraPosition = bForcedCameraPosition; }
int FindSequenceFromActivity( CStudioHdr *pStudioHdr, const char *pszActivity );
protected:
// Resource file data.
void ParseModelResInfo( KeyValues *inResourceData );
void ParseModelAnimInfo( KeyValues *inResourceData );
void ParseModelAttachInfo( KeyValues *inResourceData );
void SetupModelDefaults( void );
void SetupModelAnimDefaults( void );
public:
BMPResData_t m_BMPResData; // Base model panel data set in the .res file.
QAngle m_angPlayer;
Vector m_vecPlayerPos;
protected:
bool m_bForcePos;
bool m_bMousePressed;
bool m_bAllowRotation;
bool m_bAllowFullManipulation;
bool m_bApplyManipulators;
bool m_bForcedCameraPosition;
// VGUI script accessible variables.
CPanelAnimationVar( bool, m_bStartFramed, "start_framed", "0" );
CPanelAnimationVar( bool, m_bDisableManipulation, "disable_manipulation", "0" );
};
#endif // BASEMODEL_PANEL_H

View File

@@ -0,0 +1,898 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
//=============================================================================//
#include "cbase.h"
#include <KeyValues.h>
#include <vgui/ISurface.h>
#include <vgui/ISystem.h>
#include <vgui/IScheme.h>
#include <vgui_controls/AnimationController.h>
#include <vgui_controls/EditablePanel.h>
#include <vgui_controls/ImagePanel.h>
#include <vgui/ISurface.h>
#include <vgui/IImage.h>
#include <vgui_controls/Label.h>
#include "materialsystem/imaterialsystem.h"
#include "engine/ivmodelinfo.h"
#include "c_sceneentity.h"
#include "gamestringpool.h"
#include "model_types.h"
#include "view_shared.h"
#include "view.h"
#include "ivrenderview.h"
#include "iefx.h"
#include "dlight.h"
#include "activitylist.h"
#include "basemodelpanel.h"
bool UseHWMorphModels();
using namespace vgui;
DECLARE_BUILD_FACTORY( CModelPanel );
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
CModelPanel::CModelPanel( vgui::Panel *pParent, const char *pName ) : vgui::EditablePanel( pParent, pName )
{
m_nFOV = 54;
m_hModel = NULL;
m_pModelInfo = NULL;
m_hScene = NULL;
m_iDefaultAnimation = 0;
m_bPanelDirty = true;
m_bStartFramed = false;
m_bAllowOffscreen = false;
ListenForGameEvent( "game_newmap" );
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
CModelPanel::~CModelPanel()
{
if ( m_pModelInfo )
{
delete m_pModelInfo;
m_pModelInfo = NULL;
}
DeleteVCDData();
DeleteModelData();
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CModelPanel::ApplySettings( KeyValues *inResourceData )
{
BaseClass::ApplySettings( inResourceData );
m_nFOV = inResourceData->GetInt( "fov", 54 );
m_bStartFramed = inResourceData->GetInt( "start_framed", false );
m_bAllowOffscreen = inResourceData->GetInt( "allow_offscreen", false );
// do we have a valid "model" section in the .res file?
for ( KeyValues *pData = inResourceData->GetFirstSubKey() ; pData != NULL ; pData = pData->GetNextKey() )
{
if ( !Q_stricmp( pData->GetName(), "model" ) )
{
ParseModelInfo( pData );
}
}
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CModelPanel::ParseModelInfo( KeyValues *inResourceData )
{
// delete any current info
if ( m_pModelInfo )
{
delete m_pModelInfo;
m_pModelInfo = NULL;
}
m_pModelInfo = new CModelPanelModelInfo;
if ( !m_pModelInfo )
return;
m_pModelInfo->m_pszModelName = ReadAndAllocStringValue( inResourceData, "modelname" );
m_pModelInfo->m_pszModelName_HWM = ReadAndAllocStringValue( inResourceData, "modelname_hwm" );
m_pModelInfo->m_nSkin = inResourceData->GetInt( "skin", -1 );
m_pModelInfo->m_vecAbsAngles.Init( inResourceData->GetFloat( "angles_x", 0.0 ), inResourceData->GetFloat( "angles_y", 0.0 ), inResourceData->GetFloat( "angles_z", 0.0 ) );
m_pModelInfo->m_vecOriginOffset.Init( inResourceData->GetFloat( "origin_x", 110.0 ), inResourceData->GetFloat( "origin_y", 5.0 ), inResourceData->GetFloat( "origin_z", 5.0 ) );
m_pModelInfo->m_vecFramedOriginOffset.Init( inResourceData->GetFloat( "frame_origin_x", 110.0 ), inResourceData->GetFloat( "frame_origin_y", 5.0 ), inResourceData->GetFloat( "frame_origin_z", 5.0 ) );
m_pModelInfo->m_pszVCD = ReadAndAllocStringValue( inResourceData, "vcd" );
m_pModelInfo->m_bUseSpotlight = ( inResourceData->GetInt( "spotlight", 0 ) == 1 );
m_pModelInfo->m_vecViewportOffset.Init();
for ( KeyValues *pData = inResourceData->GetFirstSubKey(); pData != NULL; pData = pData->GetNextKey() )
{
if ( !Q_stricmp( pData->GetName(), "animation" ) )
{
OnAddAnimation( pData );
}
else if ( !Q_stricmp( pData->GetName(), "attached_model" ) )
{
CModelPanelAttachedModelInfo *pAttachedModelInfo = new CModelPanelAttachedModelInfo;
if ( pAttachedModelInfo )
{
pAttachedModelInfo->m_pszModelName = ReadAndAllocStringValue( pData, "modelname" );
pAttachedModelInfo->m_nSkin = pData->GetInt( "skin", -1 );
m_pModelInfo->m_AttachedModelsInfo.AddToTail( pAttachedModelInfo );
}
}
}
m_bPanelDirty = true;
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CModelPanel::OnAddAnimation( KeyValues *pData )
{
if ( !pData )
return;
CModelPanelModelAnimation *pAnimation = new CModelPanelModelAnimation;
if ( pAnimation )
{
pAnimation->m_pszName = ReadAndAllocStringValue( pData, "name" );
pAnimation->m_pszSequence = ReadAndAllocStringValue( pData, "sequence" );
pAnimation->m_pszActivity = ReadAndAllocStringValue( pData, "activity" );
pAnimation->m_bDefault = ( pData->GetInt( "default", 0 ) == 1 );
for ( KeyValues *pAnimData = pData->GetFirstSubKey(); pAnimData != NULL; pAnimData = pAnimData->GetNextKey() )
{
if ( !Q_stricmp( pAnimData->GetName(), "pose_parameters" ) )
{
pAnimation->m_pPoseParameters = pAnimData->MakeCopy();
}
}
m_pModelInfo->m_Animations.AddToTail( pAnimation );
if ( pAnimation->m_bDefault )
{
m_iDefaultAnimation = m_pModelInfo->m_Animations.Find( pAnimation );
}
}
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CModelPanel::FireGameEvent( IGameEvent * event )
{
const char *type = event->GetName();
if ( Q_strcmp( type, "game_newmap" ) == 0 )
{
// force the models to re-setup themselves
m_bPanelDirty = true;
}
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CModelPanel::SetDefaultAnimation( const char *pszName )
{
if ( m_pModelInfo )
{
for ( int i = 0; i < m_pModelInfo->m_Animations.Count(); i++ )
{
if ( m_pModelInfo->m_Animations[i] && m_pModelInfo->m_Animations[i]->m_pszName )
{
if ( !Q_stricmp( m_pModelInfo->m_Animations[i]->m_pszName, pszName ) )
{
m_iDefaultAnimation = i;
return;
}
}
}
}
Assert( 0 );
}
//-----------------------------------------------------------------------------
// Purpose: Replaces the current model with a new one, without changing the camera settings
//-----------------------------------------------------------------------------
void CModelPanel::SwapModel( const char *pszName, const char *pszAttached )
{
if ( !m_pModelInfo || !pszName || !pszName[0] )
return;
int len = Q_strlen( pszName ) + 1;
char *pAlloced = new char[ len ];
Assert( pAlloced );
Q_strncpy( pAlloced, pszName, len );
m_pModelInfo->m_pszModelName = pAlloced;
ClearAttachedModelInfos();
if ( pszAttached )
{
CModelPanelAttachedModelInfo *pAttachedModelInfo = new CModelPanelAttachedModelInfo;
if ( pAttachedModelInfo )
{
len = Q_strlen( pszAttached ) + 1;
pAlloced = new char[ len ];
Assert( pAlloced );
Q_strncpy( pAlloced, pszAttached, len );
pAttachedModelInfo->m_pszModelName = pAlloced;
pAttachedModelInfo->m_nSkin = 0;
m_pModelInfo->m_AttachedModelsInfo.AddToTail( pAttachedModelInfo );
}
}
m_bPanelDirty = true;
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CModelPanel::DeleteVCDData( void )
{
if ( m_hScene.Get() )
{
m_hScene->StopClientOnlyScene();
m_hScene->Remove();
m_hScene = NULL;
}
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CModelPanel::SetupVCD( void )
{
if ( !m_pModelInfo )
return;
DeleteVCDData();
C_SceneEntity *pEnt = new class C_SceneEntity;
if ( !pEnt )
return;
if ( pEnt->InitializeAsClientEntity( "", RENDER_GROUP_OTHER ) == false )
{
// we failed to initialize this entity so just return gracefully
pEnt->Remove();
return;
}
// setup the handle
m_hScene = pEnt;
// setup the scene
pEnt->SetupClientOnlyScene( m_pModelInfo->m_pszVCD, m_hModel, true );
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CModelPanel::ClearAttachedModelInfos( void )
{
if ( m_pModelInfo )
{
m_pModelInfo->m_AttachedModelsInfo.PurgeAndDeleteElements();
}
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CModelPanel::DeleteModelData( void )
{
if ( m_hModel.Get() )
{
m_hModel->Remove();
m_hModel = NULL;
m_flFrameDistance = 0;
}
for ( int i = 0 ; i < m_AttachedModels.Count() ; i++ )
{
if ( m_AttachedModels[i].Get() )
{
m_AttachedModels[i]->Remove();
}
m_AttachedModels.Remove( i );
}
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
const char *CModelPanel::GetModelName( void )
{
if ( !m_pModelInfo )
return NULL;
// check to see if we want to use a HWM model
if ( UseHWMorphModels() )
{
// do we have a valid HWM model filename
if ( m_pModelInfo->m_pszModelName_HWM && ( Q_strlen( m_pModelInfo->m_pszModelName_HWM ) > 0 ) )
{
// does the file exist
model_t *pModel = (model_t *)engine->LoadModel( m_pModelInfo->m_pszModelName_HWM );
if ( pModel )
{
return m_pModelInfo->m_pszModelName_HWM;
}
}
}
return m_pModelInfo->m_pszModelName;
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CModelPanel::SetupModel( void )
{
if ( !m_pModelInfo )
return;
MDLCACHE_CRITICAL_SECTION();
// remove any current models we're using
DeleteModelData();
const char *pszModelName = GetModelName();
if ( !pszModelName || !pszModelName[0] )
return;
// create the new model
CModelPanelModel *pEnt = new CModelPanelModel;
if ( !pEnt )
return;
if ( pEnt->InitializeAsClientEntity( pszModelName, RENDER_GROUP_OPAQUE_ENTITY ) == false )
{
// we failed to initialize this entity so just return gracefully
pEnt->Remove();
return;
}
// setup the handle
m_hModel = pEnt;
pEnt->DontRecordInTools();
pEnt->AddEffects( EF_NODRAW ); // don't let the renderer draw the model normally
if ( m_pModelInfo->m_nSkin >= 0 )
{
pEnt->m_nSkin = m_pModelInfo->m_nSkin;
}
// do we have any animation information?
if ( m_pModelInfo->m_Animations.Count() > 0 && m_pModelInfo->m_Animations.IsValidIndex( m_iDefaultAnimation ) )
{
CModelPanelModelAnimation *pAnim = m_pModelInfo->m_Animations[ m_iDefaultAnimation ];
int sequence = ACT_INVALID;
if ( pAnim->m_pszActivity && pAnim->m_pszActivity[0] )
{
Activity activity = (Activity)ActivityList_IndexForName( pAnim->m_pszActivity );
sequence = pEnt->SelectWeightedSequence( activity );
}
else if ( pAnim->m_pszSequence && pAnim->m_pszSequence[0] )
{
sequence = pEnt->LookupSequence( pAnim->m_pszSequence );
}
if ( sequence != ACT_INVALID )
{
pEnt->ResetSequence( sequence );
pEnt->SetCycle( 0 );
if ( pAnim->m_pPoseParameters )
{
for ( KeyValues *pData = pAnim->m_pPoseParameters->GetFirstSubKey(); pData != NULL; pData = pData->GetNextKey() )
{
const char *pName = pData->GetName();
float flValue = pData->GetFloat();
pEnt->SetPoseParameter( pName, flValue );
}
}
pEnt->m_flAnimTime = gpGlobals->curtime;
}
}
// setup any attached models
for ( int i = 0 ; i < m_pModelInfo->m_AttachedModelsInfo.Count() ; i++ )
{
CModelPanelAttachedModelInfo *pInfo = m_pModelInfo->m_AttachedModelsInfo[i];
C_BaseAnimating *pTemp = new C_BaseAnimating;
if ( pTemp )
{
if ( pTemp->InitializeAsClientEntity( pInfo->m_pszModelName, RENDER_GROUP_OPAQUE_ENTITY ) == false )
{
// we failed to initialize this model so just skip it
pTemp->Remove();
continue;
}
pTemp->DontRecordInTools();
pTemp->AddEffects( EF_NODRAW ); // don't let the renderer draw the model normally
pTemp->FollowEntity( m_hModel.Get() ); // attach to parent model
if ( pInfo->m_nSkin >= 0 )
{
pTemp->m_nSkin = pInfo->m_nSkin;
}
pTemp->m_flAnimTime = gpGlobals->curtime;
m_AttachedModels.AddToTail( pTemp );
}
}
CalculateFrameDistance();
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CModelPanel::InitCubeMaps()
{
ITexture *pCubemapTexture;
// Deal with the default cubemap
if ( g_pMaterialSystemHardwareConfig->GetHDREnabled() )
{
pCubemapTexture = materials->FindTexture( "editor/cubemap.hdr", NULL, true );
m_DefaultHDREnvCubemap.Init( pCubemapTexture );
}
else
{
pCubemapTexture = materials->FindTexture( "editor/cubemap", NULL, true );
m_DefaultEnvCubemap.Init( pCubemapTexture );
}
}
//-----------------------------------------------------------------------------
// Purpose: If the panel is marked as dirty, update it and mark it as clean
//-----------------------------------------------------------------------------
void CModelPanel::UpdateModel()
{
if ( m_bPanelDirty )
{
InitCubeMaps();
SetupModel();
// are we trying to play a VCD?
if ( Q_strlen( m_pModelInfo->m_pszVCD ) > 0 )
{
SetupVCD();
}
m_bPanelDirty = false;
}
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CModelPanel::Paint()
{
BaseClass::Paint();
C_BasePlayer *pLocalPlayer = C_BasePlayer::GetLocalPlayer();
if ( !pLocalPlayer || !m_pModelInfo )
return;
MDLCACHE_CRITICAL_SECTION();
UpdateModel();
if ( !m_hModel.Get() )
return;
int i = 0;
int x, y, w, h;
GetBounds( x, y, w, h );
ParentLocalToScreen( x, y );
if ( !m_bAllowOffscreen && x < 0 )
{
// prevent x from being pushed off the left side of the screen
// for modes like 1280 x 1024 (prevents model from being drawn in the panel)
x = 0;
}
Vector vecExtraModelOffset( 0, 0, 0 );
float flWidthRatio = ((float)w / (float)h ) / ( 4.0f / 3.0f );
// is this a player model?
if ( Q_strstr( GetModelName(), "models/player/" ) )
{
// need to know if the ratio is not 4/3
// HACK! HACK! to get our player models to appear the way they do in 4/3 if we're using other aspect ratios
if ( flWidthRatio > 1.05f )
{
vecExtraModelOffset.Init( -60, 0, 0 );
}
else if ( flWidthRatio < 0.95f )
{
vecExtraModelOffset.Init( 15, 0, 0 );
}
}
m_hModel->SetAbsOrigin( m_pModelInfo->m_vecOriginOffset + vecExtraModelOffset );
m_hModel->SetAbsAngles( QAngle( m_pModelInfo->m_vecAbsAngles.x, m_pModelInfo->m_vecAbsAngles.y, m_pModelInfo->m_vecAbsAngles.z ) );
// do we have a valid sequence?
if ( m_hModel->GetSequence() != -1 )
{
m_hModel->FrameAdvance( gpGlobals->frametime );
}
CMatRenderContextPtr pRenderContext( materials );
// figure out what our viewport is right now
int viewportX, viewportY, viewportWidth, viewportHeight;
pRenderContext->GetViewport( viewportX, viewportY, viewportWidth, viewportHeight );
// Now draw it.
CViewSetup view;
view.x = x + m_pModelInfo->m_vecViewportOffset.x + viewportX; // we actually want to offset by the
view.y = y + m_pModelInfo->m_vecViewportOffset.y + viewportY; // viewport origin here because Push3DView expects global coords below
view.width = w;
view.height = h;
view.m_bOrtho = false;
// scale the FOV for aspect ratios other than 4/3
view.fov = ScaleFOVByWidthRatio( m_nFOV, flWidthRatio );
view.origin = vec3_origin;
view.angles.Init();
view.zNear = VIEW_NEARZ;
view.zFar = 1000;
// Not supported by queued material system - doesn't appear to be necessary
// ITexture *pLocalCube = pRenderContext->GetLocalCubemap();
if ( g_pMaterialSystemHardwareConfig->GetHDREnabled() )
{
pRenderContext->BindLocalCubemap( m_DefaultHDREnvCubemap );
}
else
{
pRenderContext->BindLocalCubemap( m_DefaultEnvCubemap );
}
pRenderContext->SetLightingOrigin( vec3_origin );
pRenderContext->SetAmbientLight( 0.4, 0.4, 0.4 );
static Vector white[6] =
{
Vector( 0.4, 0.4, 0.4 ),
Vector( 0.4, 0.4, 0.4 ),
Vector( 0.4, 0.4, 0.4 ),
Vector( 0.4, 0.4, 0.4 ),
Vector( 0.4, 0.4, 0.4 ),
Vector( 0.4, 0.4, 0.4 ),
};
g_pStudioRender->SetAmbientLightColors( white );
g_pStudioRender->SetLocalLights( 0, NULL );
if ( m_pModelInfo->m_bUseSpotlight )
{
Vector vecMins, vecMaxs;
m_hModel->GetRenderBounds( vecMins, vecMaxs );
LightDesc_t spotLight( vec3_origin + Vector( 0, 0, 200 ), Vector( 1, 1, 1 ), m_hModel->GetAbsOrigin() + Vector( 0, 0, ( vecMaxs.z - vecMins.z ) * 0.75 ), 0.035, 0.873 );
g_pStudioRender->SetLocalLights( 1, &spotLight );
}
Frustum dummyFrustum;
render->Push3DView( view, 0, NULL, dummyFrustum );
modelrender->SuppressEngineLighting( true );
float color[3] = { 1.0f, 1.0f, 1.0f };
render->SetColorModulation( color );
render->SetBlend( 1.0f );
m_hModel->DrawModel( STUDIO_RENDER );
for ( i = 0 ; i < m_AttachedModels.Count() ; i++ )
{
if ( m_AttachedModels[i].Get() )
{
m_AttachedModels[i]->DrawModel( STUDIO_RENDER );
}
}
modelrender->SuppressEngineLighting( false );
render->PopView( dummyFrustum );
pRenderContext->BindLocalCubemap( NULL );
/*
vgui::surface()->DrawSetColor( Color(0,0,0,255) );
vgui::surface()->DrawOutlinedRect( 0,0, GetWide(), GetTall() );
*/
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
int CModelPanel::FindAnimByName( const char *pszName )
{
// first try to find the sequence using pszName as the friendly name
for ( int iIndex = 0 ; iIndex < m_pModelInfo->m_Animations.Count() ; iIndex++ )
{
CModelPanelModelAnimation *pAnimation = m_pModelInfo->m_Animations[ iIndex ];
if ( FStrEq( pAnimation->m_pszName, pszName ) )
return iIndex;
}
return -1;
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
bool CModelPanel::SetSequence( const char *pszName )
{
bool bRetVal = false;
const char *pszAnim = NULL;
MDLCACHE_CRITICAL_SECTION();
if ( m_pModelInfo )
{
int iIndex = FindAnimByName(pszName);
if ( iIndex != -1 )
{
pszAnim = m_pModelInfo->m_Animations[iIndex]->m_pszSequence;
}
else
{
// if not, just use the passed name as the sequence
pszAnim = pszName;
}
if ( m_hModel.Get() )
{
int sequence = m_hModel->LookupSequence( pszAnim );
if ( sequence != ACT_INVALID )
{
m_hModel->ResetSequence( sequence );
m_hModel->SetCycle( 0 );
bRetVal = true;
}
}
}
return bRetVal;
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CModelPanel::OnSetAnimation( KeyValues *data )
{
UpdateModel();
// If there's no model, these commands will be ignored.
Assert(m_hModel);
if ( data )
{
const char *pszAnimation = data->GetString( "animation", "" );
const char *pszActivity = data->GetString( "activity", "" );
if ( pszActivity && pszActivity[0] )
{
if ( m_hModel )
{
int iIndex = FindAnimByName(pszActivity);
if ( iIndex != -1 )
{
pszActivity = m_pModelInfo->m_Animations[iIndex]->m_pszActivity;
}
Activity activity = (Activity)ActivityList_IndexForName( pszActivity );
int sequence = m_hModel->SelectWeightedSequence( activity );
if ( sequence != ACT_INVALID )
{
m_hModel->ResetSequence( sequence );
m_hModel->SetCycle( 0 );
}
}
}
else
{
SetSequence( pszAnimation );
}
}
}
void CModelPanel::CalculateFrameDistanceInternal( const model_t *pModel )
{
// Get the model space render bounds.
Vector vecMin, vecMax;
modelinfo->GetModelRenderBounds( pModel, vecMin, vecMax );
Vector vecCenter = ( vecMax + vecMin ) * 0.5f;
vecMin -= vecCenter;
vecMax -= vecCenter;
// Get the bounds points and transform them by the desired model panel rotation.
Vector aBoundsPoints[8];
aBoundsPoints[0].Init( vecMax.x, vecMax.y, vecMax.z );
aBoundsPoints[1].Init( vecMin.x, vecMax.y, vecMax.z );
aBoundsPoints[2].Init( vecMax.x, vecMin.y, vecMax.z );
aBoundsPoints[3].Init( vecMin.x, vecMin.y, vecMax.z );
aBoundsPoints[4].Init( vecMax.x, vecMax.y, vecMin.z );
aBoundsPoints[5].Init( vecMin.x, vecMax.y, vecMin.z );
aBoundsPoints[6].Init( vecMax.x, vecMin.y, vecMin.z );
aBoundsPoints[7].Init( vecMin.x, vecMin.y, vecMin.z );
// Translated center point (offset from camera center).
Vector vecTranslateCenter = -vecCenter;
// Build the rotation matrix.
QAngle angPanelAngles( m_pModelInfo->m_vecAbsAngles.x, m_pModelInfo->m_vecAbsAngles.y, m_pModelInfo->m_vecAbsAngles.z );
matrix3x4_t matRotation;
AngleMatrix( angPanelAngles, matRotation );
Vector aXFormPoints[8];
for ( int iPoint = 0; iPoint < 8; ++iPoint )
{
VectorTransform( aBoundsPoints[iPoint], matRotation, aXFormPoints[iPoint] );
}
Vector vecXFormCenter;
VectorTransform( -vecTranslateCenter, matRotation, vecXFormCenter );
int w, h;
GetSize( w, h );
float flW = (float)w;
float flH = (float)h;
float flFOVx = DEG2RAD( m_nFOV * 0.5f );
float flFOVy = CalcFovY( ( m_nFOV * 0.5f ), flW/flH );
flFOVy = DEG2RAD( flFOVy );
float flTanFOVx = tan( flFOVx );
float flTanFOVy = tan( flFOVy );
// Find the max value of x, y, or z
float flDist = 0.0f;
for ( int iPoint = 0; iPoint < 8; ++iPoint )
{
float flDistZ = fabs( aXFormPoints[iPoint].z / flTanFOVy - aXFormPoints[iPoint].x );
float flDistY = fabs( aXFormPoints[iPoint].y / flTanFOVx - aXFormPoints[iPoint].x );
float flTestDist = MAX( flDistZ, flDistY );
flDist = MAX( flDist, flTestDist );
}
// Scale the object down by 10%.
flDist *= 1.10f;
// Add the framing offset.
vecXFormCenter += m_pModelInfo->m_vecFramedOriginOffset;
// Zoom to the frame distance
m_pModelInfo->m_vecOriginOffset.x = flDist - vecXFormCenter.x;
m_pModelInfo->m_vecOriginOffset.y = -vecXFormCenter.y;
m_pModelInfo->m_vecOriginOffset.z = -vecXFormCenter.z;
// Screen space points.
Vector2D aScreenPoints[8];
Vector aCameraPoints[8];
for ( int iPoint = 0; iPoint < 8; ++iPoint )
{
aCameraPoints[iPoint] = aXFormPoints[iPoint];
aCameraPoints[iPoint].x += flDist;
aScreenPoints[iPoint].x = aCameraPoints[iPoint].y / ( flTanFOVx * aCameraPoints[iPoint].x );
aScreenPoints[iPoint].y = aCameraPoints[iPoint].z / ( flTanFOVy * aCameraPoints[iPoint].x );
aScreenPoints[iPoint].x = ( aScreenPoints[iPoint].x * 0.5f + 0.5f ) * flW;
aScreenPoints[iPoint].y = ( aScreenPoints[iPoint].y * 0.5f + 0.5f ) * flH;
}
// Find the min/max and center of the 2D bounding box of the object.
Vector2D vecScreenMin( 99999.0f, 99999.0f ), vecScreenMax( -99999.0f, -99999.0f );
for ( int iPoint = 0; iPoint < 8; ++iPoint )
{
vecScreenMin.x = MIN( vecScreenMin.x, aScreenPoints[iPoint].x );
vecScreenMin.y = MIN( vecScreenMin.y, aScreenPoints[iPoint].y );
vecScreenMax.x = MAX( vecScreenMax.x, aScreenPoints[iPoint].x );
vecScreenMax.y = MAX( vecScreenMax.y, aScreenPoints[iPoint].y );
}
vecScreenMin.x = clamp( vecScreenMin.x, 0.0f, flW );
vecScreenMin.y = clamp( vecScreenMin.y, 0.0f, flH );
vecScreenMax.x = clamp( vecScreenMax.x, 0.0f, flW );
vecScreenMax.y = clamp( vecScreenMax.y, 0.0f, flH );
// Offset the view port based on the calculated model 2D center and the center of the viewport.
Vector2D vecScreenCenter = ( vecScreenMax + vecScreenMin ) * 0.5f;
m_pModelInfo->m_vecViewportOffset.x = -( ( flW * 0.5f ) - vecScreenCenter.x );
m_pModelInfo->m_vecViewportOffset.y = -( ( flH * 0.5f ) - vecScreenCenter.y );
}
//-----------------------------------------------------------------------------
// Purpose: Calculates the distance the camera should be at to frame the model on the screen.
//-----------------------------------------------------------------------------
void CModelPanel::CalculateFrameDistance( void )
{
m_flFrameDistance = 0;
if ( !m_hModel )
return;
// Compute a bounding radius for the model
const model_t *mod = modelinfo->GetModel( m_hModel->GetModelIndex() );
if ( !mod )
return;
if ( m_bStartFramed )
{
CalculateFrameDistanceInternal( mod );
}
}
//-----------------------------------------------------------------------------
// Purpose: Moves the camera forward/backward along the current view angle to
// frame the model on the screen.
//-----------------------------------------------------------------------------
void CModelPanel::ZoomToFrameDistance( void )
{
if ( !m_flFrameDistance || !m_hModel )
return;
const model_t *mod = modelinfo->GetModel( m_hModel->GetModelIndex() );
if ( !mod )
return;
// Move the model to the midpoint
Vector mins, maxs, vecModelCenter;
modelinfo->GetModelRenderBounds( mod, mins, maxs );
VectorLerp( mins, maxs, 0.5f, vecModelCenter );
vecModelCenter += m_pModelInfo->m_vecFramedOriginOffset;
// Zoom to the frame distance
m_pModelInfo->m_vecOriginOffset.x = m_flFrameDistance;
m_pModelInfo->m_vecOriginOffset.y = -vecModelCenter.y;
m_pModelInfo->m_vecOriginOffset.z = -vecModelCenter.z;
}

View File

@@ -0,0 +1,233 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
// $NoKeywords: $
//=============================================================================//
#ifndef BASEMODELPANEL_H
#define BASEMODELPANEL_H
#ifdef _WIN32
#pragma once
#endif
#include <vgui/IScheme.h>
#include <vgui_controls/ImagePanel.h>
#include <vgui_controls/EditablePanel.h>
#include "GameEventListener.h"
#include "KeyValues.h"
class C_SceneEntity;
class CModelPanelModel : public C_BaseFlex
{
public:
CModelPanelModel(){}
DECLARE_CLASS( CModelPanelModel, C_BaseFlex );
virtual bool IsMenuModel() const{ return true; }
};
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
class CModelPanelModelAnimation
{
public:
CModelPanelModelAnimation()
{
m_pszName = NULL;
m_pszSequence = NULL;
m_pszActivity = NULL;
m_pPoseParameters = NULL;
m_bDefault = false;
}
~CModelPanelModelAnimation()
{
if ( m_pszName && m_pszName[0] )
{
delete [] m_pszName;
m_pszName = NULL;
}
if ( m_pszSequence && m_pszSequence[0] )
{
delete [] m_pszSequence;
m_pszSequence = NULL;
}
if ( m_pszActivity && m_pszActivity[0] )
{
delete [] m_pszActivity;
m_pszActivity = NULL;
}
if ( m_pPoseParameters )
{
m_pPoseParameters->deleteThis();
m_pPoseParameters = NULL;
}
}
public:
const char *m_pszName;
const char *m_pszSequence;
const char *m_pszActivity;
KeyValues *m_pPoseParameters;
bool m_bDefault;
};
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
class CModelPanelAttachedModelInfo
{
public:
CModelPanelAttachedModelInfo()
{
m_pszModelName = NULL;
m_nSkin = 0;
}
~CModelPanelAttachedModelInfo()
{
if ( m_pszModelName && m_pszModelName[0] )
{
delete [] m_pszModelName;
m_pszModelName = NULL;
}
}
public:
const char *m_pszModelName;
int m_nSkin;
};
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
class CModelPanelModelInfo
{
public:
CModelPanelModelInfo()
{
m_pszModelName = NULL;
m_pszModelName_HWM = NULL;
m_nSkin = -1;
m_vecAbsAngles.Init();
m_vecOriginOffset.Init();
m_vecFramedOriginOffset.Init();
m_bUseSpotlight = false;
}
~CModelPanelModelInfo()
{
if ( m_pszModelName && m_pszModelName[0] )
{
delete [] m_pszModelName;
m_pszModelName = NULL;
}
if ( m_pszModelName_HWM && m_pszModelName_HWM[0] )
{
delete [] m_pszModelName_HWM;
m_pszModelName_HWM = NULL;
}
if ( m_pszVCD && m_pszVCD[0] )
{
delete [] m_pszVCD;
m_pszVCD = NULL;
}
m_Animations.PurgeAndDeleteElements();
m_AttachedModelsInfo.PurgeAndDeleteElements();
}
public:
const char *m_pszModelName;
const char *m_pszModelName_HWM;
int m_nSkin;
const char *m_pszVCD;
Vector m_vecAbsAngles;
Vector m_vecOriginOffset;
Vector2D m_vecViewportOffset;
Vector m_vecFramedOriginOffset;
bool m_bUseSpotlight;
CUtlVector<CModelPanelModelAnimation*> m_Animations;
CUtlVector<CModelPanelAttachedModelInfo*> m_AttachedModelsInfo;
};
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
class CModelPanel : public vgui::EditablePanel, public CGameEventListener
{
public:
DECLARE_CLASS_SIMPLE( CModelPanel, vgui::EditablePanel );
CModelPanel( vgui::Panel *parent, const char *name );
virtual ~CModelPanel();
virtual void Paint();
virtual void ApplySettings( KeyValues *inResourceData );
virtual void DeleteVCDData( void );
virtual void DeleteModelData( void );
virtual void SetFOV( int nFOV ){ m_nFOV = nFOV; }
virtual void SetPanelDirty( void ){ m_bPanelDirty = true; }
virtual bool SetSequence( const char *pszSequence );
MESSAGE_FUNC_PARAMS( OnAddAnimation, "AddAnimation", data );
MESSAGE_FUNC_PARAMS( OnSetAnimation, "SetAnimation", data );
void SetDefaultAnimation( const char *pszName );
void SwapModel( const char *pszName, const char *pszAttached = NULL );
virtual void ParseModelInfo( KeyValues *inResourceData );
void ClearAttachedModelInfos( void );
void CalculateFrameDistance( void );
void ZoomToFrameDistance( void );
void UpdateModel();
public: // IGameEventListener:
virtual void FireGameEvent( IGameEvent * event );
protected:
virtual void SetupModel( void );
virtual void SetupVCD( void );
virtual const char *GetModelName( void );
private:
void InitCubeMaps();
int FindAnimByName( const char *pszName );
void CalculateFrameDistanceInternal( const model_t *pModel );
public:
int m_nFOV;
float m_flFrameDistance;
bool m_bStartFramed;
CModelPanelModelInfo *m_pModelInfo;
CHandle<CModelPanelModel> m_hModel;
CUtlVector<CHandle<C_BaseAnimating> > m_AttachedModels;
CHandle<C_SceneEntity> m_hScene;
private:
bool m_bPanelDirty;
int m_iDefaultAnimation;
bool m_bAllowOffscreen;
CTextureReference m_DefaultEnvCubemap;
CTextureReference m_DefaultHDREnvCubemap;
};
#endif // BASEMODELPANEL_H

View File

@@ -0,0 +1,721 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose: Client DLL VGUI2 Viewport
//
// $Workfile: $
// $Date: $
//
//-----------------------------------------------------------------------------
// $Log: $
//
// $NoKeywords: $
//=============================================================================//
#pragma warning( disable : 4800 ) // disable forcing int to bool performance warning
#include "cbase.h"
#include <cdll_client_int.h>
#include <cdll_util.h>
#include <globalvars_base.h>
// VGUI panel includes
#include <vgui_controls/Panel.h>
#include <vgui_controls/AnimationController.h>
#include <vgui/ISurface.h>
#include <KeyValues.h>
#include <vgui/IScheme.h>
#include <vgui/IVGui.h>
#include <vgui/ILocalize.h>
#include <vgui/IPanel.h>
#include <vgui_controls/Button.h>
#include <igameresources.h>
// sub dialogs
#include "clientscoreboarddialog.h"
#include "spectatorgui.h"
#include "teammenu.h"
#include "vguitextwindow.h"
#include "IGameUIFuncs.h"
#include "mapoverview.h"
#include "hud.h"
#include "NavProgress.h"
#include "commentary_modelviewer.h"
// our definition
#include "baseviewport.h"
#include <filesystem.h>
#include <convar.h>
#include "ienginevgui.h"
#include "iclientmode.h"
#include "tier0/etwprof.h"
#if defined( REPLAY_ENABLED )
#include "replay/ireplaysystem.h"
#include "replay/ienginereplay.h"
#endif
// memdbgon must be the last include file in a .cpp file!!!
#include "tier0/memdbgon.h"
IViewPort *gViewPortInterface = NULL;
vgui::Panel *g_lastPanel = NULL; // used for mouseover buttons, keeps track of the last active panel
vgui::Button *g_lastButton = NULL; // used for mouseover buttons, keeps track of the last active button
using namespace vgui;
ConVar hud_autoreloadscript("hud_autoreloadscript", "0", FCVAR_NONE, "Automatically reloads the animation script each time one is ran");
static ConVar cl_leveloverviewmarker( "cl_leveloverviewmarker", "0", FCVAR_CHEAT );
CON_COMMAND( showpanel, "Shows a viewport panel <name>" )
{
if ( !gViewPortInterface )
return;
if ( args.ArgC() != 2 )
return;
gViewPortInterface->ShowPanel( args[ 1 ], true );
}
CON_COMMAND( hidepanel, "Hides a viewport panel <name>" )
{
if ( !gViewPortInterface )
return;
if ( args.ArgC() != 2 )
return;
gViewPortInterface->ShowPanel( args[ 1 ], false );
}
/* global helper functions
bool Helper_LoadFile( IBaseFileSystem *pFileSystem, const char *pFilename, CUtlVector<char> &buf )
{
FileHandle_t hFile = pFileSystem->Open( pFilename, "rt" );
if ( hFile == FILESYSTEM_INVALID_HANDLE )
{
Warning( "Helper_LoadFile: missing %s\n", pFilename );
return false;
}
unsigned long len = pFileSystem->Size( hFile );
buf.SetSize( len );
pFileSystem->Read( buf.Base(), buf.Count(), hFile );
pFileSystem->Close( hFile );
return true;
} */
//-----------------------------------------------------------------------------
// Purpose:
// Output : Returns true on success, false on failure.
//-----------------------------------------------------------------------------
bool CBaseViewport::LoadHudAnimations( void )
{
const char *HUDANIMATION_MANIFEST_FILE = "scripts/hudanimations_manifest.txt";
KeyValues *manifest = new KeyValues( HUDANIMATION_MANIFEST_FILE );
if ( manifest->LoadFromFile( g_pFullFileSystem, HUDANIMATION_MANIFEST_FILE, "GAME" ) == false )
{
manifest->deleteThis();
return false;
}
bool bClearScript = true;
// Load each file defined in the text
for ( KeyValues *sub = manifest->GetFirstSubKey(); sub != NULL; sub = sub->GetNextKey() )
{
if ( !Q_stricmp( sub->GetName(), "file" ) )
{
// Add it
if ( m_pAnimController->SetScriptFile( GetVPanel(), sub->GetString(), bClearScript ) == false )
{
Assert( 0 );
}
bClearScript = false;
continue;
}
}
manifest->deleteThis();
return true;
}
//================================================================
CBaseViewport::CBaseViewport() : vgui::EditablePanel( NULL, "CBaseViewport")
{
SetSize( 10, 10 ); // Quiet "parent not sized yet" spew
gViewPortInterface = this;
m_bInitialized = false;
m_GameuiFuncs = NULL;
m_GameEventManager = NULL;
SetKeyBoardInputEnabled( false );
SetMouseInputEnabled( false );
#ifndef _XBOX
m_pBackGround = NULL;
#endif
m_bHasParent = false;
m_pActivePanel = NULL;
m_pLastActivePanel = NULL;
g_lastPanel = NULL;
vgui::HScheme scheme = vgui::scheme()->LoadSchemeFromFileEx( enginevgui->GetPanel( PANEL_CLIENTDLL ), "resource/ClientScheme.res", "ClientScheme");
SetScheme(scheme);
SetProportional( true );
m_pAnimController = new vgui::AnimationController(this);
// create our animation controller
m_pAnimController->SetScheme(scheme);
m_pAnimController->SetProportional(true);
// Attempt to load all hud animations
if ( LoadHudAnimations() == false )
{
// Fall back to just the main
if ( m_pAnimController->SetScriptFile( GetVPanel(), "scripts/HudAnimations.txt", true ) == false )
{
Assert(0);
}
}
m_OldSize[ 0 ] = m_OldSize[ 1 ] = -1;
}
//-----------------------------------------------------------------------------
// Purpose: Updates hud to handle the new screen size
//-----------------------------------------------------------------------------
void CBaseViewport::OnScreenSizeChanged(int iOldWide, int iOldTall)
{
BaseClass::OnScreenSizeChanged(iOldWide, iOldTall);
IViewPortPanel* pSpecGuiPanel = FindPanelByName(PANEL_SPECGUI);
bool bSpecGuiWasVisible = pSpecGuiPanel && pSpecGuiPanel->IsVisible();
// reload the script file, so the screen positions in it are correct for the new resolution
ReloadScheme( NULL );
// recreate all the default panels
RemoveAllPanels();
#ifndef _XBOX
m_pBackGround = new CBackGroundPanel( NULL );
m_pBackGround->SetZPos( -20 ); // send it to the back
m_pBackGround->SetVisible( false );
#endif
CreateDefaultPanels();
#ifndef _XBOX
vgui::ipanel()->MoveToBack( m_pBackGround->GetVPanel() ); // really send it to the back
#endif
// hide all panels when reconnecting
ShowPanel( PANEL_ALL, false );
// re-enable the spectator gui if it was previously visible
if ( bSpecGuiWasVisible )
{
ShowPanel( PANEL_SPECGUI, true );
}
}
void CBaseViewport::CreateDefaultPanels( void )
{
#ifndef _XBOX
AddNewPanel( CreatePanelByName( PANEL_SCOREBOARD ), "PANEL_SCOREBOARD" );
AddNewPanel( CreatePanelByName( PANEL_INFO ), "PANEL_INFO" );
AddNewPanel( CreatePanelByName( PANEL_SPECGUI ), "PANEL_SPECGUI" );
AddNewPanel( CreatePanelByName( PANEL_SPECMENU ), "PANEL_SPECMENU" );
AddNewPanel( CreatePanelByName( PANEL_NAV_PROGRESS ), "PANEL_NAV_PROGRESS" );
// AddNewPanel( CreatePanelByName( PANEL_TEAM ), "PANEL_TEAM" );
// AddNewPanel( CreatePanelByName( PANEL_CLASS ), "PANEL_CLASS" );
// AddNewPanel( CreatePanelByName( PANEL_BUY ), "PANEL_BUY" );
#endif
}
void CBaseViewport::UpdateAllPanels( void )
{
int count = m_Panels.Count();
for (int i=0; i< count; i++ )
{
IViewPortPanel *p = m_Panels[i];
if ( p->IsVisible() )
{
p->Update();
}
}
}
IViewPortPanel* CBaseViewport::CreatePanelByName(const char *szPanelName)
{
IViewPortPanel* newpanel = NULL;
#ifndef _XBOX
if ( Q_strcmp(PANEL_SCOREBOARD, szPanelName) == 0 )
{
newpanel = new CClientScoreBoardDialog( this );
}
else if ( Q_strcmp(PANEL_INFO, szPanelName) == 0 )
{
newpanel = new CTextWindow( this );
}
/* else if ( Q_strcmp(PANEL_OVERVIEW, szPanelName) == 0 )
{
newpanel = new CMapOverview( this );
}
*/
else if ( Q_strcmp(PANEL_TEAM, szPanelName) == 0 )
{
newpanel = new CTeamMenu( this );
}
else if ( Q_strcmp(PANEL_SPECMENU, szPanelName) == 0 )
{
newpanel = new CSpectatorMenu( this );
}
else if ( Q_strcmp(PANEL_SPECGUI, szPanelName) == 0 )
{
newpanel = new CSpectatorGUI( this );
}
#if !defined( TF_CLIENT_DLL )
else if ( Q_strcmp(PANEL_NAV_PROGRESS, szPanelName) == 0 )
{
newpanel = new CNavProgress( this );
}
#endif // TF_CLIENT_DLL
#endif
if ( Q_strcmp(PANEL_COMMENTARY_MODELVIEWER, szPanelName) == 0 )
{
newpanel = new CCommentaryModelViewer( this );
}
return newpanel;
}
bool CBaseViewport::AddNewPanel( IViewPortPanel* pPanel, char const *pchDebugName )
{
if ( !pPanel )
{
DevMsg("CBaseViewport::AddNewPanel(%s): NULL panel.\n", pchDebugName );
return false;
}
// we created a new panel, initialize it
if ( FindPanelByName( pPanel->GetName() ) != NULL )
{
DevMsg("CBaseViewport::AddNewPanel: panel with name '%s' already exists.\n", pPanel->GetName() );
return false;
}
m_Panels.AddToTail( pPanel );
pPanel->SetParent( GetVPanel() );
return true;
}
IViewPortPanel* CBaseViewport::FindPanelByName(const char *szPanelName)
{
int count = m_Panels.Count();
for (int i=0; i< count; i++ )
{
if ( Q_strcmp(m_Panels[i]->GetName(), szPanelName) == 0 )
return m_Panels[i];
}
return NULL;
}
void CBaseViewport::PostMessageToPanel( IViewPortPanel* pPanel, KeyValues *pKeyValues )
{
PostMessage( pPanel->GetVPanel(), pKeyValues );
}
void CBaseViewport::PostMessageToPanel( const char *pName, KeyValues *pKeyValues )
{
if ( Q_strcmp( pName, PANEL_ALL ) == 0 )
{
for (int i=0; i< m_Panels.Count(); i++ )
{
PostMessageToPanel( m_Panels[i], pKeyValues );
}
return;
}
IViewPortPanel * panel = NULL;
if ( Q_strcmp( pName, PANEL_ACTIVE ) == 0 )
{
panel = m_pActivePanel;
}
else
{
panel = FindPanelByName( pName );
}
if ( !panel )
return;
PostMessageToPanel( panel, pKeyValues );
}
void CBaseViewport::ShowPanel( const char *pName, bool state )
{
if ( Q_strcmp( pName, PANEL_ALL ) == 0 )
{
for (int i=0; i< m_Panels.Count(); i++ )
{
ShowPanel( m_Panels[i], state );
}
return;
}
IViewPortPanel * panel = NULL;
if ( Q_strcmp( pName, PANEL_ACTIVE ) == 0 )
{
panel = m_pActivePanel;
}
else
{
panel = FindPanelByName( pName );
}
if ( !panel )
return;
ShowPanel( panel, state );
}
void CBaseViewport::ShowPanel( IViewPortPanel* pPanel, bool state )
{
if ( state )
{
// if this is an 'active' panel, deactivate old active panel
if ( pPanel->HasInputElements() )
{
// don't show input panels during normal demo playback
#if defined( REPLAY_ENABLED )
if ( engine->IsPlayingDemo() && !engine->IsHLTV() && !g_pEngineClientReplay->IsPlayingReplayDemo() )
#else
if ( engine->IsPlayingDemo() && !engine->IsHLTV() )
#endif
return;
if ( (m_pActivePanel != NULL) && (m_pActivePanel != pPanel) && (m_pActivePanel->IsVisible()) )
{
// store a pointer to the currently active panel
// so we can restore it later
m_pLastActivePanel = m_pActivePanel;
m_pActivePanel->ShowPanel( false );
}
m_pActivePanel = pPanel;
}
}
else
{
// if this is our current active panel
// update m_pActivePanel pointer
if ( m_pActivePanel == pPanel )
{
m_pActivePanel = NULL;
}
// restore the previous active panel if it exists
if( m_pLastActivePanel )
{
m_pActivePanel = m_pLastActivePanel;
m_pLastActivePanel = NULL;
m_pActivePanel->ShowPanel( true );
}
}
// just show/hide panel
pPanel->ShowPanel( state );
UpdateAllPanels(); // let other panels rearrange
}
IViewPortPanel* CBaseViewport::GetActivePanel( void )
{
return m_pActivePanel;
}
void CBaseViewport::RemoveAllPanels( void)
{
g_lastPanel = NULL;
for ( int i=0; i < m_Panels.Count(); i++ )
{
vgui::VPANEL vPanel = m_Panels[i]->GetVPanel();
vgui::ipanel()->DeletePanel( vPanel );
}
#ifndef _XBOX
if ( m_pBackGround )
{
m_pBackGround->MarkForDeletion();
m_pBackGround = NULL;
}
#endif
m_Panels.Purge();
m_pActivePanel = NULL;
m_pLastActivePanel = NULL;
}
CBaseViewport::~CBaseViewport()
{
m_bInitialized = false;
#ifndef _XBOX
if ( !m_bHasParent && m_pBackGround )
{
m_pBackGround->MarkForDeletion();
}
m_pBackGround = NULL;
#endif
RemoveAllPanels();
gameeventmanager->RemoveListener( this );
}
//-----------------------------------------------------------------------------
// Purpose: called when the VGUI subsystem starts up
// Creates the sub panels and initialises them
//-----------------------------------------------------------------------------
void CBaseViewport::Start( IGameUIFuncs *pGameUIFuncs, IGameEventManager2 * pGameEventManager )
{
m_GameuiFuncs = pGameUIFuncs;
m_GameEventManager = pGameEventManager;
#ifndef _XBOX
m_pBackGround = new CBackGroundPanel( NULL );
m_pBackGround->SetZPos( -20 ); // send it to the back
m_pBackGround->SetVisible( false );
#endif
CreateDefaultPanels();
m_GameEventManager->AddListener( this, "game_newmap", false );
m_bInitialized = true;
}
/*
//-----------------------------------------------------------------------------
// Purpose: Updates the spectator panel with new player info
//-----------------------------------------------------------------------------
void CBaseViewport::UpdateSpectatorPanel()
{
char bottomText[128];
int player = -1;
const char *name;
Q_snprintf(bottomText,sizeof( bottomText ), "#Spec_Mode%d", m_pClientDllInterface->SpectatorMode() );
m_pClientDllInterface->CheckSettings();
// check if we're locked onto a target, show the player's name
if ( (m_pClientDllInterface->SpectatorTarget() > 0) && (m_pClientDllInterface->SpectatorTarget() <= m_pClientDllInterface->GetMaxPlayers()) && (m_pClientDllInterface->SpectatorMode() != OBS_ROAMING) )
{
player = m_pClientDllInterface->SpectatorTarget();
}
// special case in free map and inset off, don't show names
if ( ((m_pClientDllInterface->SpectatorMode() == OBS_MAP_FREE) && !m_pClientDllInterface->PipInsetOff()) || player == -1 )
name = NULL;
else
name = m_pClientDllInterface->GetPlayerInfo(player).name;
// create player & health string
if ( player && name )
{
Q_strncpy( bottomText, name, sizeof( bottomText ) );
}
char szMapName[64];
Q_FileBase( const_cast<char *>(m_pClientDllInterface->GetLevelName()), szMapName );
m_pSpectatorGUI->Update(bottomText, player, m_pClientDllInterface->SpectatorMode(), m_pClientDllInterface->IsSpectateOnly(), m_pClientDllInterface->SpectatorNumber(), szMapName );
m_pSpectatorGUI->UpdateSpectatorPlayerList();
} */
// Return TRUE if the HUD's allowed to print text messages
bool CBaseViewport::AllowedToPrintText( void )
{
/* int iId = GetCurrentMenuID();
if ( iId == MENU_TEAM || iId == MENU_CLASS || iId == MENU_INTRO || iId == MENU_CLASSHELP )
return false; */
// TODO ask every aktive elemet if it allows to draw text while visible
return ( m_pActivePanel == NULL);
}
void CBaseViewport::OnThink()
{
// Clear our active panel pointer if the panel has made
// itself invisible. Need this so we don't bring up dead panels
// if they are stored as the last active panel
if( m_pActivePanel && !m_pActivePanel->IsVisible() )
{
if( m_pLastActivePanel )
{
m_pActivePanel = m_pLastActivePanel;
ShowPanel( m_pActivePanel, true );
m_pLastActivePanel = NULL;
}
else
m_pActivePanel = NULL;
}
m_pAnimController->UpdateAnimations( gpGlobals->curtime );
// check the auto-reload cvar
m_pAnimController->SetAutoReloadScript(hud_autoreloadscript.GetBool());
int count = m_Panels.Count();
for (int i=0; i< count; i++ )
{
IViewPortPanel *panel = m_Panels[i];
if ( panel->NeedsUpdate() && panel->IsVisible() )
{
panel->Update();
}
}
int w, h;
vgui::ipanel()->GetSize( enginevgui->GetPanel( PANEL_CLIENTDLL ), w, h );
if ( m_OldSize[ 0 ] != w || m_OldSize[ 1 ] != h )
{
m_OldSize[ 0 ] = w;
m_OldSize[ 1 ] = h;
g_pClientMode->Layout();
}
BaseClass::OnThink();
}
//-----------------------------------------------------------------------------
// Purpose: Sets the parent for each panel to use
//-----------------------------------------------------------------------------
void CBaseViewport::SetParent(vgui::VPANEL parent)
{
EditablePanel::SetParent( parent );
// force ourselves to be proportional - when we set our parent above, if our new
// parent happened to be non-proportional (such as the vgui root panel), we got
// slammed to be nonproportional
EditablePanel::SetProportional( true );
#ifndef _XBOX
m_pBackGround->SetParent( (vgui::VPANEL)parent );
#endif
// set proportionality on animation controller
m_pAnimController->SetProportional( true );
m_bHasParent = (parent != 0);
}
//-----------------------------------------------------------------------------
// Purpose: called when the engine shows the base client VGUI panel (i.e when entering a new level or exiting GameUI )
//-----------------------------------------------------------------------------
void CBaseViewport::ActivateClientUI()
{
}
//-----------------------------------------------------------------------------
// Purpose: called when the engine hides the base client VGUI panel (i.e when the GameUI is comming up )
//-----------------------------------------------------------------------------
void CBaseViewport::HideClientUI()
{
}
//-----------------------------------------------------------------------------
// Purpose: passes death msgs to the scoreboard to display specially
//-----------------------------------------------------------------------------
void CBaseViewport::FireGameEvent( IGameEvent * event)
{
const char * type = event->GetName();
if ( Q_strcmp(type, "game_newmap") == 0 )
{
// hide all panels when reconnecting
ShowPanel( PANEL_ALL, false );
if ( engine->IsHLTV() )
{
ShowPanel( PANEL_SPECGUI, true );
}
}
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CBaseViewport::ReloadScheme(const char *fromFile)
{
CETWScope timer( "CBaseViewport::ReloadScheme" );
// See if scheme should change
if ( fromFile != NULL )
{
// "resource/ClientScheme.res"
vgui::HScheme scheme = vgui::scheme()->LoadSchemeFromFileEx( enginevgui->GetPanel( PANEL_CLIENTDLL ), fromFile, "HudScheme" );
SetScheme(scheme);
SetProportional( true );
m_pAnimController->SetScheme(scheme);
}
// Force a reload
if ( LoadHudAnimations() == false )
{
// Fall back to just the main
if ( m_pAnimController->SetScriptFile( GetVPanel(), "scripts/HudAnimations.txt", true ) == false )
{
Assert(0);
}
}
SetProportional( true );
KeyValuesAD pConditions( "conditions" );
g_pClientMode->ComputeVguiResConditions( pConditions );
// reload the .res file from disk
LoadControlSettings( "scripts/HudLayout.res", NULL, NULL, pConditions );
gHUD.RefreshHudTextures();
InvalidateLayout( true, true );
// reset the hud
gHUD.ResetHUD();
}
int CBaseViewport::GetDeathMessageStartHeight( void )
{
return YRES(2);
}
void CBaseViewport::Paint()
{
if ( cl_leveloverviewmarker.GetInt() > 0 )
{
int size = cl_leveloverviewmarker.GetInt();
// draw a 1024x1024 pixel box
vgui::surface()->DrawSetColor( 255, 0, 0, 255 );
vgui::surface()->DrawLine( size, 0, size, size );
vgui::surface()->DrawLine( 0, size, size, size );
}
}

View File

@@ -0,0 +1,148 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
// $NoKeywords: $
//=============================================================================//
#ifndef TEAMFORTRESSVIEWPORT_H
#define TEAMFORTRESSVIEWPORT_H
// viewport interface for the rest of the dll
#include <game/client/iviewport.h>
#include <utlqueue.h> // a vector based queue template to manage our VGUI menu queue
#include <vgui_controls/Frame.h>
#include "vguitextwindow.h"
#include "vgui/ISurface.h"
#include "commandmenu.h"
#include <igameevents.h>
using namespace vgui;
class IBaseFileSystem;
class IGameUIFuncs;
class IGameEventManager;
//==============================================================================
class CBaseViewport : public vgui::EditablePanel, public IViewPort, public IGameEventListener2
{
DECLARE_CLASS_SIMPLE( CBaseViewport, vgui::EditablePanel );
public:
CBaseViewport();
virtual ~CBaseViewport();
virtual IViewPortPanel* CreatePanelByName(const char *szPanelName);
virtual IViewPortPanel* FindPanelByName(const char *szPanelName);
virtual IViewPortPanel* GetActivePanel( void );
virtual void RemoveAllPanels( void);
virtual void ShowPanel( const char *pName, bool state );
virtual void ShowPanel( IViewPortPanel* pPanel, bool state );
virtual bool AddNewPanel( IViewPortPanel* pPanel, char const *pchDebugName );
virtual void CreateDefaultPanels( void );
virtual void UpdateAllPanels( void );
virtual void PostMessageToPanel( const char *pName, KeyValues *pKeyValues );
virtual void Start( IGameUIFuncs *pGameUIFuncs, IGameEventManager2 *pGameEventManager );
virtual void SetParent(vgui::VPANEL parent);
virtual void ReloadScheme(const char *fromFile);
virtual void ActivateClientUI();
virtual void HideClientUI();
virtual bool AllowedToPrintText( void );
#ifndef _XBOX
virtual int GetViewPortScheme() { return m_pBackGround->GetScheme(); }
virtual VPANEL GetViewPortPanel() { return m_pBackGround->GetVParent(); }
#endif
virtual AnimationController *GetAnimationController() { return m_pAnimController; }
virtual void ShowBackGround(bool bShow)
{
#ifndef _XBOX
m_pBackGround->SetVisible( bShow );
#endif
}
virtual int GetDeathMessageStartHeight( void );
// virtual void ChatInputPosition( int *x, int *y );
public: // IGameEventListener:
virtual void FireGameEvent( IGameEvent * event);
protected:
bool LoadHudAnimations( void );
#ifndef _XBOX
class CBackGroundPanel : public vgui::Frame
{
private:
typedef vgui::Frame BaseClass;
public:
CBackGroundPanel( vgui::Panel *parent) : Frame( parent, "ViewPortBackGround" )
{
SetScheme("ClientScheme");
SetTitleBarVisible( false );
SetMoveable(false);
SetSizeable(false);
SetProportional(true);
}
private:
virtual void ApplySchemeSettings(IScheme *pScheme)
{
BaseClass::ApplySchemeSettings(pScheme);
SetBgColor(pScheme->GetColor("ViewportBG", Color( 0,0,0,0 ) ));
}
virtual void PerformLayout()
{
int w,h;
GetHudSize(w, h);
// fill the screen
SetBounds(0,0,w,h);
BaseClass::PerformLayout();
}
virtual void OnMousePressed(MouseCode code) { }// don't respond to mouse clicks
virtual vgui::VPANEL IsWithinTraverse( int x, int y, bool traversePopups )
{
return ( vgui::VPANEL )0;
}
};
#endif
protected:
virtual void Paint();
virtual void OnThink();
virtual void OnScreenSizeChanged(int iOldWide, int iOldTall);
void PostMessageToPanel( IViewPortPanel* pPanel, KeyValues *pKeyValues );
protected:
IGameUIFuncs* m_GameuiFuncs; // for key binding details
IGameEventManager2* m_GameEventManager;
#ifndef _XBOX
CBackGroundPanel *m_pBackGround;
#endif
CUtlVector<IViewPortPanel*> m_Panels;
bool m_bHasParent; // Used to track if child windows have parents or not.
bool m_bInitialized;
IViewPortPanel *m_pActivePanel;
IViewPortPanel *m_pLastActivePanel;
vgui::HCursor m_hCursorNone;
vgui::AnimationController *m_pAnimController;
int m_OldSize[2];
};
#endif

View File

@@ -0,0 +1,149 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
// $NoKeywords: $
//=============================================================================//
#include "cbase.h"
#include "buymenu.h"
#include "buysubmenu.h"
using namespace vgui;
#include "mouseoverpanelbutton.h"
// memdbgon must be the last include file in a .cpp file!!!
#include "tier0/memdbgon.h"
//-----------------------------------------------------------------------------
// Purpose: Constructor
//-----------------------------------------------------------------------------
CBuyMenu::CBuyMenu(IViewPort *pViewPort) : WizardPanel( NULL, PANEL_BUY )
{
SetScheme("ClientScheme");
SetTitle( "#Cstrike_Buy_Menu", true);
SetMoveable(false);
SetSizeable(false);
SetProportional(true);
// hide the system buttons
SetTitleBarVisible( false );
SetAutoDelete( false ); // we reuse this panel, don't let WizardPanel delete us
LoadControlSettings( "Resource/UI/BuyMenu.res" );
ShowButtons( false );
m_pViewPort = pViewPort;
m_pMainMenu = new CBuySubMenu( this, "mainmenu" );
m_pMainMenu->LoadControlSettings( "Resource/UI/MainBuyMenu.res" );
m_pMainMenu->SetVisible( false );
}
//-----------------------------------------------------------------------------
// Purpose: Destructor
//-----------------------------------------------------------------------------
CBuyMenu::~CBuyMenu()
{
if ( m_pMainMenu )
m_pMainMenu->DeleteSubPanels(); //?
}
//-----------------------------------------------------------------------------
// Purpose: shows/hides the buy menu
//-----------------------------------------------------------------------------
void CBuyMenu::ShowPanel(bool bShow)
{
if ( BaseClass::IsVisible() == bShow )
return;
if ( bShow )
{
Update();
Run( m_pMainMenu );
SetMouseInputEnabled( true );
engine->ClientCmd_Unrestricted( "gameui_preventescapetoshow\n" );
}
else
{
engine->ClientCmd_Unrestricted( "gameui_allowescapetoshow\n" );
SetVisible( false );
SetMouseInputEnabled( false );
}
m_pViewPort->ShowBackGround( bShow );
}
void CBuyMenu::Update()
{
//Don't need to do anything, but do need to implement this function as base is pure virtual
}
void CBuyMenu::OnClose()
{
engine->ClientCmd_Unrestricted( "gameui_allowescapetoshow\n" );
BaseClass::OnClose();
ResetHistory();
}
void CBuyMenu::OnKeyCodePressed( vgui::KeyCode code )
{
int nDir = 0;
switch ( code )
{
case KEY_XBUTTON_UP:
case KEY_XSTICK1_UP:
case KEY_XSTICK2_UP:
case KEY_UP:
nDir = -1;
break;
case KEY_XBUTTON_DOWN:
case KEY_XSTICK1_DOWN:
case KEY_XSTICK2_DOWN:
case KEY_DOWN:
nDir = 1;
break;
}
if ( nDir != 0 )
{
Panel *pSubPanel = ( GetCurrentSubPanel() ? GetCurrentSubPanel() : m_pMainMenu );
CUtlSortVector< SortedPanel_t, CSortedPanelYLess > vecSortedButtons;
VguiPanelGetSortedChildButtonList( pSubPanel, (void*)&vecSortedButtons, "&", 0 );
if ( VguiPanelNavigateSortedChildButtonList( (void*)&vecSortedButtons, nDir ) != -1 )
{
// Handled!
return;
}
}
else
{
BaseClass::OnKeyCodePressed( code );
}
}
void CBuyMenu::OnKeyCodeTyped( KeyCode code )
{
if ( code == KEY_ESCAPE )
{
OnClose();
}
else
{
BaseClass::OnKeyCodeTyped( code );
}
}

View File

@@ -0,0 +1,66 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
// $NoKeywords: $
//=============================================================================//
#ifndef BUYMENU_H
#define BUYMENU_H
#ifdef _WIN32
#pragma once
#endif
#include <vgui_controls/WizardPanel.h>
#include <game/client/iviewport.h>
#include "vgui/KeyCode.h"
class CBuySubMenu;
namespace vgui
{
class Panel;
}
//-----------------------------------------------------------------------------
// Purpose: Draws the class menu
//-----------------------------------------------------------------------------
class CBuyMenu : public vgui::WizardPanel, public IViewPortPanel
{
private:
DECLARE_CLASS_SIMPLE( CBuyMenu, vgui::WizardPanel );
public:
CBuyMenu(IViewPort *pViewPort);
~CBuyMenu();
virtual const char *GetName( void ) { return PANEL_BUY; }
virtual void SetData(KeyValues *data) {};
virtual void Reset() {};
virtual void Update();
virtual bool NeedsUpdate( void ) { return false; }
virtual bool HasInputElements( void ) { return true; }
virtual void ShowPanel( bool bShow );
// both vgui::Frame and IViewPortPanel define these, so explicitly define them here as passthroughs to vgui
vgui::VPANEL GetVPanel( void ) { return BaseClass::GetVPanel(); }
virtual bool IsVisible() { return BaseClass::IsVisible(); }
virtual void SetParent( vgui::VPANEL parent ) { BaseClass::SetParent( parent ); }
virtual void OnKeyCodePressed( vgui::KeyCode code );
virtual void OnKeyCodeTyped( vgui::KeyCode code );
public:
virtual void OnClose();
protected:
CBuySubMenu *m_pMainMenu;
IViewPort *m_pViewPort;
int m_iTeam;
int m_iClass;
};
#endif // BUYMENU_H

View File

@@ -0,0 +1,171 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
// $NoKeywords: $
//=============================================================================//
#include "cbase.h"
#include "buysubmenu.h"
#include <KeyValues.h>
#include <vgui_controls/WizardPanel.h>
#include <filesystem.h>
#include <game/client/iviewport.h>
#include <cdll_client_int.h>
#include "mouseoverpanelbutton.h"
// #include "cs_gamerules.h"
// memdbgon must be the last include file in a .cpp file!!!
#include "tier0/memdbgon.h"
using namespace vgui;
//-----------------------------------------------------------------------------
// Purpose: Constructor
//-----------------------------------------------------------------------------
CBuySubMenu::CBuySubMenu(vgui::Panel *parent, const char *name) : WizardSubPanel(parent, name)
{
m_NextPanel = NULL;
m_pFirstButton = NULL;
SetProportional(true);
m_pPanel = new EditablePanel( this, "ItemInfo" );// info window about these items
m_pPanel->SetProportional( true );
}
//-----------------------------------------------------------------------------
// Purpose: Destructor
//-----------------------------------------------------------------------------
CBuySubMenu::~CBuySubMenu()
{
}
//-----------------------------------------------------------------------------
// Purpose: magic override to allow vgui to create mouse over buttons for us
//-----------------------------------------------------------------------------
Panel *CBuySubMenu::CreateControlByName( const char *controlName )
{
if( !Q_stricmp( "MouseOverPanelButton", controlName ) )
{
MouseOverPanelButton *newButton = CreateNewMouseOverPanelButton( m_pPanel );
if( !m_pFirstButton )
{
m_pFirstButton = newButton;
}
return newButton;
}
else
{
return BaseClass::CreateControlByName( controlName );
}
}
//-----------------------------------------------------------------------------
// Purpose: Make the first buttons page get displayed when the menu becomes visible
//-----------------------------------------------------------------------------
void CBuySubMenu::SetVisible( bool state )
{
BaseClass::SetVisible( state );
for( int i = 0; i< GetChildCount(); i++ ) // get all the buy buttons to performlayout
{
MouseOverPanelButton *buyButton = dynamic_cast<MouseOverPanelButton *>(GetChild(i));
if ( buyButton )
{
if( buyButton == m_pFirstButton && state == true )
buyButton->ShowPage();
else
buyButton->HidePage();
buyButton->InvalidateLayout();
}
}
}
CBuySubMenu* CBuySubMenu::CreateNewSubMenu()
{
return new CBuySubMenu( this );
}
MouseOverPanelButton* CBuySubMenu::CreateNewMouseOverPanelButton(EditablePanel *panel)
{
return new MouseOverPanelButton(this, NULL, panel);
}
//-----------------------------------------------------------------------------
// Purpose: Called when the user picks a class
//-----------------------------------------------------------------------------
void CBuySubMenu::OnCommand( const char *command)
{
if ( Q_strstr( command, ".res" ) ) // if its a .res file then its a new menu
{
int i;
// check the cache
for ( i = 0; i < m_SubMenus.Count(); i++ )
{
if ( !Q_stricmp( m_SubMenus[i].filename, command ) )
{
m_NextPanel = m_SubMenus[i].panel;
Assert( m_NextPanel );
m_NextPanel->InvalidateLayout(); // force it to reset it prices
break;
}
}
if ( i == m_SubMenus.Count() )
{
// not there, add a new entry
SubMenuEntry_t newEntry;
memset( &newEntry, 0x0, sizeof( newEntry ) );
CBuySubMenu *newMenu = CreateNewSubMenu();
newMenu->LoadControlSettings( command );
m_NextPanel = newMenu;
Q_strncpy( newEntry.filename, command, sizeof( newEntry.filename ) );
newEntry.panel = newMenu;
m_SubMenus.AddToTail( newEntry );
}
GetWizardPanel()->OnNextButton();
}
else
{
GetWizardPanel()->Close();
gViewPortInterface->ShowBackGround( false );
if ( Q_stricmp( command, "vguicancel" ) != 0 )
engine->ClientCmd( command );
BaseClass::OnCommand(command);
}
}
//-----------------------------------------------------------------------------
// Purpose: Causes the panel to delete itself when it closes
//-----------------------------------------------------------------------------
void CBuySubMenu::DeleteSubPanels()
{
if ( m_NextPanel )
{
m_NextPanel->SetVisible( false );
m_NextPanel = NULL;
}
m_pFirstButton = NULL;
}
//-----------------------------------------------------------------------------
// Purpose: return the next panel to show
//-----------------------------------------------------------------------------
vgui::WizardSubPanel *CBuySubMenu::GetNextSubPanel()
{
return m_NextPanel;
}

View File

@@ -0,0 +1,59 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
// $NoKeywords: $
//=============================================================================//
#ifndef BUYSUBMENU_H
#define BUYSUBMENU_H
#ifdef _WIN32
#pragma once
#endif
#include <vgui_controls/WizardSubPanel.h>
#include <vgui_controls/Button.h>
#include <utlvector.h>
#include "mouseoverpanelbutton.h"
class CBuyMenu;
//-----------------------------------------------------------------------------
// Purpose: Draws the class menu
//-----------------------------------------------------------------------------
class CBuySubMenu : public vgui::WizardSubPanel
{
private:
DECLARE_CLASS_SIMPLE( CBuySubMenu, vgui::WizardSubPanel );
public:
CBuySubMenu(vgui::Panel *parent,const char *name = "BuySubMenu");
~CBuySubMenu();
virtual void SetVisible( bool state );
virtual void DeleteSubPanels();
protected:
// command callbacks
virtual void OnCommand( const char *command );
virtual vgui::WizardSubPanel *GetNextSubPanel(); // this is the last menu in the list
virtual vgui::Panel *CreateControlByName(const char *controlName);
virtual CBuySubMenu* CreateNewSubMenu();
virtual MouseOverPanelButton* CreateNewMouseOverPanelButton(vgui::EditablePanel *panel);
typedef struct
{
char filename[_MAX_PATH];
CBuySubMenu *panel;
} SubMenuEntry_t;
vgui::EditablePanel *m_pPanel;
MouseOverPanelButton *m_pFirstButton;
CUtlVector<SubMenuEntry_t> m_SubMenus; // a cache of buy submenus, so we don't need to construct them each time
vgui::WizardSubPanel *m_NextPanel;
};
#endif // BUYSUBMENU_H

View File

@@ -0,0 +1,316 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
// $NoKeywords: $
//=============================================================================//
#include "cbase.h"
#include <stdio.h>
#include <cdll_client_int.h>
#include "classmenu.h"
#include <vgui/IScheme.h>
#include <vgui/ILocalize.h>
#include <vgui/ISurface.h>
#include <KeyValues.h>
#include <vgui_controls/ImageList.h>
#include <filesystem.h>
#include <vgui_controls/TextEntry.h>
#include <vgui_controls/Button.h>
#include <vgui_controls/Panel.h>
#include "cdll_util.h"
#include "IGameUIFuncs.h" // for key bindings
#ifndef _XBOX
extern IGameUIFuncs *gameuifuncs; // for key binding details
#endif
#include <game/client/iviewport.h>
#include <stdlib.h> // MAX_PATH define
// memdbgon must be the last include file in a .cpp file!!!
#include "tier0/memdbgon.h"
using namespace vgui;
#ifdef TF_CLIENT_DLL
#define HUD_CLASSAUTOKILL_FLAGS ( FCVAR_CLIENTDLL | FCVAR_ARCHIVE | FCVAR_USERINFO )
#else
#define HUD_CLASSAUTOKILL_FLAGS ( FCVAR_CLIENTDLL | FCVAR_ARCHIVE )
#endif // !TF_CLIENT_DLL
ConVar hud_classautokill( "hud_classautokill", "1", HUD_CLASSAUTOKILL_FLAGS, "Automatically kill player after choosing a new playerclass." );
//-----------------------------------------------------------------------------
// Purpose: Constructor
//-----------------------------------------------------------------------------
CClassMenu::CClassMenu(IViewPort *pViewPort) : Frame(NULL, PANEL_CLASS)
{
m_pViewPort = pViewPort;
m_iScoreBoardKey = BUTTON_CODE_INVALID; // this is looked up in Activate()
m_iTeam = 0;
// initialize dialog
SetTitle("", true);
// load the new scheme early!!
SetScheme("ClientScheme");
SetMoveable(false);
SetSizeable(false);
// hide the system buttons
SetTitleBarVisible( false );
SetProportional(true);
// info window about this class
m_pPanel = new EditablePanel( this, "ClassInfo" );
LoadControlSettings( "Resource/UI/ClassMenu.res" );
}
//-----------------------------------------------------------------------------
// Purpose: Constructor
//-----------------------------------------------------------------------------
CClassMenu::CClassMenu(IViewPort *pViewPort, const char *panelName) : Frame(NULL, panelName)
{
m_pViewPort = pViewPort;
m_iScoreBoardKey = BUTTON_CODE_INVALID; // this is looked up in Activate()
m_iTeam = 0;
// initialize dialog
SetTitle("", true);
// load the new scheme early!!
SetScheme("ClientScheme");
SetMoveable(false);
SetSizeable(false);
// hide the system buttons
SetTitleBarVisible( false );
SetProportional(true);
// info window about this class
m_pPanel = new EditablePanel( this, "ClassInfo" );
// Inheriting classes are responsible for calling LoadControlSettings()!
}
//-----------------------------------------------------------------------------
// Purpose: Destructor
//-----------------------------------------------------------------------------
CClassMenu::~CClassMenu()
{
}
MouseOverPanelButton* CClassMenu::CreateNewMouseOverPanelButton(EditablePanel *panel)
{
return new MouseOverPanelButton(this, "MouseOverPanelButton", panel);
}
Panel *CClassMenu::CreateControlByName(const char *controlName)
{
if( !Q_stricmp( "MouseOverPanelButton", controlName ) )
{
MouseOverPanelButton *newButton = CreateNewMouseOverPanelButton( m_pPanel );
m_mouseoverButtons.AddToTail( newButton );
return newButton;
}
else
{
return BaseClass::CreateControlByName( controlName );
}
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CClassMenu::Reset()
{
for ( int i = 0 ; i < GetChildCount() ; ++i )
{
// Hide the subpanel for the MouseOverPanelButtons
MouseOverPanelButton *pPanel = dynamic_cast<MouseOverPanelButton *>( GetChild( i ) );
if ( pPanel )
{
pPanel->HidePage();
}
}
// Turn the first button back on again (so we have a default description shown)
Assert( m_mouseoverButtons.Count() );
for ( int i=0; i<m_mouseoverButtons.Count(); ++i )
{
if ( i == 0 )
{
m_mouseoverButtons[i]->ShowPage(); // Show the first page
}
else
{
m_mouseoverButtons[i]->HidePage(); // Hide the rest
}
}
}
//-----------------------------------------------------------------------------
// Purpose: Called when the user picks a class
//-----------------------------------------------------------------------------
void CClassMenu::OnCommand( const char *command )
{
if ( Q_stricmp( command, "vguicancel" ) )
{
engine->ClientCmd( const_cast<char *>( command ) );
#if !defined( CSTRIKE_DLL ) && !defined( TF_CLIENT_DLL )
// They entered a command to change their class, kill them so they spawn with
// the new class right away
if ( hud_classautokill.GetBool() )
{
engine->ClientCmd( "kill" );
}
#endif // !CSTRIKE_DLL && !TF_CLIENT_DLL
}
Close();
gViewPortInterface->ShowBackGround( false );
BaseClass::OnCommand( command );
}
//-----------------------------------------------------------------------------
// Purpose: shows the class menu
//-----------------------------------------------------------------------------
void CClassMenu::ShowPanel(bool bShow)
{
if ( bShow )
{
Activate();
SetMouseInputEnabled( true );
// load a default class page
for ( int i=0; i<m_mouseoverButtons.Count(); ++i )
{
if ( i == 0 )
{
m_mouseoverButtons[i]->ShowPage(); // Show the first page
}
else
{
m_mouseoverButtons[i]->HidePage(); // Hide the rest
}
}
if ( m_iScoreBoardKey == BUTTON_CODE_INVALID )
{
m_iScoreBoardKey = gameuifuncs->GetButtonCodeForBind( "showscores" );
}
}
else
{
SetVisible( false );
SetMouseInputEnabled( false );
}
m_pViewPort->ShowBackGround( bShow );
}
void CClassMenu::SetData(KeyValues *data)
{
m_iTeam = data->GetInt( "team" );
}
//-----------------------------------------------------------------------------
// Purpose: Sets the text of a control by name
//-----------------------------------------------------------------------------
void CClassMenu::SetLabelText(const char *textEntryName, const char *text)
{
Label *entry = dynamic_cast<Label *>(FindChildByName(textEntryName));
if (entry)
{
entry->SetText(text);
}
}
//-----------------------------------------------------------------------------
// Purpose: Sets the visibility of a button by name
//-----------------------------------------------------------------------------
void CClassMenu::SetVisibleButton(const char *textEntryName, bool state)
{
Button *entry = dynamic_cast<Button *>(FindChildByName(textEntryName));
if (entry)
{
entry->SetVisible(state);
}
}
void CClassMenu::OnKeyCodePressed(KeyCode code)
{
int nDir = 0;
switch ( code )
{
case KEY_XBUTTON_UP:
case KEY_XSTICK1_UP:
case KEY_XSTICK2_UP:
case KEY_UP:
case KEY_XBUTTON_LEFT:
case KEY_XSTICK1_LEFT:
case KEY_XSTICK2_LEFT:
case KEY_LEFT:
nDir = -1;
break;
case KEY_XBUTTON_DOWN:
case KEY_XSTICK1_DOWN:
case KEY_XSTICK2_DOWN:
case KEY_DOWN:
case KEY_XBUTTON_RIGHT:
case KEY_XSTICK1_RIGHT:
case KEY_XSTICK2_RIGHT:
case KEY_RIGHT:
nDir = 1;
break;
}
if ( m_iScoreBoardKey != BUTTON_CODE_INVALID && m_iScoreBoardKey == code )
{
gViewPortInterface->ShowPanel( PANEL_SCOREBOARD, true );
gViewPortInterface->PostMessageToPanel( PANEL_SCOREBOARD, new KeyValues( "PollHideCode", "code", code ) );
}
else if ( nDir != 0 )
{
CUtlSortVector< SortedPanel_t, CSortedPanelYLess > vecSortedButtons;
VguiPanelGetSortedChildButtonList( this, (void*)&vecSortedButtons, "&", 0 );
int nNewArmed = VguiPanelNavigateSortedChildButtonList( (void*)&vecSortedButtons, nDir );
if ( nNewArmed != -1 )
{
// Handled!
if ( nNewArmed < m_mouseoverButtons.Count() )
{
m_mouseoverButtons[ nNewArmed ]->OnCursorEntered();
}
return;
}
}
else
{
BaseClass::OnKeyCodePressed( code );
}
}

View File

@@ -0,0 +1,79 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
// $NoKeywords: $
//=============================================================================//
#ifndef CLASSMENU_H
#define CLASSMENU_H
#ifdef _WIN32
#pragma once
#endif
#include <vgui_controls/Frame.h>
#include <vgui_controls/Button.h>
#include <vgui_controls/HTML.h>
#include <utlvector.h>
#include <vgui/ILocalize.h>
#include <vgui/KeyCode.h>
#include <game/client/iviewport.h>
#include "mouseoverpanelbutton.h"
namespace vgui
{
class TextEntry;
}
//-----------------------------------------------------------------------------
// Purpose: Draws the class menu
//-----------------------------------------------------------------------------
class CClassMenu : public vgui::Frame, public IViewPortPanel
{
private:
DECLARE_CLASS_SIMPLE( CClassMenu, vgui::Frame );
public:
CClassMenu(IViewPort *pViewPort);
CClassMenu(IViewPort *pViewPort, const char *panelName );
virtual ~CClassMenu();
virtual const char *GetName( void ) { return PANEL_CLASS; }
virtual void SetData(KeyValues *data);
virtual void Reset();
virtual void Update() {};
virtual bool NeedsUpdate( void ) { return false; }
virtual bool HasInputElements( void ) { return true; }
virtual void ShowPanel( bool bShow );
// both vgui::Frame and IViewPortPanel define these, so explicitly define them here as passthroughs to vgui
vgui::VPANEL GetVPanel( void ) { return BaseClass::GetVPanel(); }
virtual bool IsVisible() { return BaseClass::IsVisible(); }
virtual void SetParent( vgui::VPANEL parent ) { BaseClass::SetParent( parent ); }
protected:
virtual vgui::Panel *CreateControlByName(const char *controlName);
virtual MouseOverPanelButton* CreateNewMouseOverPanelButton(vgui::EditablePanel *panel);
//vgui2 overrides
virtual void OnKeyCodePressed(vgui::KeyCode code);
// helper functions
void SetLabelText(const char *textEntryName, const char *text);
void SetVisibleButton(const char *textEntryName, bool state);
// command callbacks
void OnCommand( const char *command );
IViewPort *m_pViewPort;
ButtonCode_t m_iScoreBoardKey;
int m_iTeam;
vgui::EditablePanel *m_pPanel;
CUtlVector< MouseOverPanelButton * > m_mouseoverButtons;
};
#endif // CLASSMENU_H

View File

@@ -0,0 +1,127 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
// $NoKeywords: $
//=============================================================================//
#ifndef CLIENTSCOREBOARDDIALOG_H
#define CLIENTSCOREBOARDDIALOG_H
#ifdef _WIN32
#pragma once
#endif
#include <vgui_controls/EditablePanel.h>
#include <game/client/iviewport.h>
#include "GameEventListener.h"
#define TYPE_NOTEAM 0 // NOTEAM must be zero :)
#define TYPE_TEAM 1 // a section for a single team
#define TYPE_PLAYERS 2
#define TYPE_SPECTATORS 3 // a section for a spectator group
#define TYPE_BLANK 4
//-----------------------------------------------------------------------------
// Purpose: Game ScoreBoard
//-----------------------------------------------------------------------------
class CClientScoreBoardDialog : public vgui::EditablePanel, public IViewPortPanel, public CGameEventListener
{
private:
DECLARE_CLASS_SIMPLE( CClientScoreBoardDialog, vgui::EditablePanel );
protected:
// column widths at 640
enum { NAME_WIDTH = 160, SCORE_WIDTH = 60, DEATH_WIDTH = 60, PING_WIDTH = 80, VOICE_WIDTH = 0, FRIENDS_WIDTH = 0 };
// total = 340
public:
CClientScoreBoardDialog( IViewPort *pViewPort );
~CClientScoreBoardDialog();
virtual const char *GetName( void ) { return PANEL_SCOREBOARD; }
virtual void SetData(KeyValues *data) {};
virtual void Reset();
virtual void Update();
virtual bool NeedsUpdate( void );
virtual bool HasInputElements( void ) { return true; }
virtual void ShowPanel( bool bShow );
virtual bool ShowAvatars()
{
#ifdef CSS_PERF_TEST
return false;
#endif
return IsPC();
}
// both vgui::Frame and IViewPortPanel define these, so explicitly define them here as passthroughs to vgui
vgui::VPANEL GetVPanel( void ) { return BaseClass::GetVPanel(); }
virtual bool IsVisible() { return BaseClass::IsVisible(); }
virtual void SetParent( vgui::VPANEL parent ) { BaseClass::SetParent( parent ); }
// IGameEventListener interface:
virtual void FireGameEvent( IGameEvent *event);
virtual void UpdatePlayerAvatar( int playerIndex, KeyValues *kv );
protected:
MESSAGE_FUNC_INT( OnPollHideCode, "PollHideCode", code );
// functions to override
virtual bool GetPlayerScoreInfo(int playerIndex, KeyValues *outPlayerInfo);
virtual void InitScoreboardSections();
virtual void UpdateTeamInfo();
virtual void UpdatePlayerInfo();
virtual void OnThink();
virtual void AddHeader(); // add the start header of the scoreboard
virtual void AddSection(int teamType, int teamNumber); // add a new section header for a team
virtual int GetAdditionalHeight() { return 0; }
// sorts players within a section
static bool StaticPlayerSortFunc(vgui::SectionedListPanel *list, int itemID1, int itemID2);
virtual void ApplySchemeSettings(vgui::IScheme *pScheme);
virtual void PostApplySchemeSettings( vgui::IScheme *pScheme );
// finds the player in the scoreboard
int FindItemIDForPlayerIndex(int playerIndex);
int m_iNumTeams;
vgui::SectionedListPanel *m_pPlayerList;
int m_iSectionId; // the current section we are entering into
int s_VoiceImage[5];
int TrackerImage;
int m_HLTVSpectators;
int m_ReplaySpectators;
float m_fNextUpdateTime;
void MoveLabelToFront(const char *textEntryName);
void MoveToCenterOfScreen();
vgui::ImageList *m_pImageList;
CUtlMap<CSteamID,int> m_mapAvatarsToImageList;
CPanelAnimationVar( int, m_iAvatarWidth, "avatar_width", "34" ); // Avatar width doesn't scale with resolution
CPanelAnimationVarAliasType( int, m_iNameWidth, "name_width", "136", "proportional_int" );
CPanelAnimationVarAliasType( int, m_iClassWidth, "class_width", "35", "proportional_int" );
CPanelAnimationVarAliasType( int, m_iScoreWidth, "score_width", "35", "proportional_int" );
CPanelAnimationVarAliasType( int, m_iDeathWidth, "death_width", "35", "proportional_int" );
CPanelAnimationVarAliasType( int, m_iPingWidth, "ping_width", "23", "proportional_int" );
private:
int m_iPlayerIndexSymbol;
int m_iDesiredHeight;
IViewPort *m_pViewPort;
ButtonCode_t m_nCloseKey;
// methods
void FillScoreBoard();
};
#endif // CLIENTSCOREBOARDDIALOG_H

View File

@@ -0,0 +1,361 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
// $NoKeywords: $
//===========================================================================//
#include "cbase.h"
#include <cdll_client_int.h>
#include <cdll_util.h>
#include <globalvars_base.h>
#include <icvar.h>
#include <filesystem.h>
#include "commandmenu.h"
#include "vgui_controls/MenuItem.h"
// memdbgon must be the last include file in a .cpp file!!!
#include "tier0/memdbgon.h"
CommandMenu::CommandMenu( Panel *parent, const char *panelName, IViewPort * viewport) : Menu( parent, panelName )
{
if ( !viewport )
return;
m_ViewPort = viewport;
SetVisible( false );
m_CurrentMenu = this;
m_MenuKeys = NULL;
}
bool CommandMenu::LoadFromFile( const char * fileName) // load menu from KeyValues
{
KeyValues * kv = new KeyValues(fileName);
if ( !kv->LoadFromFile( g_pFullFileSystem, fileName, "GAME" ) )
return false;
bool ret = LoadFromKeyValues( kv );
kv->deleteThis();
return ret;
}
CommandMenu::~CommandMenu()
{
ClearMenu();
}
void CommandMenu::OnMessage(const KeyValues *params, VPANEL fromPanel)
{
char text[255];
bool bHandled = false;
KeyValues *param1 = const_cast<KeyValues *>(params);
// toggle attached cvar, if any
Q_strncpy( text, param1->GetString("toggle"), sizeof( text ) );
if ( text[0] )
{
ConVarRef convar( text );
if ( convar.IsValid() )
{
// toggle cvar
if ( convar.GetInt() )
{
convar.SetValue( 0 );
}
else
{
convar.SetValue( 1 );
}
UpdateMenu();
}
else
{
Msg("CommandComboBox::OnMessage: cvar %s not found.\n", param1->GetString("typedata") );
}
bHandled = true;
}
// execute attached command, if any
Q_strncpy( text, param1->GetString("command"), sizeof( text ) );
if ( text[0] )
{
engine->ClientCmd( text );
bHandled = true;
}
// fire custom message, if any
Q_strncpy( text, param1->GetString("custom"), sizeof( text ) );
if ( text[0] )
{
OnCustomItem( param1 ); // let derived class decide what to do
bHandled = true;
}
if ( bHandled )
{
PostMessage( GetParent(), new KeyValues("CommandMenuClosed") );
}
BaseClass::OnMessage( params, fromPanel );
}
void CommandMenu::StartNewSubMenu(KeyValues * params)
{
CommandMenuItem menuitem;
menuitem.menu = m_CurrentMenu;
Menu * menu = new Menu( this, params->GetString("name") ); // create new menu
menuitem.itemnr = m_CurrentMenu->AddCascadingMenuItem( params->GetString("label"), this, menu, params ); // add to current menu as item
m_MenuItems.AddToTail( menuitem ); // add to global list
m_pMenuStack.Push( m_CurrentMenu ); // remember current menu
m_CurrentMenu = menu; // continue adding items in new menu
}
void CommandMenu::FinishSubMenu()
{
m_CurrentMenu = m_pMenuStack.Top(); // get menu one level above
m_pMenuStack.Pop(); // remove it from stack
}
void CommandMenu::AddMenuCommandItem(KeyValues * params)
{
CommandMenuItem menuitem; // create new menuItem
menuitem.menu = m_CurrentMenu; // save the current menu context
menuitem.itemnr = m_CurrentMenu->AddMenuItem( params->GetString("label"), params->MakeCopy(), this, params ); // add it
m_MenuItems.AddToTail( menuitem ); // add to global list
}
void CommandMenu::AddMenuToggleItem(KeyValues * params)
{
CommandMenuItem menuitem; // create new menuItem
menuitem.menu = m_CurrentMenu; // save the current menu context
menuitem.itemnr = m_CurrentMenu->AddCheckableMenuItem( params->GetString("label"), params->MakeCopy(), this, params ); // add it
m_MenuItems.AddToTail( menuitem ); // add to global list
}
void CommandMenu::AddMenuCustomItem(KeyValues * params)
{
CommandMenuItem menuitem; // create new menuItem
menuitem.menu = m_CurrentMenu; // save the current menu context
menuitem.itemnr = AddCustomItem( params, m_CurrentMenu );
m_MenuItems.AddToTail( menuitem ); // add to global list
}
void CommandMenu::ClearMenu()
{
SetVisible( false );
m_pMenuStack.Clear();
m_MenuItems.RemoveAll();
// DeleteAllItems();
MarkForDeletion();
if ( m_MenuKeys )
{
m_MenuKeys->deleteThis();
m_MenuKeys = NULL;
}
}
void CommandMenu::RebuildMenu()
{
if ( !m_MenuKeys )
return;
m_pMenuStack.Clear();
m_MenuItems.RemoveAll();
DeleteAllItems();
LoadFromKeyValues( m_MenuKeys ); // and reload respecting new team, mapname etc.
}
void CommandMenu::UpdateMenu()
{
char text[255];
int num = m_MenuItems.Count();
for (int i=0; i < num; i++)
{
CommandMenuItem menuitem = m_MenuItems.Element(i);
KeyValues * keys = menuitem.menu->GetItemUserData( menuitem.itemnr );
if ( !keys )
continue;
// let custom menu items update themself
Q_strncpy( text, keys->GetString("custom"), sizeof(text) );
if ( text[0] )
{
// let derived class modify the menu item
UpdateCustomItem( keys, menuitem.menu->GetMenuItem(menuitem.itemnr) );
continue;
}
// update toggle buttons
Q_strncpy( text, keys->GetString("toggle"), sizeof(text) );
if ( text[0] )
{
// set toggle state equal to cvar state
ConVarRef convar( text );
if ( convar.IsValid() )
{
menuitem.menu->SetMenuItemChecked( menuitem.itemnr, convar.GetBool() );
}
}
}
}
void CommandMenu::SetVisible(bool state)
{
if ( state && !IsVisible() )
{
UpdateMenu();
}
BaseClass::SetVisible( state );
}
bool CommandMenu::CheckRules(const char *rule, const char *ruledata)
{
if ( !rule || !ruledata )
{
return true; // no rule defined, show item
}
if ( Q_strcmp( rule, "team") == 0 )
{
// if team is same as specified in rule, show item
return ( Q_strcmp( m_CurrentTeam, ruledata ) == 0 );
}
else if ( Q_strcmp( rule, "map") == 0 )
{
// if team is same as specified in rule, show item
return ( Q_strcmp( m_CurrentMap, ruledata ) == 0 );
}
return true;
}
KeyValues * CommandMenu::GetKeyValues()
{
return m_MenuKeys;
}
bool CommandMenu::LoadFromKeyValues( KeyValues * params )
{
if ( !params )
return false;
Q_snprintf( m_CurrentTeam, 4, "%i", GetLocalPlayerTeam() );
Q_FileBase( engine->GetLevelName(), m_CurrentMap, sizeof(m_CurrentMap) );
if ( params != m_MenuKeys )
{
if ( m_MenuKeys )
m_MenuKeys->deleteThis();
m_MenuKeys = params->MakeCopy(); // save keyvalues
}
// iterate through all menu items
KeyValues * subkey = m_MenuKeys->GetFirstSubKey();
while ( subkey )
{
if ( subkey->GetDataType() == KeyValues::TYPE_NONE )
{
if ( !LoadFromKeyValuesInternal( subkey, 0 ) ) // recursive call
return false;
}
subkey = subkey->GetNextKey();
}
UpdateMenu();
return true;
}
bool CommandMenu::LoadFromKeyValuesInternal(KeyValues * key, int depth)
{
char text[255];
KeyValues * subkey = NULL;
if ( depth > 100 )
{
Msg("CommandMenu::LoadFromKeyValueInternal: depth > 100.\n");
return false;
}
Q_strncpy( text, key->GetString("custom"), sizeof(text) ); // get type
if ( text[0] )
{
AddMenuCustomItem( key ); // do whatever custom item wants to
return true;
}
if ( !CheckRules( key->GetString("rule"), key->GetString("ruledata") ) )
{
return true;
}
// rules OK add subkey
Q_strncpy( text, key->GetString("toggle"), sizeof(text) ); // get type
if ( text[0] )
{
AddMenuToggleItem( key );
return true;
}
Q_strncpy( text, key->GetString("command"), sizeof(text) ); // get type
if ( text[0] )
{
AddMenuCommandItem( key );
return true;
}
// not a command, nor a toggle. Must be a submenu:
StartNewSubMenu( key ); // create submenu
// iterate through all subkeys
subkey = key->GetFirstSubKey();
while ( subkey )
{
if ( subkey->GetDataType() == KeyValues::TYPE_NONE )
{
LoadFromKeyValuesInternal( subkey, depth+1 ); // recursive call
}
subkey = subkey->GetNextKey();
}
FinishSubMenu(); // go one level back
return true;
}

View File

@@ -0,0 +1,77 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
// $NoKeywords: $
//=============================================================================
#ifndef COMMANDMENU_H
#define COMMANDMENU_H
#include <vgui_controls/Menu.h>
#include <game/client/iviewport.h>
#include <filesystem.h>
#include "utlstack.h"
#include "utlvector.h"
#include <KeyValues.h>
using namespace vgui;
class CommandMenu : public Menu
{
private:
DECLARE_CLASS_SIMPLE( CommandMenu, Menu );
typedef struct
{
Menu * menu;
int itemnr;
} CommandMenuItem;
public:
CommandMenu( Panel *parent, const char *panelName, IViewPort * viewport );
~CommandMenu();
bool LoadFromFile(const char * fileName); // load menu from file (via KeyValues)
void UpdateMenu(); // call to update all menu items, check buttons etc
void RebuildMenu(); // rebuilds menu respecting changed game state (map, team etc)
void ClearMenu(); // destroy menu
public:
// overwrite these in your derived class
// virtual CommandMenu * CommandMenu::Factory(Panel *parent, const char *panelName, IViewPort * viewport = NULL, IFileSystem * pFileSytem = NULL); // overwrite
virtual int AddCustomItem(KeyValues * params, Menu * menu) {return 0;} // return MenuItem nr
virtual void UpdateCustomItem(KeyValues * params, MenuItem * item ) {}; // maybe change your item
virtual void OnCustomItem(KeyValues * params) {}; // a custom item was pressed
virtual bool CheckRules(const char *rule, const char *ruledata); // check a menu item rule
virtual void SetVisible(bool state);
// DON'T touch anything below !
protected:
void OnMessage(const KeyValues *params, VPANEL fromPanel);
void StartNewSubMenu(KeyValues * params);
void FinishSubMenu();
void AddMenuCommandItem(KeyValues * params);
void AddMenuCustomItem(KeyValues * params);
void AddMenuToggleItem(KeyValues * params);
bool LoadFromKeyValuesInternal(KeyValues * key, int depth);
bool LoadFromKeyValues( KeyValues * key); //
KeyValues * GetKeyValues(); // returns keyValues for current menu or NULL
IViewPort * m_ViewPort; // viewport interface
Menu * m_CurrentMenu; // Current menu while building CommandComoboBox
char m_CurrentTeam[4];
char m_CurrentMap[256];
KeyValues* m_MenuKeys;
CUtlStack<vgui::Menu*>m_pMenuStack;
CUtlVector<CommandMenuItem>m_MenuItems;
};
#endif // COMMANDMENU_H

View File

@@ -0,0 +1,256 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
// $NoKeywords: $
//=============================================================================//
#ifndef IMAGE_MOUSE_OVER_BUTTON_H
#define IMAGE_MOUSE_OVER_BUTTON_H
#include "vgui/ISurface.h"
#include "vgui/IScheme.h"
#include "mouseoverpanelbutton.h"
//===============================================
// CImageMouseOverButton - used for class images
//===============================================
template <class T>
class CImageMouseOverButton : public MouseOverButton<T>
{
private:
//DECLARE_CLASS_SIMPLE( CImageMouseOverButton, MouseOverButton );
public:
CImageMouseOverButton( vgui::Panel *parent, const char *panelName, T *templatePanel );
virtual void ApplySettings( KeyValues *inResourceData );
virtual void ApplySchemeSettings( vgui::IScheme *pScheme );
virtual void OnSizeChanged( int newWide, int newTall );
void RecalculateImageSizes( void );
void SetActiveImage( const char *imagename );
void SetInactiveImage( const char *imagename );
void SetActiveImage( vgui::IImage *image );
void SetInactiveImage( vgui::IImage *image );
public:
virtual void Paint();
virtual void ShowPage( void );
virtual void HidePage( void );
private:
vgui::IImage *m_pActiveImage;
char *m_pszActiveImageName;
vgui::IImage *m_pInactiveImage;
char *m_pszInactiveImageName;
bool m_bScaleImage;
};
template <class T>
CImageMouseOverButton<T>::CImageMouseOverButton( vgui::Panel *parent, const char *panelName, T *templatePanel ) :
MouseOverButton<T>( parent, panelName, templatePanel )
{
m_pszActiveImageName = NULL;
m_pszInactiveImageName = NULL;
m_pActiveImage = NULL;
m_pInactiveImage = NULL;
}
template <class T>
void CImageMouseOverButton<T>::ApplySettings( KeyValues *inResourceData )
{
m_bScaleImage = inResourceData->GetInt( "scaleImage", 0 );
// Active Image
delete [] m_pszActiveImageName;
m_pszActiveImageName = NULL;
const char *activeImageName = inResourceData->GetString( "activeimage", "" );
if ( *activeImageName )
{
this->SetActiveImage( activeImageName );
}
// Inactive Image
delete [] m_pszInactiveImageName;
m_pszInactiveImageName = NULL;
const char *inactiveImageName = inResourceData->GetString( "inactiveimage", "" );
if ( *inactiveImageName )
{
this->SetInactiveImage( inactiveImageName );
}
MouseOverButton<T>::ApplySettings( inResourceData );
this->InvalidateLayout( false, true ); // force applyschemesettings to run
}
template <class T>
void CImageMouseOverButton<T>::ApplySchemeSettings( vgui::IScheme *pScheme )
{
MouseOverButton<T>::ApplySchemeSettings( pScheme );
if ( m_pszActiveImageName && strlen( m_pszActiveImageName ) > 0 )
{
this->SetActiveImage( vgui::scheme()->GetImage( m_pszActiveImageName, m_bScaleImage ) );
}
if ( m_pszInactiveImageName && strlen( m_pszInactiveImageName ) > 0 )
{
this->SetInactiveImage( vgui::scheme()->GetImage( m_pszInactiveImageName, m_bScaleImage ) );
}
vgui::IBorder *pBorder = pScheme->GetBorder( "NoBorder" );
this->SetDefaultBorder( pBorder);
this->SetDepressedBorder( pBorder );
this->SetKeyFocusBorder( pBorder );
Color blank(0,0,0,0);
this->SetDefaultColor( this->GetButtonFgColor(), blank );
this->SetArmedColor( this->GetButtonArmedFgColor(), blank );
this->SetDepressedColor( this->GetButtonDepressedFgColor(), blank );
}
template <class T>
void CImageMouseOverButton<T>::RecalculateImageSizes( void )
{
// Reset our images, which will force them to recalculate their size.
// Necessary for images shared with other scaling buttons.
this->SetActiveImage( m_pActiveImage );
this->SetInactiveImage( m_pInactiveImage );
}
template <class T>
void CImageMouseOverButton<T>::SetActiveImage( const char *imagename )
{
int len = Q_strlen( imagename ) + 1;
m_pszActiveImageName = new char[ len ];
Q_strncpy( m_pszActiveImageName, imagename, len );
}
template <class T>
void CImageMouseOverButton<T>::SetInactiveImage( const char *imagename )
{
int len = Q_strlen( imagename ) + 1;
m_pszInactiveImageName = new char[ len ];
Q_strncpy( m_pszInactiveImageName, imagename, len );
}
template <class T>
void CImageMouseOverButton<T>::SetActiveImage( vgui::IImage *image )
{
m_pActiveImage = image;
if ( m_pActiveImage )
{
int wide, tall;
if ( m_bScaleImage )
{
// scaling, force the image size to be our size
this->GetSize( wide, tall );
m_pActiveImage->SetSize( wide, tall );
}
else
{
// not scaling, so set our size to the image size
m_pActiveImage->GetSize( wide, tall );
this->SetSize( wide, tall );
}
}
this->Repaint();
}
template <class T>
void CImageMouseOverButton<T>::SetInactiveImage( vgui::IImage *image )
{
m_pInactiveImage = image;
if ( m_pInactiveImage )
{
int wide, tall;
if ( m_bScaleImage)
{
// scaling, force the image size to be our size
this->GetSize( wide, tall );
m_pInactiveImage->SetSize( wide, tall );
}
else
{
// not scaling, so set our size to the image size
m_pInactiveImage->GetSize( wide, tall );
this->SetSize( wide, tall );
}
}
this->Repaint();
}
template <class T>
void CImageMouseOverButton<T>::OnSizeChanged( int newWide, int newTall )
{
if ( m_bScaleImage )
{
// scaling, force the image size to be our size
if ( m_pActiveImage )
m_pActiveImage->SetSize( newWide, newTall );
if ( m_pInactiveImage )
m_pInactiveImage->SetSize( newWide, newTall );
}
MouseOverButton<T>::OnSizeChanged( newWide, newTall );
}
template <class T>
void CImageMouseOverButton<T>::Paint()
{
this->SetActiveImage( m_pActiveImage );
this->SetInactiveImage( m_pInactiveImage );
if ( this->IsArmed() )
{
// draw the active image
if ( m_pActiveImage )
{
vgui::surface()->DrawSetColor( 255, 255, 255, 255 );
m_pActiveImage->SetPos( 0, 0 );
m_pActiveImage->Paint();
}
}
else
{
// draw the inactive image
if ( m_pInactiveImage )
{
vgui::surface()->DrawSetColor( 255, 255, 255, 255 );
m_pInactiveImage->SetPos( 0, 0 );
m_pInactiveImage->Paint();
}
}
MouseOverButton<T>::Paint();
}
template <class T>
void CImageMouseOverButton<T>::ShowPage( void )
{
MouseOverButton<T>::ShowPage();
// send message to parent that we triggered something
this->PostActionSignal( new KeyValues( "ShowPage", "page", this->GetName() ) );
}
template <class T>
void CImageMouseOverButton<T>::HidePage( void )
{
MouseOverButton<T>::HidePage();
}
#endif //IMAGE_MOUSE_OVER_BUTTON_H

View File

@@ -0,0 +1,122 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
//=============================================================================
#include "cbase.h"
#include "intromenu.h"
#include <networkstringtabledefs.h>
#include <cdll_client_int.h>
#include <vgui/IScheme.h>
#include <vgui/ILocalize.h>
#include <vgui/ISurface.h>
#include <filesystem.h>
#include <KeyValues.h>
#include <convar.h>
#include <game/client/iviewport.h>
#include "spectatorgui.h"
#include "gamerules.h"
// memdbgon must be the last include file in a .cpp file!!!
#include "tier0/memdbgon.h"
using namespace vgui;
//-----------------------------------------------------------------------------
// Purpose: Constructor
//-----------------------------------------------------------------------------
CIntroMenu::CIntroMenu( IViewPort *pViewPort ) : Frame( NULL, PANEL_INTRO )
{
// initialize dialog
m_pViewPort = pViewPort;
m_pTitleLabel = NULL;
// load the new scheme early!!
SetScheme( "ClientScheme" );
SetMoveable( false );
SetSizeable( false );
SetProportional( true );
// hide the system buttons
SetTitleBarVisible( false );
Reset();
}
//-----------------------------------------------------------------------------
// Purpose: Destructor
//-----------------------------------------------------------------------------
CIntroMenu::~CIntroMenu()
{
}
//-----------------------------------------------------------------------------
// Purpose: Sets the color of the top and bottom bars
//-----------------------------------------------------------------------------
void CIntroMenu::ApplySchemeSettings( IScheme *pScheme )
{
BaseClass::ApplySchemeSettings( pScheme );
LoadControlSettings("Resource/UI/IntroMenu.res");
m_pTitleLabel = dynamic_cast<Label *>( FindChildByName( "titlelabel" ) );
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CIntroMenu::Reset( void )
{
Update();
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CIntroMenu::Update( void )
{
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CIntroMenu::OnCommand( const char *command )
{
if ( !Q_strcmp( command, "skip" ) )
{
engine->ClientCmd( "intro_skip" );
m_pViewPort->ShowPanel( this, false );
}
BaseClass::OnCommand( command );
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CIntroMenu::ShowPanel( bool bShow )
{
if ( BaseClass::IsVisible() == bShow )
return;
m_pViewPort->ShowBackGround( bShow );
if ( bShow )
{
Activate();
if ( GameRules() )
{
SetDialogVariable( "gamemode", g_pVGuiLocalize->Find( GameRules()->GetGameTypeName() ) );
}
SetMouseInputEnabled( true );
}
else
{
SetVisible( false );
SetMouseInputEnabled( false );
}
}

View File

@@ -0,0 +1,57 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
//=============================================================================
#ifndef INTROMENU_H
#define INTROMENU_H
#ifdef _WIN32
#pragma once
#endif
#include <vgui_controls/Frame.h>
#include <vgui_controls/Button.h>
#include <vgui_controls/Label.h>
#include <game/client/iviewport.h>
namespace vgui
{
class TextEntry;
}
class CIntroMenu : public vgui::Frame, public IViewPortPanel
{
private:
DECLARE_CLASS_SIMPLE( CIntroMenu, vgui::Frame );
public:
CIntroMenu( IViewPort *pViewPort );
virtual ~CIntroMenu();
virtual void ApplySchemeSettings( vgui::IScheme *pScheme );
virtual const char *GetName( void ){ return PANEL_INTRO; }
virtual void SetData( KeyValues *data ){ return; }
virtual void Reset();
virtual void Update();
virtual bool NeedsUpdate( void ) { return false; }
virtual bool HasInputElements( void ) { return true; }
virtual void ShowPanel( bool bShow );
// both vgui::Frame and IViewPortPanel define these, so explicitly define them here as passthroughs to vgui
vgui::VPANEL GetVPanel( void ) { return BaseClass::GetVPanel(); }
virtual bool IsVisible() { return BaseClass::IsVisible(); }
virtual void SetParent( vgui::VPANEL parent ) { BaseClass::SetParent( parent ); }
protected:
// vgui overrides
virtual void OnCommand( const char *command );
IViewPort *m_pViewPort;
vgui::Label *m_pTitleLabel;
};
#endif // INTROMENU_H

View File

@@ -0,0 +1,275 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose: MiniMap.h: interface for the CMiniMap class.
//
// $NoKeywords: $
//=============================================================================//
#if !defined HLTVPANEL_H
#define HLTVPANEL_H
#ifdef _WIN32
#pragma once
#endif
#include <vgui_controls/Panel.h>
#include <game/client/iviewport.h>
#include "mathlib/vector.h"
#include <igameevents.h>
#include <shareddefs.h>
#include <const.h>
#include "hudelement.h"
class IMapOverviewPanel
{
public:
virtual void SetMode( int mode ) = 0;
virtual int GetMode( void ) = 0;
virtual void FlashEntity( int entityID ) = 0;
virtual void SetPlayerPositions(int index, const Vector &position, const QAngle &angle) = 0;
virtual void SetVisible(bool state) = 0;
virtual float GetZoom( void ) = 0;
virtual vgui::Panel *GetAsPanel() = 0;
virtual bool AllowConCommandsWhileAlive() = 0;
virtual void SetPlayerPreferredMode( int mode ) = 0;
virtual void SetPlayerPreferredViewSize( float viewSize ) = 0;
virtual bool IsVisible() = 0;
virtual void GetBounds(int &x, int &y, int &wide, int &tall) = 0;
virtual float GetFullZoom( void ) = 0;
virtual float GetMapScale( void ) = 0;
};
#define MAX_TRAIL_LENGTH 30
#define OVERVIEW_MAP_SIZE 1024 // an overview map is 1024x1024 pixels
typedef bool ( *FnCustomMapOverviewObjectPaint )( int textureID, Vector pos, float scale, float angle, const char *text, Color *textColor, float status, Color *statusColor );
class CMapOverview : public CHudElement, public vgui::Panel, public IMapOverviewPanel
{
DECLARE_CLASS_SIMPLE( CMapOverview, vgui::Panel );
public:
enum
{
MAP_MODE_OFF = 0, // Totally off
MAP_MODE_INSET, // A little map up in a corner
MAP_MODE_FULL, // Full screen, full map
MAP_MODE_RADAR // In game radar, extra functionality
};
CMapOverview( const char *pElementName );
virtual ~CMapOverview();
virtual bool ShouldDraw( void );
vgui::Panel *GetAsPanel(){ return this; }
virtual bool AllowConCommandsWhileAlive(){return true;}
virtual void SetPlayerPreferredMode( int mode ){}
virtual void SetPlayerPreferredViewSize( float viewSize ){};
protected: // private structures & types
float GetViewAngle( void ); // The angle that determines the viewport twist from map texture to panel drawing.
// list of game events the hLTV takes care of
typedef struct {
int xpos;
int ypos;
} FootStep_t;
typedef struct MapPlayer_s {
int index; // player's index
int userid; // user ID on server
int icon; // players texture icon ID
Color color; // players team color
char name[MAX_PLAYER_NAME_LENGTH];
int team; // N,T,CT
int health; // 0..100, 7 bit
Vector position; // current x,y pos
QAngle angle; // view origin 0..360
Vector2D trail[MAX_TRAIL_LENGTH]; // save 1 footstep each second for 1 minute
} MapPlayer_t;
typedef struct MapObject_s {
int objectID; // unique object ID
int index; // entity index if any
int icon; // players texture icon ID
Color color; // players team color
char name[MAX_PLAYER_NAME_LENGTH]; // show text under icon
Vector position; // current x,y pos
QAngle angle; // view origin 0..360
float endtime; // time stop showing object
float size; // object size
float status; // green status bar [0..1], -1 = disabled
Color statusColor; // color of status bar
int flags; // MAB_OBJECT_*
const char *text; // text to draw underneath the icon
} MapObject_t;
#define MAP_OBJECT_ALIGN_TO_MAP (1<<0)
public: // IViewPortPanel interface:
virtual const char *GetName( void ) { return PANEL_OVERVIEW; }
virtual void SetData(KeyValues *data);
virtual void Reset();
virtual void OnThink();
virtual void Update();
virtual bool NeedsUpdate( void );
virtual bool HasInputElements( void ) { return false; }
virtual void ShowPanel( bool bShow );
virtual void Init( void );
// both vgui::Frame and IViewPortPanel define these, so explicitly define them here as passthroughs to vgui
vgui::VPANEL GetVPanel( void ) { return BaseClass::GetVPanel(); }
virtual bool IsVisible() { return BaseClass::IsVisible(); }
virtual void GetBounds(int &x, int &y, int &wide, int &tall) { BaseClass::GetBounds(x, y, wide, tall); }
virtual void SetParent(vgui::VPANEL parent) { BaseClass::SetParent(parent); }
public: // IGameEventListener
virtual void FireGameEvent( IGameEvent *event);
public: // VGUI overrides
virtual void Paint();
virtual void OnMousePressed( vgui::MouseCode code );
virtual void ApplySchemeSettings(vgui::IScheme *scheme);
virtual void SetVisible(bool state){BaseClass::SetVisible(state);}
public:
virtual float GetZoom( void );
virtual int GetMode( void );
virtual float GetFullZoom( void ){ return m_fFullZoom; }
virtual float GetMapScale( void ){ return m_fMapScale; }
// Player settings:
virtual void ShowPlayerNames(bool state);
virtual void ShowPlayerHealth(bool state);
virtual void ShowPlayerTracks(float seconds);
virtual void SetPlayerPositions(int index, const Vector &position, const QAngle &angle);
// general settings:
virtual void SetMap(const char * map);
virtual void SetTime( float time );
virtual void SetMode( int mode );
virtual bool SetTeamColor(int team, Color color);
virtual void SetFollowAngle(bool state);
virtual void SetFollowEntity(int entindex); // 0 = off
virtual void SetCenter( const Vector2D &mappos);
virtual void SetAngle( float angle);
virtual Vector2D WorldToMap( const Vector &worldpos );
// Object settings
virtual int AddObject( const char *icon, int entity, float timeToLive ); // returns object ID, 0 = no entity, -1 = forever
virtual void SetObjectIcon( int objectID, const char *icon, float size ); // icon world size
virtual void SetObjectText( int objectID, const char *text, Color color ); // text under icon
virtual void SetObjectStatus( int objectID, float value, Color statusColor ); // status bar under icon
virtual void SetObjectPosition( int objectID, const Vector &position, const QAngle &angle ); // world pos/angles
virtual void AddObjectFlags( int objectID, int flags );
virtual void SetObjectFlags( int objectID, int flags );
virtual void RemoveObject( int objectID );
virtual void RemoveObjectByIndex( int index );
virtual void FlashEntity( int entityID ){}
// rules that define if you can see a player on the overview or not
virtual bool CanPlayerBeSeen(MapPlayer_t *player);
/// allows mods to restrict health
virtual bool CanPlayerHealthBeSeen(MapPlayer_t *player);
/// allows mods to restrict names (e.g. CS when mp_playerid is non-zero)
virtual bool CanPlayerNameBeSeen(MapPlayer_t *player);
virtual int GetIconNumberFromTeamNumber( int teamNumber ){return teamNumber;}
protected:
virtual void DrawCamera();
virtual void DrawObjects();
virtual void DrawMapTexture();
virtual void DrawMapPlayers();
virtual void DrawMapPlayerTrails();
virtual void UpdatePlayerTrails();
virtual void ResetRound();
virtual void InitTeamColorsAndIcons();
virtual void UpdateSizeAndPosition();
virtual bool RunHudAnimations(){ return true; }
bool IsInPanel(Vector2D &pos);
MapPlayer_t* GetPlayerByUserID( int userID );
int AddIconTexture(const char *filename);
Vector2D MapToPanel( const Vector2D &mappos );
int GetPixelOffset( float height );
void UpdateFollowEntity();
virtual void UpdatePlayers();
void UpdateObjects(); // objects bound to entities
MapObject_t* FindObjectByID(int objectID);
virtual bool IsRadarLocked() {return false;}
virtual bool DrawIcon( MapObject_t *obj );
/*virtual bool DrawIcon( int textureID,
int offscreenTextureID,
Vector pos,
float scale,
float angle,
int alpha = 255,
const char *text = NULL,
Color *textColor = NULL,
float status = -1,
Color *statusColor = NULL,
int objectType = OBJECT_TYPE_NORMAL );*/
int m_nMode;
Vector2D m_vPosition;
Vector2D m_vSize;
float m_flChangeSpeed;
float m_flIconSize;
IViewPort * m_pViewPort;
MapPlayer_t m_Players[MAX_PLAYERS];
CUtlDict< int, int> m_TextureIDs;
CUtlVector<MapObject_t> m_Objects;
Color m_TeamColors[MAX_TEAMS];
int m_TeamIcons[MAX_TEAMS];
int m_ObjectIcons[64];
int m_ObjectCounterID;
vgui::HFont m_hIconFont;
bool m_bShowNames;
bool m_bShowTrails;
bool m_bShowHealth;
int m_nMapTextureID; // texture id for current overview image
KeyValues * m_MapKeyValues; // keyvalues describing overview parameters
Vector m_MapOrigin; // read from KeyValues files
float m_fMapScale; // origin and scale used when screenshot was made
bool m_bRotateMap; // if true roatate map around 90 degress, so it fits better to 4:3 screen ratio
int m_nFollowEntity;// entity number to follow, 0 = off
CPanelAnimationVar( float, m_fZoom, "zoom", "1.0" ); // current zoom n = overview panel shows 1/n^2 of whole map'
float m_fFullZoom; // best zoom factor for full map view (1.0 is map is a square)
Vector2D m_ViewOrigin; // map coordinates that are in the center of the pverview panel
Vector2D m_MapCenter; // map coordinates that are in the center of the pverview panel
float m_fNextUpdateTime;
float m_fViewAngle; // rotation of overview map
float m_fWorldTime; // current world time
float m_fNextTrailUpdate; // next time to update player trails
float m_fTrailUpdateInterval; // if -1 don't show trails
bool m_bFollowAngle; // if true, map rotates with view angle
};
extern IMapOverviewPanel *g_pMapOverview;
#endif //

View File

@@ -0,0 +1,119 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
// $NoKeywords: $
//=============================================================================//
#ifndef MOUSEOVERHTMLBUTTON_H
#define MOUSEOVERHTMLBUTTON_H
#ifdef _WIN32
#pragma once
#endif
//-----------------------------------------------------------------------------
// Purpose: Triggers a new html page when the mouse goes over the button
//-----------------------------------------------------------------------------
class MouseOverHTMLButton : public vgui::Button
{
public:
MouseOverHTMLButton(vgui::Panel *parent, const char *panelName, vgui::HTML *html, const char *page) :
Button( parent, panelName, "MouseOverHTMLButton")
{
m_pHTML = html;
m_iClass = 0;
m_iIndex = -1;
m_bAddShortCut = true;
if ( page )
{
Q_strncpy( m_sPage, page, sizeof( m_sPage ) );
}
else
{
memset(m_sPage, 0x0, sizeof( m_sPage ) );
}
}
void SetClass(int pClass, int index) { m_iClass = pClass; m_iIndex = index;}
int GetClass() { return m_iClass; }
void SetAddHotKey( bool state ) { m_bAddShortCut = state; }
void SetPage( const char *page )
{
if ( page )
{
Q_strncpy( m_sPage, page, sizeof( m_sPage ) );
}
else
{
memset(m_sPage, 0x0, sizeof( m_sPage ) );
}
}
void SetHTML( vgui::HTML *html)
{
m_pHTML = html;
}
private:
virtual void OnCursorEntered()
{
Button::OnCursorEntered();
if ( m_pHTML && strlen(m_sPage) > 0 )
{
m_pHTML->OpenURL(m_sPage);
}
}
virtual void SetText(const char *text)
{
if ( m_iIndex != -1 )
{
wchar_t newText[ 128 ];
wchar_t localizeText[ 128 ];
wchar_t *ansiLocal;
if ( text[0] == '#' && ( ansiLocal = g_pVGuiLocalize->Find( text ) ) )
{
// wcsncpy will crash if ansiLocal is null... *sigh*
wcsncpy(localizeText, ansiLocal, sizeof(localizeText)/sizeof(wchar_t));
}
else
{
g_pVGuiLocalize->ConvertANSIToUnicode( text, localizeText, sizeof( localizeText ) );
}
if ( m_bAddShortCut )
{
#ifdef WIN32
_snwprintf( newText, sizeof( newText )/ sizeof( wchar_t ), L"&%i %s", m_iIndex, localizeText);
#else
_snwprintf( newText, sizeof( newText )/ sizeof( wchar_t ), L"&%i %S", m_iIndex, localizeText);
#endif
}
else
{
memcpy( newText, localizeText, sizeof( newText ) );
}
Button::SetText( newText );
}
else
{
Button::SetText( text );
}
}
vgui::HTML *m_pHTML;
char m_sPage[ 255 ];
int m_iClass;
int m_iIndex;
bool m_bAddShortCut;
};
#endif // MOUSEOVERHTMLBUTTON_H

View File

@@ -0,0 +1,186 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
// $NoKeywords: $
//=============================================================================//
#ifndef MOUSEOVERPANELBUTTON_H
#define MOUSEOVERPANELBUTTON_H
#ifdef _WIN32
#pragma once
#endif
#include <vgui/IScheme.h>
#include <vgui_controls/Button.h>
#include <vgui/KeyCode.h>
#include <filesystem.h>
extern vgui::Panel *g_lastPanel;
extern vgui::Button *g_lastButton;
//-----------------------------------------------------------------------------
// Purpose: Triggers a new panel when the mouse goes over the button
//
// the new panel has the same dimensions as the passed templatePanel and is of
// the same class.
//
// must at least inherit from vgui::EditablePanel to support LoadControlSettings
//-----------------------------------------------------------------------------
template <class T>
class MouseOverButton : public vgui::Button
{
private:
DECLARE_CLASS_SIMPLE( MouseOverButton, vgui::Button );
public:
MouseOverButton(vgui::Panel *parent, const char *panelName, T *templatePanel ) :
Button( parent, panelName, "MouseOverButton")
{
m_pPanel = new T( parent, NULL );
m_pPanel ->SetVisible( false );
// copy size&pos from template panel
int x,y,wide,tall;
templatePanel->GetBounds( x, y, wide, tall );
m_pPanel->SetBounds( x, y, wide, tall );
int px, py;
templatePanel->GetPinOffset( px, py );
int rx, ry;
templatePanel->GetResizeOffset( rx, ry );
// Apply pin settings from template, too
m_pPanel->SetAutoResize( templatePanel->GetPinCorner(), templatePanel->GetAutoResize(), px, py, rx, ry );
m_bPreserveArmedButtons = false;
m_bUpdateDefaultButtons = false;
}
virtual void SetPreserveArmedButtons( bool bPreserve ){ m_bPreserveArmedButtons = bPreserve; }
virtual void SetUpdateDefaultButtons( bool bUpdate ){ m_bUpdateDefaultButtons = bUpdate; }
virtual void ShowPage()
{
if( m_pPanel )
{
m_pPanel->SetVisible( true );
m_pPanel->MoveToFront();
g_lastPanel = m_pPanel;
}
}
virtual void HidePage()
{
if ( m_pPanel )
{
m_pPanel->SetVisible( false );
}
}
const char *GetClassPage( const char *className )
{
static char classPanel[ _MAX_PATH ];
Q_snprintf( classPanel, sizeof( classPanel ), "classes/%s.res", className);
if ( g_pFullFileSystem->FileExists( classPanel, IsX360() ? "MOD" : "GAME" ) )
{
}
else if (g_pFullFileSystem->FileExists( "classes/default.res", IsX360() ? "MOD" : "GAME" ) )
{
Q_snprintf ( classPanel, sizeof( classPanel ), "classes/default.res" );
}
else
{
return NULL;
}
return classPanel;
}
#ifdef REFRESH_CLASSMENU_TOOL
void RefreshClassPage( void )
{
m_pPanel->LoadControlSettings( GetClassPage( GetName() ) );
}
#endif
virtual void ApplySettings( KeyValues *resourceData )
{
BaseClass::ApplySettings( resourceData );
// name, position etc of button is set, now load matching
// resource file for associated info panel:
m_pPanel->LoadControlSettings( GetClassPage( GetName() ) );
}
T *GetClassPanel( void ) { return m_pPanel; }
virtual void OnCursorExited()
{
if ( !m_bPreserveArmedButtons )
{
BaseClass::OnCursorExited();
}
}
virtual void OnCursorEntered()
{
BaseClass::OnCursorEntered();
if ( !IsEnabled() )
return;
// are we updating the default buttons?
if ( m_bUpdateDefaultButtons )
{
SetAsDefaultButton( 1 );
}
// are we preserving the armed state (and need to turn off the old button)?
if ( m_bPreserveArmedButtons )
{
if ( g_lastButton && g_lastButton != this )
{
g_lastButton->SetArmed( false );
}
g_lastButton = this;
}
// turn on our panel (if it isn't already)
if ( m_pPanel && ( !m_pPanel->IsVisible() ) )
{
// turn off the previous panel
if ( g_lastPanel && g_lastPanel->IsVisible() )
{
g_lastPanel->SetVisible( false );
}
ShowPage();
}
}
virtual void OnKeyCodeReleased( vgui::KeyCode code )
{
BaseClass::OnKeyCodeReleased( code );
if ( m_bPreserveArmedButtons )
{
if ( g_lastButton )
{
g_lastButton->SetArmed( true );
}
}
}
private:
T *m_pPanel;
bool m_bPreserveArmedButtons;
bool m_bUpdateDefaultButtons;
};
#define MouseOverPanelButton MouseOverButton<vgui::EditablePanel>
#endif // MOUSEOVERPANELBUTTON_H

View File

@@ -0,0 +1,154 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
// $NoKeywords: $
//=============================================================================//
#ifndef SPECTATORGUI_H
#define SPECTATORGUI_H
#ifdef _WIN32
#pragma once
#endif
#include <vgui/IScheme.h>
#include <vgui/KeyCode.h>
#include <vgui_controls/Frame.h>
#include <vgui_controls/EditablePanel.h>
#include <vgui_controls/Button.h>
#include <vgui_controls/ComboBox.h>
#include <igameevents.h>
#include "GameEventListener.h"
#include <game/client/iviewport.h>
class KeyValues;
namespace vgui
{
class TextEntry;
class Button;
class Panel;
class ImagePanel;
class ComboBox;
}
#define BLACK_BAR_COLOR Color(0, 0, 0, 196)
class IBaseFileSystem;
//-----------------------------------------------------------------------------
// Purpose: Spectator UI
//-----------------------------------------------------------------------------
class CSpectatorGUI : public vgui::EditablePanel, public IViewPortPanel
{
DECLARE_CLASS_SIMPLE( CSpectatorGUI, vgui::EditablePanel );
public:
CSpectatorGUI( IViewPort *pViewPort );
virtual ~CSpectatorGUI();
virtual const char *GetName( void ) { return PANEL_SPECGUI; }
virtual void SetData(KeyValues *data) {};
virtual void Reset() {};
virtual void Update();
virtual bool NeedsUpdate( void ) { return false; }
virtual bool HasInputElements( void ) { return false; }
virtual void ShowPanel( bool bShow );
// both vgui::Frame and IViewPortPanel define these, so explicitly define them here as passthroughs to vgui
vgui::VPANEL GetVPanel( void ) { return BaseClass::GetVPanel(); }
virtual bool IsVisible() { return BaseClass::IsVisible(); }
virtual void SetParent(vgui::VPANEL parent) { BaseClass::SetParent(parent); }
virtual void OnThink();
virtual int GetTopBarHeight() { return m_pTopBar->GetTall(); }
virtual int GetBottomBarHeight() { return m_pBottomBarBlank->GetTall(); }
virtual bool ShouldShowPlayerLabel( int specmode );
virtual Color GetBlackBarColor( void ) { return BLACK_BAR_COLOR; }
virtual const char *GetResFile( void ) { return "Resource/UI/Spectator.res"; }
protected:
void SetLabelText(const char *textEntryName, const char *text);
void SetLabelText(const char *textEntryName, wchar_t *text);
void MoveLabelToFront(const char *textEntryName);
void UpdateTimer();
void SetLogoImage(const char *image);
protected:
enum { INSET_OFFSET = 2 } ;
// vgui overrides
virtual void PerformLayout();
virtual void ApplySchemeSettings(vgui::IScheme *pScheme);
// virtual void OnCommand( const char *command );
vgui::Panel *m_pTopBar;
vgui::Panel *m_pBottomBarBlank;
vgui::ImagePanel *m_pBannerImage;
vgui::Label *m_pPlayerLabel;
IViewPort *m_pViewPort;
// bool m_bHelpShown;
// bool m_bInsetVisible;
bool m_bSpecScoreboard;
};
//-----------------------------------------------------------------------------
// Purpose: the bottom bar panel, this is a separate panel because it
// wants mouse input and the main window doesn't
//----------------------------------------------------------------------------
class CSpectatorMenu : public vgui::Frame, public IViewPortPanel, public CGameEventListener
{
DECLARE_CLASS_SIMPLE( CSpectatorMenu, vgui::Frame );
public:
CSpectatorMenu( IViewPort *pViewPort );
~CSpectatorMenu() {}
virtual const char *GetName( void ) { return PANEL_SPECMENU; }
virtual void SetData(KeyValues *data) {};
virtual void Reset( void ) { m_pPlayerList->DeleteAllItems(); }
virtual void Update( void );
virtual bool NeedsUpdate( void ) { return false; }
virtual bool HasInputElements( void ) { return true; }
virtual void ShowPanel( bool bShow );
virtual void FireGameEvent( IGameEvent *event );
// both vgui::Frame and IViewPortPanel define these, so explicitly define them here as passthroughs to vgui
virtual bool IsVisible() { return BaseClass::IsVisible(); }
vgui::VPANEL GetVPanel( void ) { return BaseClass::GetVPanel(); }
virtual void SetParent(vgui::VPANEL parent) { BaseClass::SetParent(parent); }
private:
// VGUI2 overrides
MESSAGE_FUNC_PARAMS( OnTextChanged, "TextChanged", data );
virtual void OnCommand( const char *command );
virtual void OnKeyCodePressed(vgui::KeyCode code);
virtual void ApplySchemeSettings(vgui::IScheme *pScheme);
virtual void PerformLayout();
void SetViewModeText( const char *text ) { m_pViewOptions->SetText( text ); }
void SetPlayerFgColor( Color c1 ) { m_pPlayerList->SetFgColor(c1); }
vgui::ComboBox *m_pPlayerList;
vgui::ComboBox *m_pViewOptions;
vgui::ComboBox *m_pConfigSettings;
vgui::Button *m_pLeftButton;
vgui::Button *m_pRightButton;
IViewPort *m_pViewPort;
ButtonCode_t m_iDuckKey;
};
extern CSpectatorGUI * g_pSpectatorGUI;
#endif // SPECTATORGUI_H

View File

@@ -0,0 +1,444 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
// $NoKeywords: $
//=============================================================================//
#include "cbase.h"
#include <cdll_client_int.h>
#include "teammenu.h"
#include <vgui/IScheme.h>
#include <vgui/ILocalize.h>
#include <vgui/ISurface.h>
#include <KeyValues.h>
#include <vgui_controls/ImageList.h>
#include <filesystem.h>
#include <vgui_controls/RichText.h>
#include <vgui_controls/Label.h>
#include <vgui_controls/Button.h>
#include <vgui_controls/HTML.h>
#include "IGameUIFuncs.h" // for key bindings
#include <igameresources.h>
#include <game/client/iviewport.h>
#include <stdlib.h> // MAX_PATH define
#include <stdio.h>
#include "byteswap.h"
// memdbgon must be the last include file in a .cpp file!!!
#include "tier0/memdbgon.h"
extern IGameUIFuncs *gameuifuncs; // for key binding details
using namespace vgui;
void UpdateCursorState();
// void DuckMessage(const char *str);
// helper function
const char *GetStringTeamColor( int i )
{
switch( i )
{
case 0:
return "team0";
case 1:
return "team1";
case 2:
return "team2";
case 3:
return "team3";
case 4:
default:
return "team4";
}
}
//-----------------------------------------------------------------------------
// Purpose: Constructor
//-----------------------------------------------------------------------------
CTeamMenu::CTeamMenu(IViewPort *pViewPort) : Frame(NULL, PANEL_TEAM )
{
m_pViewPort = pViewPort;
m_iJumpKey = BUTTON_CODE_INVALID; // this is looked up in Activate()
m_iScoreBoardKey = BUTTON_CODE_INVALID; // this is looked up in Activate()
// initialize dialog
SetTitle("", true);
// load the new scheme early!!
SetScheme("ClientScheme");
SetMoveable(false);
SetSizeable(false);
// hide the system buttons
SetTitleBarVisible( false );
SetProportional(true);
// info window about this map
m_pMapInfo = new RichText( this, "MapInfo" );
#if defined( ENABLE_HTML_WINDOW )
m_pMapInfoHTML = new HTML( this, "MapInfoHTML");
#endif
LoadControlSettings("Resource/UI/TeamMenu.res");
InvalidateLayout();
m_szMapName[0] = 0;
}
//-----------------------------------------------------------------------------
// Purpose: Destructor
//-----------------------------------------------------------------------------
CTeamMenu::~CTeamMenu()
{
}
//-----------------------------------------------------------------------------
// Purpose: sets the text color of the map description field
//-----------------------------------------------------------------------------
void CTeamMenu::ApplySchemeSettings(IScheme *pScheme)
{
BaseClass::ApplySchemeSettings(pScheme);
m_pMapInfo->SetFgColor( pScheme->GetColor("MapDescriptionText", Color(255, 255, 255, 0)) );
if ( *m_szMapName )
{
LoadMapPage( m_szMapName ); // reload the map description to pick up the color
}
}
//-----------------------------------------------------------------------------
// Purpose: makes the user choose the auto assign option
//-----------------------------------------------------------------------------
void CTeamMenu::AutoAssign()
{
engine->ClientCmd("jointeam 0");
OnClose();
}
//-----------------------------------------------------------------------------
// Purpose: shows the team menu
//-----------------------------------------------------------------------------
void CTeamMenu::ShowPanel(bool bShow)
{
if ( BaseClass::IsVisible() == bShow )
return;
if ( bShow )
{
Activate();
SetMouseInputEnabled( true );
// get key bindings if shown
if( m_iJumpKey == BUTTON_CODE_INVALID ) // you need to lookup the jump key AFTER the engine has loaded
{
m_iJumpKey = gameuifuncs->GetButtonCodeForBind( "jump" );
}
if ( m_iScoreBoardKey == BUTTON_CODE_INVALID )
{
m_iScoreBoardKey = gameuifuncs->GetButtonCodeForBind( "showscores" );
}
}
else
{
SetVisible( false );
SetMouseInputEnabled( false );
}
m_pViewPort->ShowBackGround( bShow );
}
//-----------------------------------------------------------------------------
// Purpose: updates the UI with a new map name and map html page, and sets up the team buttons
//-----------------------------------------------------------------------------
void CTeamMenu::Update()
{
char mapname[MAX_MAP_NAME];
Q_FileBase( engine->GetLevelName(), mapname, sizeof(mapname) );
SetLabelText( "mapname", mapname );
LoadMapPage( mapname );
}
//-----------------------------------------------------------------------------
// Purpose: chooses and loads the text page to display that describes mapName map
//-----------------------------------------------------------------------------
void CTeamMenu::LoadMapPage( const char *mapName )
{
// Save off the map name so we can re-load the page in ApplySchemeSettings().
Q_strncpy( m_szMapName, mapName, strlen( mapName ) + 1 );
char mapRES[ MAX_PATH ];
char uilanguage[ 64 ];
engine->GetUILanguage( uilanguage, sizeof( uilanguage ) );
Q_snprintf( mapRES, sizeof( mapRES ), "resource/maphtml/%s_%s.html", mapName, uilanguage );
bool bFoundHTML = false;
if ( !g_pFullFileSystem->FileExists( mapRES ) )
{
// try english
Q_snprintf( mapRES, sizeof( mapRES ), "resource/maphtml/%s_english.html", mapName );
}
else
{
bFoundHTML = true;
}
if( bFoundHTML || g_pFullFileSystem->FileExists( mapRES ) )
{
// it's a local HTML file
char localURL[ _MAX_PATH + 7 ];
Q_strncpy( localURL, "file://", sizeof( localURL ) );
char pPathData[ _MAX_PATH ];
g_pFullFileSystem->GetLocalPath( mapRES, pPathData, sizeof(pPathData) );
Q_strncat( localURL, pPathData, sizeof( localURL ), COPY_ALL_CHARACTERS );
// force steam to dump a local copy
g_pFullFileSystem->GetLocalCopy( pPathData );
m_pMapInfo->SetVisible( false );
#if defined( ENABLE_HTML_WINDOW )
m_pMapInfoHTML->SetVisible( true );
m_pMapInfoHTML->OpenURL( localURL, NULL );
#endif
InvalidateLayout();
Repaint();
return;
}
else
{
m_pMapInfo->SetVisible( true );
#if defined( ENABLE_HTML_WINDOW )
m_pMapInfoHTML->SetVisible( false );
#endif
}
Q_snprintf( mapRES, sizeof( mapRES ), "maps/%s.txt", mapName);
// if no map specific description exists, load default text
if( !g_pFullFileSystem->FileExists( mapRES ) )
{
if ( g_pFullFileSystem->FileExists( "maps/default.txt" ) )
{
Q_snprintf ( mapRES, sizeof( mapRES ), "maps/default.txt");
}
else
{
m_pMapInfo->SetText( "" );
return;
}
}
FileHandle_t f = g_pFullFileSystem->Open( mapRES, "r" );
// read into a memory block
int fileSize = g_pFullFileSystem->Size(f);
int dataSize = fileSize + sizeof( wchar_t );
if ( dataSize % 2 )
++dataSize;
wchar_t *memBlock = (wchar_t *)malloc(dataSize);
memset( memBlock, 0x0, dataSize);
int bytesRead = g_pFullFileSystem->Read(memBlock, fileSize, f);
if ( bytesRead < fileSize )
{
// NULL-terminate based on the length read in, since Read() can transform \r\n to \n and
// return fewer bytes than we were expecting.
char *data = reinterpret_cast<char *>( memBlock );
data[ bytesRead ] = 0;
data[ bytesRead+1 ] = 0;
}
#ifndef WIN32
if ( ((ucs2 *)memBlock)[0] == 0xFEFF )
{
// convert the win32 ucs2 data to wchar_t
dataSize*=2;// need to *2 to account for ucs2 to wchar_t (4byte) growth
wchar_t *memBlockConverted = (wchar_t *)malloc(dataSize);
V_UCS2ToUnicode( (ucs2 *)memBlock, memBlockConverted, dataSize );
free(memBlock);
memBlock = memBlockConverted;
}
#else
// null-terminate the stream (redundant, since we memset & then trimmed the transformed buffer already)
memBlock[dataSize / sizeof(wchar_t) - 1] = 0x0000;
#endif
// ensure little-endian unicode reads correctly on all platforms
CByteswap byteSwap;
byteSwap.SetTargetBigEndian( false );
byteSwap.SwapBufferToTargetEndian( memBlock, memBlock, dataSize/sizeof(wchar_t) );
// check the first character, make sure this a little-endian unicode file
if ( memBlock[0] != 0xFEFF )
{
// its a ascii char file
m_pMapInfo->SetText( reinterpret_cast<char *>( memBlock ) );
}
else
{
m_pMapInfo->SetText( memBlock+1 );
}
// go back to the top of the text buffer
m_pMapInfo->GotoTextStart();
g_pFullFileSystem->Close( f );
free(memBlock);
InvalidateLayout();
Repaint();
}
/*
//-----------------------------------------------------------------------------
// Purpose: sets the text on and displays the team buttons
//-----------------------------------------------------------------------------
void CTeamMenu::MakeTeamButtons(void)
{
int i = 0;
for( i = 0; i< m_pTeamButtons.Count(); i++ )
{
m_pTeamButtons[i]->SetVisible(false);
}
i = 0;
while( true )
{
const char *teamname = GameResources()->GetTeamName( i );
if ( !teamname || !teamname[0] )
return; // no more teams
char buttonText[32];
Q_snprintf( buttonText, sizeof(buttonText), "&%i %s", i +1, teamname );
m_pTeamButtons[i]->SetText( buttonText );
m_pTeamButtons[i]->SetCommand( new KeyValues("TeamButton", "team", i ) );
IScheme *pScheme = scheme()->GetIScheme( GetScheme() );
m_pTeamButtons[i]->SetArmedColor(pScheme->GetColor(GetStringTeamColor(i), Color(255, 255, 255, 255)) , pScheme->GetColor("SelectionBG", Color(255, 255, 255, 0)) );
m_pTeamButtons[i]->SetDepressedColor( pScheme->GetColor(GetStringTeamColor(i), Color(255, 255, 255, 255)), pScheme->GetColor("ButtonArmedBgColor", Color(255, 255, 255, 0)) );
m_pTeamButtons[i]->SetDefaultColor( pScheme->GetColor(GetStringTeamColor(i), Color(255, 255, 255, 255)), pScheme->GetColor("ButtonDepressedBgColor", Color(255, 255, 255, 0)) );
m_pTeamButtons[i]->SetVisible(true);
i++;
}
}
//-----------------------------------------------------------------------------
// Purpose: When a team button is pressed it triggers this function to cause the player to join a team
//-----------------------------------------------------------------------------
void CTeamMenu::OnTeamButton( int team )
{
char cmd[64];
if( team >= m_iNumTeams ) // its a special button
{
if( team == m_iNumTeams ) // first extra team is auto assign
{
Q_snprintf( cmd, sizeof( cmd ), "jointeam 5" );
}
else // next is spectate
{
// DuckMessage( "#Spec_Duck" );
gViewPortInterface->ShowBackGround( false );
}
}
else
{
Q_snprintf( cmd, sizeof( cmd ), "jointeam %i", team + 1 );
//g_iTeamNumber = team + 1;
}
engine->ClientCmd(cmd);
SetVisible( false );
OnClose();
} */
//-----------------------------------------------------------------------------
// Purpose: Sets the text of a control by name
//-----------------------------------------------------------------------------
void CTeamMenu::SetLabelText(const char *textEntryName, const char *text)
{
Label *entry = dynamic_cast<Label *>(FindChildByName(textEntryName));
if (entry)
{
entry->SetText(text);
}
}
void CTeamMenu::OnKeyCodePressed(KeyCode code)
{
int nDir = 0;
switch ( code )
{
case KEY_XBUTTON_UP:
case KEY_XSTICK1_UP:
case KEY_XSTICK2_UP:
case KEY_UP:
case KEY_XBUTTON_LEFT:
case KEY_XSTICK1_LEFT:
case KEY_XSTICK2_LEFT:
case KEY_LEFT:
nDir = -1;
break;
case KEY_XBUTTON_DOWN:
case KEY_XSTICK1_DOWN:
case KEY_XSTICK2_DOWN:
case KEY_DOWN:
case KEY_XBUTTON_RIGHT:
case KEY_XSTICK1_RIGHT:
case KEY_XSTICK2_RIGHT:
case KEY_RIGHT:
nDir = 1;
break;
}
if ( m_iScoreBoardKey != BUTTON_CODE_INVALID && m_iScoreBoardKey == code )
{
gViewPortInterface->ShowPanel( PANEL_SCOREBOARD, true );
gViewPortInterface->PostMessageToPanel( PANEL_SCOREBOARD, new KeyValues( "PollHideCode", "code", code ) );
}
else if ( nDir != 0 )
{
CUtlSortVector< SortedPanel_t, CSortedPanelYLess > vecSortedButtons;
VguiPanelGetSortedChildButtonList( this, (void*)&vecSortedButtons, "&", 0 );
if ( VguiPanelNavigateSortedChildButtonList( (void*)&vecSortedButtons, nDir ) != -1 )
{
// Handled!
return;
}
}
else
{
BaseClass::OnKeyCodePressed( code );
}
}

View File

@@ -0,0 +1,86 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
// $NoKeywords: $
//=============================================================================//
#ifndef TEAMMENU_H
#define TEAMMENU_H
#ifdef _WIN32
#pragma once
#endif
#include <vgui_controls/Frame.h>
#include <vgui_controls/Button.h>
#include <game/client/iviewport.h>
#include <vgui/KeyCode.h>
#include <utlvector.h>
namespace vgui
{
class RichText;
class HTML;
}
class TeamFortressViewport;
//-----------------------------------------------------------------------------
// Purpose: Displays the team menu
//-----------------------------------------------------------------------------
class CTeamMenu : public vgui::Frame, public IViewPortPanel
{
private:
DECLARE_CLASS_SIMPLE( CTeamMenu, vgui::Frame );
public:
CTeamMenu(IViewPort *pViewPort);
virtual ~CTeamMenu();
virtual const char *GetName( void ) { return PANEL_TEAM; }
virtual void SetData(KeyValues *data) {};
virtual void Reset() {};
virtual void Update();
virtual bool NeedsUpdate( void ) { return false; }
virtual bool HasInputElements( void ) { return true; }
virtual void ShowPanel( bool bShow );
// both vgui::Frame and IViewPortPanel define these, so explicitly define them here as passthroughs to vgui
vgui::VPANEL GetVPanel( void ) { return BaseClass::GetVPanel(); }
virtual bool IsVisible() { return BaseClass::IsVisible(); }
virtual void SetParent( vgui::VPANEL parent ) { BaseClass::SetParent( parent ); }
public:
void AutoAssign();
protected:
// int GetNumTeams() { return m_iNumTeams; }
// VGUI2 overrides
virtual void ApplySchemeSettings(vgui::IScheme *pScheme);
virtual void OnKeyCodePressed(vgui::KeyCode code);
// helper functions
virtual void SetLabelText(const char *textEntryName, const char *text);
virtual void LoadMapPage( const char *mapName );
// virtual void MakeTeamButtons( void );
// command callbacks
// MESSAGE_FUNC_INT( OnTeamButton, "TeamButton", team );
IViewPort *m_pViewPort;
vgui::RichText *m_pMapInfo;
vgui::HTML *m_pMapInfoHTML;
// int m_iNumTeams;
ButtonCode_t m_iJumpKey;
ButtonCode_t m_iScoreBoardKey;
char m_szMapName[ MAX_PATH ];
};
#endif // TEAMMENU_H

View File

@@ -0,0 +1,446 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
// $NoKeywords: $
//=============================================================================//
#include "cbase.h"
#include "vguitextwindow.h"
#include <networkstringtabledefs.h>
#include <cdll_client_int.h>
#include <clientmode_shared.h>
#include <vgui/IScheme.h>
#include <vgui/ILocalize.h>
#include <vgui/ISurface.h>
#include <filesystem.h>
#include <KeyValues.h>
#include <convar.h>
#include <vgui_controls/ImageList.h>
#include <vgui_controls/TextEntry.h>
#include <vgui_controls/Button.h>
#include <game/client/iviewport.h>
// memdbgon must be the last include file in a .cpp file!!!
#include "tier0/memdbgon.h"
using namespace vgui;
extern INetworkStringTable *g_pStringTableInfoPanel;
#define TEMP_HTML_FILE "textwindow_temp.html"
ConVar cl_disablehtmlmotd( "cl_disablehtmlmotd", "0", FCVAR_ARCHIVE, "Disable HTML motds." );
//=============================================================================
// HPE_BEGIN:
// [Forrest] Replaced text window command string with TEXTWINDOW_CMD enumeration
// of options. Passing a command string is dangerous and allowed a server network
// message to run arbitrary commands on the client.
//=============================================================================
CON_COMMAND( showinfo, "Shows a info panel: <type> <title> <message> [<command number>]" )
{
if ( !gViewPortInterface )
return;
if ( args.ArgC() < 4 )
return;
IViewPortPanel * panel = gViewPortInterface->FindPanelByName( PANEL_INFO );
if ( panel )
{
KeyValues *kv = new KeyValues("data");
kv->SetInt( "type", Q_atoi(args[ 1 ]) );
kv->SetString( "title", args[ 2 ] );
kv->SetString( "message", args[ 3 ] );
if ( args.ArgC() == 5 )
kv->SetString( "command", args[ 4 ] );
panel->SetData( kv );
gViewPortInterface->ShowPanel( panel, true );
kv->deleteThis();
}
else
{
Msg("Couldn't find info panel.\n" );
}
}
//=============================================================================
// HPE_END
//=============================================================================
//-----------------------------------------------------------------------------
// Purpose: Constructor
//-----------------------------------------------------------------------------
CTextWindow::CTextWindow(IViewPort *pViewPort) : Frame(NULL, PANEL_INFO )
{
// initialize dialog
m_pViewPort = pViewPort;
// SetTitle("", true);
m_szTitle[0] = '\0';
m_szMessage[0] = '\0';
m_szMessageFallback[0] = '\0';
m_nExitCommand = TEXTWINDOW_CMD_NONE;
m_bShownURL = false;
m_bUnloadOnDismissal = false;
// load the new scheme early!!
SetScheme("ClientScheme");
SetMoveable(false);
SetSizeable(false);
SetProportional(true);
// hide the system buttons
SetTitleBarVisible( false );
m_pTextMessage = new TextEntry( this, "TextMessage" );
#if defined( ENABLE_CHROMEHTMLWINDOW )
m_pHTMLMessage = new CMOTDHTML( this,"HTMLMessage" );
#else
m_pHTMLMessage = NULL;
#endif
m_pTitleLabel = new Label( this, "MessageTitle", "Message Title" );
m_pOK = new Button(this, "ok", "#PropertyDialog_OK");
m_pOK->SetCommand("okay");
m_pTextMessage->SetMultiline( true );
m_nContentType = TYPE_TEXT;
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CTextWindow::ApplySchemeSettings( IScheme *pScheme )
{
BaseClass::ApplySchemeSettings( pScheme );
LoadControlSettings("Resource/UI/TextWindow.res");
Reset();
}
//-----------------------------------------------------------------------------
// Purpose: Destructor
//-----------------------------------------------------------------------------
CTextWindow::~CTextWindow()
{
// remove temp file again
g_pFullFileSystem->RemoveFile( TEMP_HTML_FILE, "DEFAULT_WRITE_PATH" );
}
void CTextWindow::Reset( void )
{
//=============================================================================
// HPE_BEGIN:
// [Forrest] Replace strange hard-coded default message with hard-coded error message.
//=============================================================================
Q_strcpy( m_szTitle, "Error loading info message." );
Q_strcpy( m_szMessage, "" );
Q_strcpy( m_szMessageFallback, "" );
//=============================================================================
// HPE_END
//=============================================================================
m_nExitCommand = TEXTWINDOW_CMD_NONE;
m_nContentType = TYPE_TEXT;
m_bShownURL = false;
m_bUnloadOnDismissal = false;
Update();
}
void CTextWindow::ShowText( const char *text )
{
m_pTextMessage->SetVisible( true );
m_pTextMessage->SetText( text );
m_pTextMessage->GotoTextStart();
}
void CTextWindow::ShowURL( const char *URL, bool bAllowUserToDisable )
{
#if defined( ENABLE_CHROMEHTMLWINDOW )
#ifdef _DEBUG
Msg( "CTextWindow::ShowURL( %s )\n", URL );
#endif
ClientModeShared *mode = ( ClientModeShared * )GetClientModeNormal();
if ( ( bAllowUserToDisable && cl_disablehtmlmotd.GetBool() ) || !mode->IsHTMLInfoPanelAllowed() )
{
Warning( "Blocking HTML info panel '%s'; Using plaintext instead.\n", URL );
// User has disabled HTML TextWindows. Show the fallback as text only.
if ( g_pStringTableInfoPanel )
{
int index = g_pStringTableInfoPanel->FindStringIndex( "motd_text" );
if ( index != ::INVALID_STRING_INDEX )
{
int length = 0;
const char *data = (const char *)g_pStringTableInfoPanel->GetStringUserData( index, &length );
if ( data && data[0] )
{
m_pHTMLMessage->SetVisible( false );
ShowText( data );
}
}
}
return;
}
m_pHTMLMessage->SetVisible( true );
m_pHTMLMessage->OpenURL( URL, NULL );
m_bShownURL = true;
#endif
}
void CTextWindow::ShowIndex( const char *entry )
{
const char *data = NULL;
int length = 0;
if ( NULL == g_pStringTableInfoPanel )
return;
int index = g_pStringTableInfoPanel->FindStringIndex( m_szMessage );
if ( index != ::INVALID_STRING_INDEX )
data = (const char *)g_pStringTableInfoPanel->GetStringUserData( index, &length );
if ( !data || !data[0] )
return; // nothing to show
// is this a web URL ?
if ( !Q_strncmp( data, "http://", 7 ) || !Q_strncmp( data, "https://", 8 ) )
{
ShowURL( data );
return;
}
// try to figure out if this is HTML or not
if ( data[0] != '<' )
{
ShowText( data );
return;
}
// data is a HTML, we have to write to a file and then load the file
FileHandle_t hFile = g_pFullFileSystem->Open( TEMP_HTML_FILE, "wb", "DEFAULT_WRITE_PATH" );
if ( hFile == FILESYSTEM_INVALID_HANDLE )
return;
g_pFullFileSystem->Write( data, length, hFile );
g_pFullFileSystem->Close( hFile );
if ( g_pFullFileSystem->Size( TEMP_HTML_FILE ) != (unsigned int)length )
return; // something went wrong while writing
ShowFile( TEMP_HTML_FILE );
}
void CTextWindow::ShowFile( const char *filename )
{
if ( Q_stristr( filename, ".htm" ) || Q_stristr( filename, ".html" ) )
{
// it's a local HTML file
char localURL[ _MAX_PATH + 7 ];
Q_strncpy( localURL, "file://", sizeof( localURL ) );
char pPathData[ _MAX_PATH ];
g_pFullFileSystem->GetLocalPath( filename, pPathData, sizeof(pPathData) );
Q_strncat( localURL, pPathData, sizeof( localURL ), COPY_ALL_CHARACTERS );
ShowURL( localURL );
}
else
{
// read from local text from file
FileHandle_t f = g_pFullFileSystem->Open( m_szMessage, "rb", "GAME" );
if ( !f )
return;
char buffer[2048];
int size = MIN( g_pFullFileSystem->Size( f ), sizeof(buffer)-1 ); // just allow 2KB
g_pFullFileSystem->Read( buffer, size, f );
g_pFullFileSystem->Close( f );
buffer[size]=0; //terminate string
ShowText( buffer );
}
}
void CTextWindow::Update( void )
{
SetTitle( m_szTitle, false );
m_pTitleLabel->SetText( m_szTitle );
#if defined( ENABLE_CHROMEHTMLWINDOW )
m_pHTMLMessage->SetVisible( false );
#endif
m_pTextMessage->SetVisible( false );
if ( m_nContentType == TYPE_INDEX )
{
ShowIndex( m_szMessage );
}
else if ( m_nContentType == TYPE_URL )
{
if ( !Q_strncmp( m_szMessage, "http://", 7 ) || !Q_strncmp( m_szMessage, "https://", 8 ) || !Q_stricmp( m_szMessage, "about:blank" ) )
{
ShowURL( m_szMessage );
}
else
{
// We should have trapped this at a higher level
Assert( !"URL protocol is missing or blocked" );
}
}
else if ( m_nContentType == TYPE_FILE )
{
ShowFile( m_szMessage );
}
else if ( m_nContentType == TYPE_TEXT )
{
ShowText( m_szMessage );
}
else
{
DevMsg("CTextWindow::Update: unknown content type %i\n", m_nContentType );
}
}
void CTextWindow::OnCommand( const char *command )
{
if (!Q_strcmp(command, "okay"))
{
//=============================================================================
// HPE_BEGIN:
// [Forrest] Replaced text window command string with TEXTWINDOW_CMD enumeration
// of options. Passing a command string is dangerous and allowed a server network
// message to run arbitrary commands on the client.
//=============================================================================
const char *pszCommand = NULL;
switch ( m_nExitCommand )
{
case TEXTWINDOW_CMD_NONE:
break;
case TEXTWINDOW_CMD_JOINGAME:
pszCommand = "joingame";
break;
case TEXTWINDOW_CMD_CHANGETEAM:
pszCommand = "changeteam";
break;
case TEXTWINDOW_CMD_IMPULSE101:
pszCommand = "impulse 101";
break;
case TEXTWINDOW_CMD_MAPINFO:
pszCommand = "mapinfo";
break;
case TEXTWINDOW_CMD_CLOSED_HTMLPAGE:
pszCommand = "closed_htmlpage";
break;
case TEXTWINDOW_CMD_CHOOSETEAM:
pszCommand = "chooseteam";
break;
default:
DevMsg("CTextWindow::OnCommand: unknown exit command value %i\n", m_nExitCommand );
break;
}
if ( pszCommand != NULL )
{
engine->ClientCmd_Unrestricted( pszCommand );
}
//=============================================================================
// HPE_END
//=============================================================================
m_pViewPort->ShowPanel( this, false );
}
BaseClass::OnCommand(command);
}
void CTextWindow::OnKeyCodePressed( vgui::KeyCode code )
{
if ( code == KEY_XBUTTON_A || code == KEY_XBUTTON_B )
{
OnCommand( "okay" );
return;
}
BaseClass::OnKeyCodePressed(code);
}
void CTextWindow::SetData(KeyValues *data)
{
SetData( data->GetInt( "type" ), data->GetString( "title" ), data->GetString( "msg" ), data->GetString( "msg_fallback" ), data->GetInt( "cmd" ), data->GetBool( "unload" ) );
}
void CTextWindow::SetData( int type, const char *title, const char *message, const char *message_fallback, int command, bool bUnload )
{
Q_strncpy( m_szTitle, title, sizeof( m_szTitle ) );
Q_strncpy( m_szMessage, message, sizeof( m_szMessage ) );
Q_strncpy( m_szMessageFallback, message_fallback, sizeof( m_szMessageFallback ) );
m_nExitCommand = command;
m_nContentType = type;
m_bUnloadOnDismissal = bUnload;
Update();
}
void CTextWindow::ShowPanel( bool bShow )
{
if ( BaseClass::IsVisible() == bShow )
return;
m_pViewPort->ShowBackGround( bShow );
if ( bShow )
{
Activate();
SetMouseInputEnabled( true );
}
else
{
SetVisible( false );
SetMouseInputEnabled( false );
#if defined( ENABLE_CHROMEHTMLWINDOW )
if ( m_bUnloadOnDismissal && m_bShownURL )
{
m_pHTMLMessage->OpenURL( "about:blank", NULL );
m_bShownURL = false;
}
#endif
}
}
bool CTextWindow::CMOTDHTML::OnStartRequest( const char *url, const char *target, const char *pchPostData, bool bIsRedirect )
{
if ( Q_strstr( url, "steam://" ) )
return false;
return BaseClass::OnStartRequest( url, target, pchPostData, bIsRedirect );
}

View File

@@ -0,0 +1,104 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
// $NoKeywords: $
//=============================================================================//
#ifndef VGUITEXTWINDOW_H
#define VGUITEXTWINDOW_H
#ifdef _WIN32
#pragma once
#endif
#include <vgui_controls/Frame.h>
#include <vgui_controls/Button.h>
#include <vgui_controls/HTML.h>
#include <game/client/iviewport.h>
#include "shareddefs.h"
namespace vgui
{
class TextEntry;
}
//-----------------------------------------------------------------------------
// Purpose: displays the MOTD
//-----------------------------------------------------------------------------
class CTextWindow : public vgui::Frame, public IViewPortPanel
{
private:
DECLARE_CLASS_SIMPLE( CTextWindow, vgui::Frame );
public:
CTextWindow(IViewPort *pViewPort);
virtual ~CTextWindow();
virtual const char *GetName( void ) { return PANEL_INFO; }
virtual void SetData(KeyValues *data);
virtual void Reset();
virtual void Update();
virtual bool NeedsUpdate( void ) { return false; }
virtual bool HasInputElements( void ) { return true; }
virtual void ShowPanel( bool bShow );
// both vgui::Frame and IViewPortPanel define these, so explicitly define them here as passthroughs to vgui
vgui::VPANEL GetVPanel( void ) { return BaseClass::GetVPanel(); }
virtual bool IsVisible() { return BaseClass::IsVisible(); }
virtual void SetParent( vgui::VPANEL parent ) { BaseClass::SetParent( parent ); }
public:
virtual void SetData( int type, const char *title, const char *message, const char *message_fallback, int command, bool bUnload );
virtual void ShowFile( const char *filename );
virtual void ShowText( const char *text );
virtual void ShowURL( const char *URL, bool bAllowUserToDisable = true );
virtual void ShowIndex( const char *entry );
virtual void ApplySchemeSettings( vgui::IScheme *pScheme );
protected:
// vgui overrides
virtual void OnCommand( const char *command );
void OnKeyCodePressed( vgui::KeyCode code );
IViewPort *m_pViewPort;
char m_szTitle[255];
char m_szMessage[2048];
char m_szMessageFallback[2048];
//=============================================================================
// HPE_BEGIN:
// [Forrest] Replaced text window command string with TEXTWINDOW_CMD enumeration
// of options. Passing a command string is dangerous and allowed a server network
// message to run arbitrary commands on the client.
//=============================================================================
int m_nExitCommand;
//=============================================================================
// HPE_END
//=============================================================================
int m_nContentType;
bool m_bShownURL;
bool m_bUnloadOnDismissal;
vgui::TextEntry *m_pTextMessage;
class CMOTDHTML : public vgui::HTML
{
private:
DECLARE_CLASS_SIMPLE( CMOTDHTML, vgui::HTML );
public:
CMOTDHTML( Panel *parent, const char *pchName ) : vgui::HTML( parent, pchName ) {}
virtual bool OnStartRequest( const char *url, const char *target, const char *pchPostData, bool bIsRedirect ) OVERRIDE;
};
CMOTDHTML *m_pHTMLMessage;
vgui::Button *m_pOK;
vgui::Label *m_pTitleLabel;
};
#endif // VGUITEXTWINDOW_H

View File

@@ -0,0 +1,29 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
// $NoKeywords: $
//=============================================================================//
#include "cbase.h"
// memdbgon must be the last include file in a .cpp file!!!
#include "tier0/memdbgon.h"
class C_FuncMonitor : public C_BaseEntity
{
public:
DECLARE_CLASS( C_FuncMonitor, C_BaseEntity );
DECLARE_CLIENTCLASS();
// C_BaseEntity.
public:
virtual bool ShouldDraw();
};
IMPLEMENT_CLIENTCLASS_DT( C_FuncMonitor, DT_FuncMonitor, CFuncMonitor )
END_RECV_TABLE()
bool C_FuncMonitor::ShouldDraw()
{
return true;
}

View File

@@ -0,0 +1,219 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
// $NoKeywords: $
//=============================================================================//
#include "cbase.h"
#include "fx.h"
#include "particlemgr.h"
#include "particle_prototype.h"
#include "particle_util.h"
#include "c_te_particlesystem.h"
#include "particles_ez.h"
// memdbgon must be the last include file in a .cpp file!!!
#include "tier0/memdbgon.h"
#define DUST_STARTSIZE 16
#define DUST_ENDSIZE 48
#define DUST_RADIUS 32.0f
#define DUST_STARTALPHA 0.3f
#define DUST_ENDALPHA 0.0f
#define DUST_LIFETIME 2.0f
static Vector g_AntlionDustColor( 0.3f, 0.25f, 0.2f );
extern IPhysicsSurfaceProps *physprops;
class CAntlionDustEmitter : public CSimpleEmitter
{
public:
static CAntlionDustEmitter *Create( const char *debugname )
{
return new CAntlionDustEmitter( debugname );
}
void UpdateVelocity( SimpleParticle *pParticle, float timeDelta )
{
//FIXME: Incorrect
pParticle->m_vecVelocity *= 0.9f;
}
private:
CAntlionDustEmitter( const char *pDebugName ) : CSimpleEmitter( pDebugName ) {}
CAntlionDustEmitter( const CAntlionDustEmitter & ); // not defined, not accessible
};
//==================================================
// C_TEAntlionDust
//==================================================
class C_TEAntlionDust: public C_TEParticleSystem
{
public:
DECLARE_CLASS( C_TEAntlionDust, C_TEParticleSystem );
DECLARE_CLIENTCLASS();
C_TEAntlionDust();
virtual ~C_TEAntlionDust();
//C_BaseEntity
public:
virtual void PostDataUpdate( DataUpdateType_t updateType );
virtual bool ShouldDraw() { return true; }
//IParticleEffect
public:
virtual void RenderParticles( CParticleRenderIterator *pIterator );
virtual void SimulateParticles( CParticleSimulateIterator *pIterator );
public:
PMaterialHandle m_MaterialHandle;
Vector m_vecOrigin;
QAngle m_vecAngles;
bool m_bBlockedSpawner;
protected:
void GetDustColor( Vector &color );
};
// Expose to the particle app.
EXPOSE_PROTOTYPE_EFFECT( AntlionDust, C_TEAntlionDust );
IMPLEMENT_CLIENTCLASS_EVENT_DT( C_TEAntlionDust, DT_TEAntlionDust, CTEAntlionDust )
RecvPropVector(RECVINFO( m_vecOrigin )),
RecvPropVector(RECVINFO( m_vecAngles )),
RecvPropBool(RECVINFO( m_bBlockedSpawner )),
END_RECV_TABLE()
//==================================================
// C_TEAntlionDust
//==================================================
C_TEAntlionDust::C_TEAntlionDust()
{
m_MaterialHandle = INVALID_MATERIAL_HANDLE;
m_vecOrigin.Init();
m_vecAngles.Init();
m_bBlockedSpawner = false;
}
C_TEAntlionDust::~C_TEAntlionDust()
{
}
//-----------------------------------------------------------------------------
// Purpose:
// Input : bNewEntity - whether or not to start a new entity
//-----------------------------------------------------------------------------
void C_TEAntlionDust::PostDataUpdate( DataUpdateType_t updateType )
{
// This style of creating dust emitters is now deprecated; we use the simple particle singleton exclusively.
/*
CSmartPtr<CAntlionDustEmitter> pDustEmitter = CAntlionDustEmitter::Create( "TEAntlionDust" );
Assert( pDustEmitter );
if ( pDustEmitter == NULL )
return;
pDustEmitter->SetSortOrigin( m_vecOrigin );
pDustEmitter->SetNearClip( 32, 64 );
pDustEmitter->GetBinding().SetBBox( m_vecOrigin - Vector( 32, 32, 32 ), m_vecOrigin + Vector( 32, 32, 32 ) );
*/
Vector offset;
Vector vecColor;
GetDustColor( vecColor );
int iParticleCount = 16;
if ( m_bBlockedSpawner == true )
{
iParticleCount = 8;
}
//Spawn the dust
SimpleParticle particle;
for ( int i = 0; i < iParticleCount; i++ )
{
//Offset this dust puff's origin
offset[0] = random->RandomFloat( -DUST_RADIUS, DUST_RADIUS );
offset[1] = random->RandomFloat( -DUST_RADIUS, DUST_RADIUS );
offset[2] = random->RandomFloat( -16, 8 );
offset += m_vecOrigin;
particle.m_Pos = offset;
particle.m_flDieTime = random->RandomFloat( 0.75f, 1.25f );
particle.m_flLifetime = 0.0f;
Vector dir = particle.m_Pos - m_vecOrigin;
particle.m_vecVelocity = dir * random->RandomFloat( 0.5f, 1.0f );
dir.z = fabs(dir.z);
float colorRamp = random->RandomFloat( 0.5f, 1.0f );
Vector color = vecColor*colorRamp;
color[0] = clamp( color[0], 0.0f, 1.0f );
color[1] = clamp( color[1], 0.0f, 1.0f );
color[2] = clamp( color[2], 0.0f, 1.0f );
color *= 255;
particle.m_uchColor[0] = color[0];
particle.m_uchColor[1] = color[1];
particle.m_uchColor[2] = color[2];
particle.m_uchStartAlpha= random->RandomFloat( 64, 128 );
particle.m_uchEndAlpha = 0;
particle.m_uchStartSize = random->RandomInt( 16, 32 );
particle.m_uchEndSize = particle.m_uchStartSize * 3;
particle.m_flRoll = random->RandomInt( 0, 360 );
particle.m_flRollDelta = random->RandomFloat( -0.2f, 0.2f );
// Though it appears there are two particle handle entries in g_Mat_DustPuff, in fact
// only the one present at index 0 actually draws. Trying to spawn a particle with
// the other material will give you no particle at all. Therefore while instead of this:
// AddSimpleParticle( &particle, g_Mat_DustPuff[random->RandomInt(0,1) );
// we have to do this:
AddSimpleParticle( &particle, g_Mat_DustPuff[0] );
}
}
void GetColorForSurface( trace_t *trace, Vector *color );
//-----------------------------------------------------------------------------
// Purpose:
// Input : &color -
//-----------------------------------------------------------------------------
void C_TEAntlionDust::GetDustColor( Vector &color )
{
trace_t tr;
UTIL_TraceLine( m_vecOrigin+Vector(0,0,1), m_vecOrigin+Vector(0,0,-32),
MASK_SOLID_BRUSHONLY, NULL, COLLISION_GROUP_NONE, &tr );
if ( tr.fraction < 1.0f )
{
GetColorForSurface( &tr, &color );
}
else
{
//Fill in a fallback
color = g_AntlionDustColor;
}
}
void C_TEAntlionDust::RenderParticles( CParticleRenderIterator *pIterator )
{
}
void C_TEAntlionDust::SimulateParticles( CParticleSimulateIterator *pIterator )
{
}

View File

@@ -0,0 +1,475 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
//=============================================================================//
#include "cbase.h"
#include "particlemgr.h"
#include "particle_prototype.h"
#include "particle_util.h"
#include "surfinfo.h"
#include "baseparticleentity.h"
#include "materialsystem/imaterialsystemhardwareconfig.h"
// memdbgon must be the last include file in a .cpp file!!!
#include "tier0/memdbgon.h"
// ------------------------------------------------------------------------- //
// Definitions
// ------------------------------------------------------------------------- //
#define NUM_AR2_EXPLOSION_PARTICLES 70
#define AR2_DUST_RADIUS 240 // 340
#define AR2_DUST_LIFETIME 4
#define AR2_DUST_LIFETIME_DELTA 6
#define AR2_DUST_SPEED 10000
#define AR2_DUST_STARTSIZE 8
#define AR2_DUST_ENDSIZE 32
#define AR2_DUST_ALPHA 0.5f
#define AR2_DUST_FADE_IN_TIME 0.25f
static Vector g_AR2DustColor1(0.35, 0.345, 0.33 );
static Vector g_AR2DustColor2(0.75, 0.75, 0.7);
// ------------------------------------------------------------------------- //
// Classes
// ------------------------------------------------------------------------- //
class C_AR2Explosion : public C_BaseParticleEntity, public IPrototypeAppEffect
{
public:
DECLARE_CLASS( C_AR2Explosion, C_BaseParticleEntity );
DECLARE_CLIENTCLASS();
C_AR2Explosion();
~C_AR2Explosion();
private:
class AR2ExplosionParticle : public StandardParticle_t
{
public:
float m_Dist;
Vector m_Start;
float m_Roll;
float m_RollSpeed;
float m_Dwell;
};
// C_BaseEntity.
public:
virtual void OnDataChanged(DataUpdateType_t updateType);
// IPrototypeAppEffect.
public:
virtual void Start(CParticleMgr *pParticleMgr, IPrototypeArgAccess *pArgs);
// IParticleEffect.
public:
virtual void Update(float fTimeDelta);
virtual void RenderParticles( CParticleRenderIterator *pIterator );
virtual void SimulateParticles( CParticleSimulateIterator *pIterator );
public:
CParticleMgr *m_pParticleMgr;
PMaterialHandle m_MaterialHandle;
private:
char m_szMaterialName[255];
C_AR2Explosion( const C_AR2Explosion & );
};
// Expose to the particle app.
EXPOSE_PROTOTYPE_EFFECT(AR2Explosion, C_AR2Explosion);
IMPLEMENT_CLIENTCLASS_DT(C_AR2Explosion, DT_AR2Explosion, AR2Explosion)
RecvPropString( RECVINFO( m_szMaterialName ) ),
END_RECV_TABLE()
// ------------------------------------------------------------------------- //
// Helpers.
// ------------------------------------------------------------------------- //
// Given a line segment from vStart to vEnd
// and a list of convex polygons in pSurfInfos and nSurfInfos,
// fill in the list of which polygons the segment intersects.
// Returns the number of intersected surfaces.
static int IntersectSegmentWithSurfInfos(
const Vector &vStart,
const Vector &vEnd,
SurfInfo *pSurfInfos,
const int nSurfInfos,
SurfInfo ** pIntersections,
Vector *pIntersectionPositions,
int nMaxIntersections)
{
if(nMaxIntersections == 0)
return 0;
int nIntersections = 0;
for(int i=0; i < nSurfInfos; i++)
{
SurfInfo *pSurf = &pSurfInfos[i];
// Does it intersect the plane?
float dot1 = pSurf->m_Plane.DistTo(vStart);
float dot2 = pSurf->m_Plane.DistTo(vEnd);
if((dot1 > 0) != (dot2 > 0))
{
float t = dot1 / (dot1 - dot2);
Vector vIntersection = vStart + (vEnd - vStart) * t;
// If the intersection is behind any edge plane, then it's not inside the polygon.
unsigned long iEdge;
for(iEdge=0; iEdge < pSurf->m_nVerts; iEdge++)
{
VPlane edgePlane;
edgePlane.m_Normal = pSurf->m_Plane.m_Normal.Cross(pSurf->m_Verts[iEdge] - pSurf->m_Verts[(iEdge+1)%pSurf->m_nVerts]);
VectorNormalize( edgePlane.m_Normal );
edgePlane.m_Dist = edgePlane.m_Normal.Dot(pSurf->m_Verts[iEdge]);
if(edgePlane.DistTo(vIntersection) < 0.0f)
break;
}
if(iEdge == pSurf->m_nVerts)
{
pIntersections[nIntersections] = pSurf;
pIntersectionPositions[nIntersections] = vIntersection;
++nIntersections;
if(nIntersections >= nMaxIntersections)
break;
}
}
}
return nIntersections;
}
// ------------------------------------------------------------------------- //
// C_AR2Explosion
// ------------------------------------------------------------------------- //
C_AR2Explosion::C_AR2Explosion()
{
m_pParticleMgr = NULL;
m_MaterialHandle = INVALID_MATERIAL_HANDLE;
}
C_AR2Explosion::~C_AR2Explosion()
{
}
void C_AR2Explosion::OnDataChanged(DataUpdateType_t updateType)
{
C_BaseEntity::OnDataChanged(updateType);
if(updateType == DATA_UPDATE_CREATED)
{
Start(ParticleMgr(), NULL);
}
}
static ConVar mat_reduceparticles( "mat_reduceparticles", "0" );
void C_AR2Explosion::Start(CParticleMgr *pParticleMgr, IPrototypeArgAccess *pArgs)
{
m_pParticleMgr = pParticleMgr;
if(!pParticleMgr->AddEffect(&m_ParticleEffect, this))
return;
if (!m_szMaterialName[0])
{
Q_strncpy(m_szMaterialName, "particle/particle_noisesphere", sizeof( m_szMaterialName ) );
}
m_MaterialHandle = m_ParticleEffect.FindOrAddMaterial(m_szMaterialName);
// Precalculate stuff for the particle spawning..
#define NUM_DUSTEMITTER_SURFINFOS 128
SurfInfo surfInfos[NUM_DUSTEMITTER_SURFINFOS];
int nSurfInfos;
// Center of explosion.
Vector vCenter = GetAbsOrigin(); // HACKHACK.. when the engine bug is fixed, use origin.
if ( IsXbox() )
{
m_ParticleEffect.SetBBox( vCenter-Vector(300,300,300), vCenter+Vector(300,300,300) );
}
#ifdef PARTICLEPROTOTYPE_APP
float surfSize = 10000;
nSurfInfos = 1;
surfInfos[0].m_Verts[0].Init(-surfSize,-surfSize,0);
surfInfos[0].m_Verts[1].Init(-surfSize,surfSize,0);
surfInfos[0].m_Verts[2].Init(surfSize, surfSize,0);
surfInfos[0].m_Verts[3].Init(surfSize,-surfSize,0);
surfInfos[0].m_nVerts = 4;
surfInfos[0].m_Plane.m_Normal.Init(0,0,1);
surfInfos[0].m_Plane.m_Dist = -3;
#else
{
nSurfInfos = 0;
C_BaseEntity *ent = cl_entitylist->GetEnt( 0 );
if ( ent )
{
nSurfInfos = engine->GetIntersectingSurfaces(
ent->GetModel(),
vCenter,
AR2_DUST_RADIUS,
true,
surfInfos,
NUM_DUSTEMITTER_SURFINFOS);
}
}
#endif
int nParticles = 0;
int iParticlesToSpawn = NUM_AR2_EXPLOSION_PARTICLES;
// In DX7, much fewer particles
if ( g_pMaterialSystemHardwareConfig->GetDXSupportLevel() < 80 )
{
iParticlesToSpawn *= 0.25;
}
else if ( mat_reduceparticles.GetBool() )
{
iParticlesToSpawn *= 0.025;
}
if( nSurfInfos > 0 )
{
// For nParticles*N, generate a ray and cast it out. If it hits anything, spawn a particle there.
int nTestsPerParticle=3;
for(int i=0; i < iParticlesToSpawn; i++)
{
for(int iTest=0; iTest < nTestsPerParticle; iTest++)
{
Vector randVec = RandomVector(-1,1);
VectorNormalize( randVec );
Vector startPos = vCenter + randVec * AR2_DUST_RADIUS;
randVec = RandomVector(-1,1);
VectorNormalize( randVec );
Vector endPos = vCenter + randVec * AR2_DUST_RADIUS;
#define MAX_SURFINFO_INTERSECTIONS 4
SurfInfo *pIntersected[MAX_SURFINFO_INTERSECTIONS];
Vector vIntersections[MAX_SURFINFO_INTERSECTIONS];
int nIntersections;
nIntersections = IntersectSegmentWithSurfInfos(
startPos,
endPos,
surfInfos,
nSurfInfos,
pIntersected,
vIntersections,
MAX_SURFINFO_INTERSECTIONS);
if(nIntersections)
{
int iIntersection = rand() % nIntersections;
Vector velocity;
//velocity.Init(-1.0f + ((float)rand()/VALVE_RAND_MAX) * 2.0f, -1.0f + ((float)rand()/VALVE_RAND_MAX) * 2.0f, -1.0f + ((float)rand()/VALVE_RAND_MAX) * 2.0f);
//velocity = velocity * FRand(m_MinSpeed, m_MaxSpeed);
Vector direction = (vIntersections[iIntersection] - vCenter );
float dist = VectorNormalize( direction );
if(dist > AR2_DUST_RADIUS)
dist = AR2_DUST_RADIUS;
static float power = 2.0f;
float falloffMul = pow(1.0f - dist / AR2_DUST_RADIUS, power);
Vector reflection = direction - 2 * DotProduct( direction, pIntersected[iIntersection]->m_Plane.m_Normal ) * pIntersected[iIntersection]->m_Plane.m_Normal;
VectorNormalize( reflection );
velocity = reflection * AR2_DUST_SPEED * falloffMul;
// velocity = velocity + (vIntersections[iIntersection] - vCenter) * falloffMul;
/*
debugoverlay->AddLineOverlay( vIntersections[iIntersection],
vIntersections[iIntersection] + reflection * 64,
128, 128, 255, false, 15.0 );
*/
#if 1
AR2ExplosionParticle *pParticle =
(AR2ExplosionParticle*)m_ParticleEffect.AddParticle( sizeof(AR2ExplosionParticle), m_MaterialHandle );
if(pParticle)
{
pParticle->m_Pos = vIntersections[iIntersection];
pParticle->m_Start = pParticle->m_Pos;
pParticle->m_Dist = 8.0;
pParticle->m_Velocity = velocity;
// sound == 13031.496062992125984251968503937ips
pParticle->m_Lifetime = -dist / 13031.5f - 0.1;
pParticle->m_Roll = FRand( 0, M_PI * 2 );
pParticle->m_RollSpeed = FRand( -1, 1 ) * 0.4;
pParticle->m_Dwell = AR2_DUST_LIFETIME + random->RandomFloat( 0, AR2_DUST_LIFETIME_DELTA );
nParticles++;
break;
}
#endif
}
}
}
}
// build interior smoke particles
for(int i=nParticles; i < iParticlesToSpawn; i++)
{
Vector randVec = RandomVector(-1,1);
VectorNormalize( randVec );
Vector endPos = vCenter + randVec * AR2_DUST_RADIUS / 4.0;
Vector direction = (endPos - vCenter );
float dist = VectorNormalize( direction ) + random->RandomFloat( 0, AR2_DUST_RADIUS / 4.0 );
if(dist > AR2_DUST_RADIUS)
dist = AR2_DUST_RADIUS;
static float power = 2.0f;
float falloffMul = pow(1.0f - dist / (AR2_DUST_RADIUS / 2), power);
Vector velocity = direction * AR2_DUST_SPEED * falloffMul;
AR2ExplosionParticle *pParticle =
(AR2ExplosionParticle*)m_ParticleEffect.AddParticle( sizeof(AR2ExplosionParticle), m_MaterialHandle );
if(pParticle)
{
pParticle->m_Pos = endPos;
pParticle->m_Start = pParticle->m_Pos;
pParticle->m_Dist = 8.0;
pParticle->m_Velocity = velocity;
// sound == 13031.496062992125984251968503937ips
pParticle->m_Lifetime = -dist / 13031.5f - 0.1;
pParticle->m_Roll = FRand( 0, M_PI * 2 );
pParticle->m_RollSpeed = FRand( -1, 1 ) * 4.0;
pParticle->m_Dwell = 0.5 * (AR2_DUST_LIFETIME + random->RandomFloat( 0, AR2_DUST_LIFETIME_DELTA ));
}
}
}
void C_AR2Explosion::Update(float fTimeDelta)
{
if(!m_pParticleMgr)
return;
}
void C_AR2Explosion::SimulateParticles( CParticleSimulateIterator *pIterator )
{
float dt = pIterator->GetTimeDelta();
AR2ExplosionParticle *pParticle = (AR2ExplosionParticle*)pIterator->GetFirst();
while ( pParticle )
{
if (dt > 0.05)
dt = 0.05; // yuck, air resistance function craps out at less then 20fps
// Update its lifetime.
pParticle->m_Lifetime += dt; // pDraw->GetTimeDelta();
if(pParticle->m_Lifetime > pParticle->m_Dwell)
{
// faded to nothing....
pIterator->RemoveParticle( pParticle );
}
else
{
// Spin the thing
pParticle->m_Roll += pParticle->m_RollSpeed * pIterator->GetTimeDelta();
// delayed?
if ( pParticle->m_Lifetime >= 0.0f )
{
// Move it (this comes after rendering to make it clear that moving the particle here won't change
// its rendering for this frame since m_TransformedPos has already been set).
pParticle->m_Pos = pParticle->m_Pos + pParticle->m_Velocity * dt;
// keep track of distance traveled
pParticle->m_Dist = pParticle->m_Dist + pParticle->m_Velocity.Length() * dt;
// Dampen velocity.
float dist = pParticle->m_Velocity.Length() * dt;
float r = dist * dist;
// FIXME: this is a really screwy air-resistance function....
pParticle->m_Velocity = pParticle->m_Velocity * (100 / (100 + r ));
// dampen roll
static float dtime;
static float decay;
if (dtime != dt)
{
dtime = dt;
decay = ExponentialDecay( 0.3, 1.0, dtime );
}
if (fabs(pParticle->m_RollSpeed) > 0.2)
pParticle->m_RollSpeed = pParticle->m_RollSpeed * decay;
}
}
pParticle = (AR2ExplosionParticle*)pIterator->GetNext();
}
}
void C_AR2Explosion::RenderParticles( CParticleRenderIterator *pIterator )
{
const AR2ExplosionParticle *pParticle = (const AR2ExplosionParticle *)pIterator->GetFirst();
while ( pParticle )
{
float sortKey = 0;
if ( pParticle->m_Lifetime >= 0.0f )
{
// Draw.
float lifetimePercent = ( pParticle->m_Lifetime - AR2_DUST_FADE_IN_TIME ) / pParticle->m_Dwell;
// FIXME: base color should be a dirty version of the material color
Vector color = g_AR2DustColor1 * (1.0 - lifetimePercent) + g_AR2DustColor2 * lifetimePercent;
Vector tPos;
TransformParticle(m_pParticleMgr->GetModelView(), pParticle->m_Pos, tPos);
sortKey = tPos.z;
float alpha;
if ( pParticle->m_Lifetime < AR2_DUST_FADE_IN_TIME )
{
alpha = AR2_DUST_ALPHA * ( pParticle->m_Lifetime / AR2_DUST_FADE_IN_TIME );
}
else
{
alpha = AR2_DUST_ALPHA * ( 1.0f - lifetimePercent );
}
alpha *= GetAlphaDistanceFade( tPos, IsXbox() ? 100 : 50, IsXbox() ? 200 : 150 );
RenderParticle_ColorSizeAngle(
pIterator->GetParticleDraw(),
tPos,
color,
alpha,
pParticle->m_Dist, // size based on how far it's traveled
pParticle->m_Roll);
}
pParticle = (const AR2ExplosionParticle *)pIterator->GetNext( sortKey );
}
}

View File

@@ -0,0 +1,313 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
// $NoKeywords: $
//=============================================================================//
#include "cbase.h"
#include "c_ai_basenpc.h"
#include "engine/ivmodelinfo.h"
#include "rope_physics.h"
#include "materialsystem/imaterialsystem.h"
#include "fx_line.h"
#include "engine/ivdebugoverlay.h"
#include "bone_setup.h"
#include "model_types.h"
// memdbgon must be the last include file in a .cpp file!!!
#include "tier0/memdbgon.h"
#define BARNACLE_TONGUE_POINTS 7
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
class C_NPC_Barnacle : public C_AI_BaseNPC
{
public:
DECLARE_CLASS( C_NPC_Barnacle, C_AI_BaseNPC );
DECLARE_CLIENTCLASS();
C_NPC_Barnacle( void );
virtual void GetRenderBounds( Vector &theMins, Vector &theMaxs )
{
BaseClass::GetRenderBounds( theMins, theMaxs );
// Extend our bounding box downwards the length of the tongue
theMins -= Vector( 0, 0, m_flAltitude );
}
// Purpose: Initialize absmin & absmax to the appropriate box
virtual void ComputeWorldSpaceSurroundingBox( Vector *pVecWorldMins, Vector *pVecWorldMaxs )
{
// Extend our bounding box downwards the length of the tongue
CollisionProp()->WorldSpaceAABB( pVecWorldMins, pVecWorldMaxs );
// We really care about the tongue tip. The altitude is not really relevant.
VectorMin( *pVecWorldMins, m_vecTip, *pVecWorldMins );
VectorMax( *pVecWorldMaxs, m_vecTip, *pVecWorldMaxs );
// pVecWorldMins->z -= m_flAltitude;
}
void OnDataChanged( DataUpdateType_t updateType );
void InitTonguePhysics( void );
void ClientThink( void );
void StandardBlendingRules( CStudioHdr *pStudioHdr, Vector pos[], Quaternion q[], float currentTime, int boneMask );
void SetVecTip( const float *pPosition );
void SetAltitude( float flAltitude );
// Purpose:
void ComputeVisualTipPoint( Vector *pTip );
protected:
Vector m_vecTipPrevious;
Vector m_vecRoot;
Vector m_vecTip;
Vector m_vecTipDrawOffset;
private:
// Tongue points
float m_flAltitude;
Vector m_vecTonguePoints[BARNACLE_TONGUE_POINTS];
CRopePhysics<BARNACLE_TONGUE_POINTS> m_TonguePhysics;
// Tongue physics delegate
class CBarnaclePhysicsDelegate : public CSimplePhysics::IHelper
{
public:
virtual void GetNodeForces( CSimplePhysics::CNode *pNodes, int iNode, Vector *pAccel );
virtual void ApplyConstraints( CSimplePhysics::CNode *pNodes, int nNodes );
C_NPC_Barnacle *m_pBarnacle;
};
friend class CBarnaclePhysicsDelegate;
CBarnaclePhysicsDelegate m_PhysicsDelegate;
private:
C_NPC_Barnacle( const C_NPC_Barnacle & ); // not defined, not accessible
};
static void RecvProxy_VecTip( const CRecvProxyData *pData, void *pStruct, void *pOut )
{
((C_NPC_Barnacle*)pStruct)->SetVecTip( pData->m_Value.m_Vector );
}
IMPLEMENT_CLIENTCLASS_DT( C_NPC_Barnacle, DT_Barnacle, CNPC_Barnacle )
RecvPropFloat( RECVINFO( m_flAltitude ) ),
RecvPropVector( RECVINFO( m_vecRoot ) ),
RecvPropVector( RECVINFO( m_vecTip ), 0, RecvProxy_VecTip ),
RecvPropVector( RECVINFO( m_vecTipDrawOffset ) ),
END_RECV_TABLE()
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
C_NPC_Barnacle::C_NPC_Barnacle( void )
{
m_PhysicsDelegate.m_pBarnacle = this;
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void C_NPC_Barnacle::OnDataChanged( DataUpdateType_t updateType )
{
BaseClass::OnDataChanged( updateType );
if ( updateType == DATA_UPDATE_CREATED )
{
InitTonguePhysics();
// We want to think every frame.
SetNextClientThink( CLIENT_THINK_ALWAYS );
return;
}
}
//-----------------------------------------------------------------------------
// Sets the tongue altitude
//-----------------------------------------------------------------------------
void C_NPC_Barnacle::SetAltitude( float flAltitude )
{
m_flAltitude = flAltitude;
}
void C_NPC_Barnacle::SetVecTip( const float *pPosition )
{
Vector vecNewTip;
vecNewTip.Init( pPosition[0], pPosition[1], pPosition[2] );
if ( vecNewTip != m_vecTip )
{
m_vecTip = vecNewTip;
CollisionProp()->MarkSurroundingBoundsDirty();
}
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void C_NPC_Barnacle::InitTonguePhysics( void )
{
// Init tongue spline
// First point is at the top
m_TonguePhysics.SetupSimulation( m_flAltitude / (BARNACLE_TONGUE_POINTS-1), &m_PhysicsDelegate );
m_TonguePhysics.Restart();
// Initialize the positions of the nodes.
m_TonguePhysics.GetFirstNode()->m_vPos = m_vecRoot;
m_TonguePhysics.GetFirstNode()->m_vPrevPos = m_TonguePhysics.GetFirstNode()->m_vPos;
float flAltitude = m_flAltitude;
for( int i = 1; i < m_TonguePhysics.NumNodes(); i++ )
{
flAltitude *= 0.5;
CSimplePhysics::CNode *pNode = m_TonguePhysics.GetNode( i );
pNode->m_vPos = m_TonguePhysics.GetNode(i-1)->m_vPos - Vector(0,0,flAltitude);
pNode->m_vPrevPos = pNode->m_vPos;
// Set the length of the node's spring
//m_TonguePhysics.ResetNodeSpringLength( i-1, flAltitude );
}
m_vecTipPrevious = m_vecTip;
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void C_NPC_Barnacle::ClientThink( void )
{
m_TonguePhysics.Simulate( gpGlobals->frametime );
// Set the spring's length to that of the tongue's extension
m_TonguePhysics.ResetSpringLength( m_flAltitude / (BARNACLE_TONGUE_POINTS-1) );
// Necessary because ComputeVisualTipPoint depends on m_vecTipPrevious
Vector vecTemp;
ComputeVisualTipPoint( &vecTemp );
m_vecTipPrevious = vecTemp;
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void C_NPC_Barnacle::StandardBlendingRules( CStudioHdr *hdr, Vector pos[], Quaternion q[], float currentTime, int boneMask )
{
BaseClass::StandardBlendingRules( hdr, pos, q, currentTime, boneMask );
if ( !hdr )
return;
int firstBone = Studio_BoneIndexByName( hdr, "Barnacle.tongue1" );
Vector vecPrevRight;
GetVectors( NULL, &vecPrevRight, NULL );
Vector vecPrev = pos[Studio_BoneIndexByName( hdr, "Barnacle.base" )];
Vector vecCurr = vec3_origin;
Vector vecForward;
for ( int i = 0; i <= BARNACLE_TONGUE_POINTS; i++ )
{
// We double up the bones at the last node.
if ( i == BARNACLE_TONGUE_POINTS )
{
vecCurr = m_TonguePhysics.GetLastNode()->m_vPos;
}
else
{
vecCurr = m_TonguePhysics.GetNode(i)->m_vPos;
}
//debugoverlay->AddBoxOverlay( vecCurr, -Vector(2,2,2), Vector(2,2,2), vec3_angle, 0,255,0, 128, 0.1 );
// Fill out the positions in local space
VectorITransform( vecCurr, EntityToWorldTransform(), pos[firstBone+i] );
vecCurr = pos[firstBone+i];
// Disallow twist in the tongue visually
// Forward vector has to follow the tongue, right + up have to minimize twist from
// the previous bone
// Fill out the angles
if ( i != BARNACLE_TONGUE_POINTS )
{
vecForward = (vecCurr - vecPrev);
if ( VectorNormalize( vecForward ) < 1e-3 )
{
vecForward.Init( 0, 0, 1 );
}
}
// Project the previous vecRight into a plane perpendicular to vecForward
// that's the vector closest to what we want...
Vector vecRight, vecUp;
VectorMA( vecPrevRight, -DotProduct( vecPrevRight, vecForward ), vecForward, vecRight );
VectorNormalize( vecRight );
CrossProduct( vecForward, vecRight, vecUp );
BasisToQuaternion( vecForward, vecRight, vecUp, q[firstBone+i] );
vecPrev = vecCurr;
vecPrevRight = vecRight;
}
}
//===============================================================================================================================
// BARNACLE TONGUE PHYSICS
//===============================================================================================================================
#define TONGUE_GRAVITY 0, 0, -1000
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void C_NPC_Barnacle::CBarnaclePhysicsDelegate::GetNodeForces( CSimplePhysics::CNode *pNodes, int iNode, Vector *pAccel )
{
// Gravity.
pAccel->Init( TONGUE_GRAVITY );
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
#define TIP_SNAP_FACTOR 200
// Todo: this really ought to be SIMD.
void C_NPC_Barnacle::ComputeVisualTipPoint( Vector *pTip )
{
float flTipMove = TIP_SNAP_FACTOR * gpGlobals->frametime;
Vector tipIdeal;
VectorAdd(m_vecTip, m_vecTipDrawOffset, tipIdeal);
if ( tipIdeal.DistToSqr( m_vecTipPrevious ) > (flTipMove * flTipMove) )
{
// Inch the visual tip toward the actual tip
VectorSubtract( tipIdeal, m_vecTipPrevious, *pTip );
VectorNormalize( *pTip );
*pTip *= flTipMove;
*pTip += m_vecTipPrevious;
}
else
{
*pTip = tipIdeal;
}
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void C_NPC_Barnacle::CBarnaclePhysicsDelegate::ApplyConstraints( CSimplePhysics::CNode *pNodes, int nNodes )
{
// Startpoint always stays at the root
pNodes[0].m_vPos = m_pBarnacle->m_vecRoot;
// Endpoint always stays at the tip
m_pBarnacle->ComputeVisualTipPoint( &pNodes[nNodes-1].m_vPos );
}

View File

@@ -0,0 +1,41 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
// $NoKeywords: $
//=============================================================================//
#include "cbase.h"
#include "c_ai_basenpc.h"
// memdbgon must be the last include file in a .cpp file!!!
#include "tier0/memdbgon.h"
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
class C_Barney : public C_AI_BaseNPC
{
public:
DECLARE_CLASS( C_Barney, C_AI_BaseNPC );
DECLARE_CLIENTCLASS();
C_Barney();
virtual ~C_Barney();
private:
C_Barney( const C_Barney & ); // not defined, not accessible
};
IMPLEMENT_CLIENTCLASS_DT(C_Barney, DT_NPC_Barney, CNPC_Barney)
END_RECV_TABLE()
C_Barney::C_Barney()
{
}
C_Barney::~C_Barney()
{
}

View File

@@ -0,0 +1,91 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
//=============================================================================//
#include "cbase.h"
#include "c_basehelicopter.h"
#include "proxyentity.h"
#include "materialsystem/imaterial.h"
#include "materialsystem/imaterialvar.h"
#include "KeyValues.h"
// memdbgon must be the last include file in a .cpp file!!!
#include "tier0/memdbgon.h"
IMPLEMENT_CLIENTCLASS_DT( C_BaseHelicopter, DT_BaseHelicopter, CBaseHelicopter )
RecvPropTime( RECVINFO( m_flStartupTime ) ),
END_RECV_TABLE()
C_BaseHelicopter::C_BaseHelicopter()
{
}
//-----------------------------------------------------------------------------
// Chopper blade fade-in time
//-----------------------------------------------------------------------------
#define FADE_IN_TIME 2.0f
//-----------------------------------------------------------------------------
// Sets the fade of the blades when the chopper starts up
//-----------------------------------------------------------------------------
class CHeliBladeMaterialProxy : public CEntityMaterialProxy
{
public:
CHeliBladeMaterialProxy() { m_AlphaVar = NULL; }
virtual ~CHeliBladeMaterialProxy() {}
virtual bool Init( IMaterial *pMaterial, KeyValues *pKeyValues );
virtual void OnBind( C_BaseEntity *pEntity );
virtual IMaterial *GetMaterial();
private:
IMaterialVar *m_AlphaVar;
bool m_bFadeOut;
};
bool CHeliBladeMaterialProxy::Init( IMaterial *pMaterial, KeyValues *pKeyValues )
{
bool foundVar;
m_AlphaVar = pMaterial->FindVar( "$alpha", &foundVar, false );
m_bFadeOut = pKeyValues->GetInt( "$fadeout", 0 ) != 0;
return foundVar;
}
void CHeliBladeMaterialProxy::OnBind( C_BaseEntity *pEnt )
{
if (!m_AlphaVar)
return;
C_BaseHelicopter *pHeli = dynamic_cast<C_BaseHelicopter*>( pEnt );
if ( pHeli )
{
float dt = gpGlobals->curtime - pHeli->StartupTime();
dt /= FADE_IN_TIME;
dt = clamp( dt, 0.0f, 1.0f );
if ( m_bFadeOut )
{
dt = 1.0f - dt;
}
m_AlphaVar->SetFloatValue( dt );
}
else
{
m_AlphaVar->SetFloatValue( 1.0f );
}
}
IMaterial *CHeliBladeMaterialProxy::GetMaterial()
{
if ( !m_AlphaVar )
return NULL;
return m_AlphaVar->GetOwningMaterial();
}
EXPOSE_INTERFACE( CHeliBladeMaterialProxy, IMaterialProxy, "HeliBlade" IMATERIAL_PROXY_INTERFACE_VERSION );

View File

@@ -0,0 +1,33 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
//=============================================================================//
#ifndef C_BASEHELICOPTER_H
#define C_BASEHELICOPTER_H
#ifdef _WIN32
#pragma once
#endif
#include "c_ai_basenpc.h"
class C_BaseHelicopter : public C_AI_BaseNPC
{
public:
DECLARE_CLASS( C_BaseHelicopter, C_AI_BaseNPC );
DECLARE_CLIENTCLASS();
C_BaseHelicopter();
float StartupTime() const { return m_flStartupTime; }
private:
C_BaseHelicopter( const C_BaseHelicopter &other ) {}
float m_flStartupTime;
};
#endif // C_BASEHELICOPTER_H

View File

@@ -0,0 +1,21 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
//=============================================================================//
#include "cbase.h"
#include "c_basehlcombatweapon.h"
#include "igamemovement.h"
// memdbgon must be the last include file in a .cpp file!!!
#include "tier0/memdbgon.h"
IMPLEMENT_CLIENTCLASS_DT( C_HLMachineGun, DT_HLMachineGun, CHLMachineGun )
END_RECV_TABLE()
IMPLEMENT_CLIENTCLASS_DT( C_HLSelectFireMachineGun, DT_HLSelectFireMachineGun, CHLSelectFireMachineGun )
END_RECV_TABLE()
IMPLEMENT_CLIENTCLASS_DT( C_BaseHLBludgeonWeapon, DT_BaseHLBludgeonWeapon, CBaseHLBludgeonWeapon )
END_RECV_TABLE()

View File

@@ -0,0 +1,36 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
//=============================================================================//
#include "basehlcombatweapon_shared.h"
#ifndef C_BASEHLCOMBATWEAPON_H
#define C_BASEHLCOMBATWEAPON_H
#ifdef _WIN32
#pragma once
#endif
class C_HLMachineGun : public C_BaseHLCombatWeapon
{
public:
DECLARE_CLASS( C_HLMachineGun, C_BaseHLCombatWeapon );
DECLARE_CLIENTCLASS();
};
class C_HLSelectFireMachineGun : public C_HLMachineGun
{
public:
DECLARE_CLASS( C_HLSelectFireMachineGun, C_HLMachineGun );
DECLARE_CLIENTCLASS();
};
class C_BaseHLBludgeonWeapon : public C_BaseHLCombatWeapon
{
public:
DECLARE_CLASS( C_BaseHLBludgeonWeapon, C_BaseHLCombatWeapon );
DECLARE_CLIENTCLASS();
};
#endif // C_BASEHLCOMBATWEAPON_H

View File

@@ -0,0 +1,659 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
// $NoKeywords: $
//=============================================================================//
#include "cbase.h"
#include "c_basehlplayer.h"
#include "playerandobjectenumerator.h"
#include "engine/ivdebugoverlay.h"
#include "c_ai_basenpc.h"
#include "in_buttons.h"
#include "collisionutils.h"
// memdbgon must be the last include file in a .cpp file!!!
#include "tier0/memdbgon.h"
// How fast to avoid collisions with center of other object, in units per second
#define AVOID_SPEED 2000.0f
extern ConVar cl_forwardspeed;
extern ConVar cl_backspeed;
extern ConVar cl_sidespeed;
extern ConVar zoom_sensitivity_ratio;
extern ConVar default_fov;
extern ConVar sensitivity;
ConVar cl_npc_speedmod_intime( "cl_npc_speedmod_intime", "0.25", FCVAR_CLIENTDLL | FCVAR_ARCHIVE );
ConVar cl_npc_speedmod_outtime( "cl_npc_speedmod_outtime", "1.5", FCVAR_CLIENTDLL | FCVAR_ARCHIVE );
IMPLEMENT_CLIENTCLASS_DT(C_BaseHLPlayer, DT_HL2_Player, CHL2_Player)
RecvPropDataTable( RECVINFO_DT(m_HL2Local),0, &REFERENCE_RECV_TABLE(DT_HL2Local) ),
RecvPropBool( RECVINFO( m_fIsSprinting ) ),
END_RECV_TABLE()
BEGIN_PREDICTION_DATA( C_BaseHLPlayer )
DEFINE_PRED_TYPEDESCRIPTION( m_HL2Local, C_HL2PlayerLocalData ),
DEFINE_PRED_FIELD( m_fIsSprinting, FIELD_BOOLEAN, FTYPEDESC_INSENDTABLE ),
END_PREDICTION_DATA()
// link to the correct class.
#if !defined ( HL2MP ) && !defined ( PORTAL )
LINK_ENTITY_TO_CLASS( player, C_BaseHLPlayer );
#endif
//-----------------------------------------------------------------------------
// Purpose: Drops player's primary weapon
//-----------------------------------------------------------------------------
void CC_DropPrimary( void )
{
C_BasePlayer *pPlayer = (C_BasePlayer *) C_BasePlayer::GetLocalPlayer();
if ( pPlayer == NULL )
return;
pPlayer->Weapon_DropPrimary();
}
static ConCommand dropprimary("dropprimary", CC_DropPrimary, "dropprimary: Drops the primary weapon of the player.");
//-----------------------------------------------------------------------------
// Constructor
//-----------------------------------------------------------------------------
C_BaseHLPlayer::C_BaseHLPlayer()
{
AddVar( &m_Local.m_vecPunchAngle, &m_Local.m_iv_vecPunchAngle, LATCH_SIMULATION_VAR );
AddVar( &m_Local.m_vecPunchAngleVel, &m_Local.m_iv_vecPunchAngleVel, LATCH_SIMULATION_VAR );
m_flZoomStart = 0.0f;
m_flZoomEnd = 0.0f;
m_flZoomRate = 0.0f;
m_flZoomStartTime = 0.0f;
m_flSpeedMod = cl_forwardspeed.GetFloat();
#ifdef MAPBASE
ConVarRef scissor("r_flashlightscissor");
scissor.SetValue("0");
#endif
}
//-----------------------------------------------------------------------------
// Purpose:
// Input : updateType -
//-----------------------------------------------------------------------------
void C_BaseHLPlayer::OnDataChanged( DataUpdateType_t updateType )
{
// Make sure we're thinking
if ( updateType == DATA_UPDATE_CREATED )
{
SetNextClientThink( CLIENT_THINK_ALWAYS );
}
BaseClass::OnDataChanged( updateType );
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void C_BaseHLPlayer::Weapon_DropPrimary( void )
{
engine->ServerCmd( "DropPrimary" );
}
float C_BaseHLPlayer::GetFOV()
{
//Find our FOV with offset zoom value
float flFOVOffset = BaseClass::GetFOV() + GetZoom();
// Clamp FOV in MP
int min_fov = ( gpGlobals->maxClients == 1 ) ? 5 : default_fov.GetInt();
// Don't let it go too low
flFOVOffset = MAX( min_fov, flFOVOffset );
return flFOVOffset;
}
//-----------------------------------------------------------------------------
// Purpose:
// Output : float
//-----------------------------------------------------------------------------
float C_BaseHLPlayer::GetZoom( void )
{
float fFOV = m_flZoomEnd;
//See if we need to lerp the values
if ( ( m_flZoomStart != m_flZoomEnd ) && ( m_flZoomRate > 0.0f ) )
{
float deltaTime = (float)( gpGlobals->curtime - m_flZoomStartTime ) / m_flZoomRate;
if ( deltaTime >= 1.0f )
{
//If we're past the zoom time, just take the new value and stop lerping
fFOV = m_flZoomStart = m_flZoomEnd;
}
else
{
fFOV = SimpleSplineRemapVal( deltaTime, 0.0f, 1.0f, m_flZoomStart, m_flZoomEnd );
}
}
return fFOV;
}
//-----------------------------------------------------------------------------
// Purpose:
// Input : FOVOffset -
// time -
//-----------------------------------------------------------------------------
void C_BaseHLPlayer::Zoom( float FOVOffset, float time )
{
m_flZoomStart = GetZoom();
m_flZoomEnd = FOVOffset;
m_flZoomRate = time;
m_flZoomStartTime = gpGlobals->curtime;
}
//-----------------------------------------------------------------------------
// Purpose: Hack to zero out player's pitch, use value from poseparameter instead
// Input : flags -
// Output : int
//-----------------------------------------------------------------------------
int C_BaseHLPlayer::DrawModel( int flags )
{
// Not pitch for player
QAngle saveAngles = GetLocalAngles();
QAngle useAngles = saveAngles;
useAngles[ PITCH ] = 0.0f;
SetLocalAngles( useAngles );
int iret = BaseClass::DrawModel( flags );
SetLocalAngles( saveAngles );
return iret;
}
//-----------------------------------------------------------------------------
// Purpose: Helper to remove from ladder
//-----------------------------------------------------------------------------
void C_BaseHLPlayer::ExitLadder()
{
if ( MOVETYPE_LADDER != GetMoveType() )
return;
SetMoveType( MOVETYPE_WALK );
SetMoveCollide( MOVECOLLIDE_DEFAULT );
// Remove from ladder
m_HL2Local.m_hLadder = NULL;
}
//-----------------------------------------------------------------------------
// Purpose: Determines if a player can be safely moved towards a point
// Input: pos - position to test move to, fVertDist - how far to trace downwards to see if the player would fall,
// radius - how close the player can be to the object, objPos - position of the object to avoid,
// objDir - direction the object is travelling
//-----------------------------------------------------------------------------
bool C_BaseHLPlayer::TestMove( const Vector &pos, float fVertDist, float radius, const Vector &objPos, const Vector &objDir )
{
trace_t trUp;
trace_t trOver;
trace_t trDown;
float flHit1, flHit2;
UTIL_TraceHull( GetAbsOrigin(), pos, GetPlayerMins(), GetPlayerMaxs(), MASK_SOLID_BRUSHONLY, this, COLLISION_GROUP_NONE, &trOver );
if ( trOver.fraction < 1.0f )
{
// check if the endpos intersects with the direction the object is travelling. if it doesn't, this is a good direction to move.
if ( objDir.IsZero() ||
( IntersectInfiniteRayWithSphere( objPos, objDir, trOver.endpos, radius, &flHit1, &flHit2 ) &&
( ( flHit1 >= 0.0f ) || ( flHit2 >= 0.0f ) ) )
)
{
// our first trace failed, so see if we can go farther if we step up.
// trace up to see if we have enough room.
UTIL_TraceHull( GetAbsOrigin(), GetAbsOrigin() + Vector( 0, 0, m_Local.m_flStepSize ),
GetPlayerMins(), GetPlayerMaxs(), MASK_SOLID_BRUSHONLY, this, COLLISION_GROUP_NONE, &trUp );
// do a trace from the stepped up height
UTIL_TraceHull( trUp.endpos, pos + Vector( 0, 0, trUp.endpos.z - trUp.startpos.z ),
GetPlayerMins(), GetPlayerMaxs(), MASK_SOLID_BRUSHONLY, this, COLLISION_GROUP_NONE, &trOver );
if ( trOver.fraction < 1.0f )
{
// check if the endpos intersects with the direction the object is travelling. if it doesn't, this is a good direction to move.
if ( objDir.IsZero() ||
( IntersectInfiniteRayWithSphere( objPos, objDir, trOver.endpos, radius, &flHit1, &flHit2 ) && ( ( flHit1 >= 0.0f ) || ( flHit2 >= 0.0f ) ) ) )
{
return false;
}
}
}
}
// trace down to see if this position is on the ground
UTIL_TraceLine( trOver.endpos, trOver.endpos - Vector( 0, 0, fVertDist ),
MASK_SOLID_BRUSHONLY, NULL, COLLISION_GROUP_NONE, &trDown );
if ( trDown.fraction == 1.0f )
return false;
return true;
}
//-----------------------------------------------------------------------------
// Client-side obstacle avoidance
//-----------------------------------------------------------------------------
void C_BaseHLPlayer::PerformClientSideObstacleAvoidance( float flFrameTime, CUserCmd *pCmd )
{
// Don't avoid if noclipping or in movetype none
switch ( GetMoveType() )
{
case MOVETYPE_NOCLIP:
case MOVETYPE_NONE:
case MOVETYPE_OBSERVER:
return;
default:
break;
}
// Try to steer away from any objects/players we might interpenetrate
Vector size = WorldAlignSize();
float radius = 0.7f * sqrt( size.x * size.x + size.y * size.y );
float curspeed = GetLocalVelocity().Length2D();
//int slot = 1;
//engine->Con_NPrintf( slot++, "speed %f\n", curspeed );
//engine->Con_NPrintf( slot++, "radius %f\n", radius );
// If running, use a larger radius
float factor = 1.0f;
if ( curspeed > 150.0f )
{
curspeed = MIN( 2048.0f, curspeed );
factor = ( 1.0f + ( curspeed - 150.0f ) / 150.0f );
//engine->Con_NPrintf( slot++, "scaleup (%f) to radius %f\n", factor, radius * factor );
radius = radius * factor;
}
Vector currentdir;
Vector rightdir;
QAngle vAngles = pCmd->viewangles;
vAngles.x = 0;
AngleVectors( vAngles, &currentdir, &rightdir, NULL );
bool istryingtomove = false;
bool ismovingforward = false;
if ( fabs( pCmd->forwardmove ) > 0.0f ||
fabs( pCmd->sidemove ) > 0.0f )
{
istryingtomove = true;
if ( pCmd->forwardmove > 1.0f )
{
ismovingforward = true;
}
}
if ( istryingtomove == true )
radius *= 1.3f;
CPlayerAndObjectEnumerator avoid( radius );
partition->EnumerateElementsInSphere( PARTITION_CLIENT_SOLID_EDICTS, GetAbsOrigin(), radius, false, &avoid );
// Okay, decide how to avoid if there's anything close by
int c = avoid.GetObjectCount();
if ( c <= 0 )
return;
//engine->Con_NPrintf( slot++, "moving %s forward %s\n", istryingtomove ? "true" : "false", ismovingforward ? "true" : "false" );
float adjustforwardmove = 0.0f;
float adjustsidemove = 0.0f;
for ( int i = 0; i < c; i++ )
{
C_AI_BaseNPC *obj = dynamic_cast< C_AI_BaseNPC *>(avoid.GetObject( i ));
if( !obj )
continue;
Vector vecToObject = obj->GetAbsOrigin() - GetAbsOrigin();
float flDist = vecToObject.Length2D();
// Figure out a 2D radius for the object
Vector vecWorldMins, vecWorldMaxs;
obj->CollisionProp()->WorldSpaceAABB( &vecWorldMins, &vecWorldMaxs );
Vector objSize = vecWorldMaxs - vecWorldMins;
float objectradius = 0.5f * sqrt( objSize.x * objSize.x + objSize.y * objSize.y );
//Don't run this code if the NPC is not moving UNLESS we are in stuck inside of them.
if ( !obj->IsMoving() && flDist > objectradius )
continue;
if ( flDist > objectradius && obj->IsEffectActive( EF_NODRAW ) )
{
obj->RemoveEffects( EF_NODRAW );
}
Vector vecNPCVelocity;
obj->EstimateAbsVelocity( vecNPCVelocity );
float flNPCSpeed = VectorNormalize( vecNPCVelocity );
Vector vPlayerVel = GetAbsVelocity();
VectorNormalize( vPlayerVel );
float flHit1, flHit2;
Vector vRayDir = vecToObject;
VectorNormalize( vRayDir );
float flVelProduct = DotProduct( vecNPCVelocity, vPlayerVel );
float flDirProduct = DotProduct( vRayDir, vPlayerVel );
if ( !IntersectInfiniteRayWithSphere(
GetAbsOrigin(),
vRayDir,
obj->GetAbsOrigin(),
radius,
&flHit1,
&flHit2 ) )
continue;
Vector dirToObject = -vecToObject;
VectorNormalize( dirToObject );
float fwd = 0;
float rt = 0;
float sidescale = 2.0f;
float forwardscale = 1.0f;
bool foundResult = false;
Vector vMoveDir = vecNPCVelocity;
if ( flNPCSpeed > 0.001f )
{
// This NPC is moving. First try deflecting the player left or right relative to the NPC's velocity.
// Start with whatever side they're on relative to the NPC's velocity.
Vector vecNPCTrajectoryRight = CrossProduct( vecNPCVelocity, Vector( 0, 0, 1) );
int iDirection = ( vecNPCTrajectoryRight.Dot( dirToObject ) > 0 ) ? 1 : -1;
for ( int nTries = 0; nTries < 2; nTries++ )
{
Vector vecTryMove = vecNPCTrajectoryRight * iDirection;
VectorNormalize( vecTryMove );
Vector vTestPosition = GetAbsOrigin() + vecTryMove * radius * 2;
if ( TestMove( vTestPosition, size.z * 2, radius * 2, obj->GetAbsOrigin(), vMoveDir ) )
{
fwd = currentdir.Dot( vecTryMove );
rt = rightdir.Dot( vecTryMove );
//Msg( "PUSH DEFLECT fwd=%f, rt=%f\n", fwd, rt );
foundResult = true;
break;
}
else
{
// Try the other direction.
iDirection *= -1;
}
}
}
else
{
// the object isn't moving, so try moving opposite the way it's facing
Vector vecNPCForward;
obj->GetVectors( &vecNPCForward, NULL, NULL );
Vector vTestPosition = GetAbsOrigin() - vecNPCForward * radius * 2;
if ( TestMove( vTestPosition, size.z * 2, radius * 2, obj->GetAbsOrigin(), vMoveDir ) )
{
fwd = currentdir.Dot( -vecNPCForward );
rt = rightdir.Dot( -vecNPCForward );
if ( flDist < objectradius )
{
obj->AddEffects( EF_NODRAW );
}
//Msg( "PUSH AWAY FACE fwd=%f, rt=%f\n", fwd, rt );
foundResult = true;
}
}
if ( !foundResult )
{
// test if we can move in the direction the object is moving
Vector vTestPosition = GetAbsOrigin() + vMoveDir * radius * 2;
if ( TestMove( vTestPosition, size.z * 2, radius * 2, obj->GetAbsOrigin(), vMoveDir ) )
{
fwd = currentdir.Dot( vMoveDir );
rt = rightdir.Dot( vMoveDir );
if ( flDist < objectradius )
{
obj->AddEffects( EF_NODRAW );
}
//Msg( "PUSH ALONG fwd=%f, rt=%f\n", fwd, rt );
foundResult = true;
}
else
{
// try moving directly away from the object
Vector vTestPosition = GetAbsOrigin() - dirToObject * radius * 2;
if ( TestMove( vTestPosition, size.z * 2, radius * 2, obj->GetAbsOrigin(), vMoveDir ) )
{
fwd = currentdir.Dot( -dirToObject );
rt = rightdir.Dot( -dirToObject );
foundResult = true;
//Msg( "PUSH AWAY fwd=%f, rt=%f\n", fwd, rt );
}
}
}
if ( !foundResult )
{
// test if we can move through the object
Vector vTestPosition = GetAbsOrigin() - vMoveDir * radius * 2;
fwd = currentdir.Dot( -vMoveDir );
rt = rightdir.Dot( -vMoveDir );
if ( flDist < objectradius )
{
obj->AddEffects( EF_NODRAW );
}
//Msg( "PUSH THROUGH fwd=%f, rt=%f\n", fwd, rt );
foundResult = true;
}
// If running, then do a lot more sideways veer since we're not going to do anything to
// forward velocity
if ( istryingtomove )
{
sidescale = 6.0f;
}
if ( flVelProduct > 0.0f && flDirProduct > 0.0f )
{
sidescale = 0.1f;
}
float force = 1.0f;
float forward = forwardscale * fwd * force * AVOID_SPEED;
float side = sidescale * rt * force * AVOID_SPEED;
adjustforwardmove += forward;
adjustsidemove += side;
}
pCmd->forwardmove += adjustforwardmove;
pCmd->sidemove += adjustsidemove;
// Clamp the move to within legal limits, preserving direction. This is a little
// complicated because we have different limits for forward, back, and side
//Msg( "PRECLAMP: forwardmove=%f, sidemove=%f\n", pCmd->forwardmove, pCmd->sidemove );
float flForwardScale = 1.0f;
if ( pCmd->forwardmove > fabs( cl_forwardspeed.GetFloat() ) )
{
flForwardScale = fabs( cl_forwardspeed.GetFloat() ) / pCmd->forwardmove;
}
else if ( pCmd->forwardmove < -fabs( cl_backspeed.GetFloat() ) )
{
flForwardScale = fabs( cl_backspeed.GetFloat() ) / fabs( pCmd->forwardmove );
}
float flSideScale = 1.0f;
if ( fabs( pCmd->sidemove ) > fabs( cl_sidespeed.GetFloat() ) )
{
flSideScale = fabs( cl_sidespeed.GetFloat() ) / fabs( pCmd->sidemove );
}
float flScale = MIN( flForwardScale, flSideScale );
pCmd->forwardmove *= flScale;
pCmd->sidemove *= flScale;
//Msg( "POSTCLAMP: forwardmove=%f, sidemove=%f\n", pCmd->forwardmove, pCmd->sidemove );
}
void C_BaseHLPlayer::PerformClientSideNPCSpeedModifiers( float flFrameTime, CUserCmd *pCmd )
{
if ( m_hClosestNPC == NULL )
{
if ( m_flSpeedMod != cl_forwardspeed.GetFloat() )
{
float flDeltaTime = (m_flSpeedModTime - gpGlobals->curtime);
m_flSpeedMod = RemapValClamped( flDeltaTime, cl_npc_speedmod_outtime.GetFloat(), 0, m_flExitSpeedMod, cl_forwardspeed.GetFloat() );
}
}
else
{
C_AI_BaseNPC *pNPC = dynamic_cast< C_AI_BaseNPC *>( m_hClosestNPC.Get() );
if ( pNPC )
{
float flDist = (GetAbsOrigin() - pNPC->GetAbsOrigin()).LengthSqr();
bool bShouldModSpeed = false;
// Within range?
if ( flDist < pNPC->GetSpeedModifyRadius() )
{
// Now, only slowdown if we're facing & running parallel to the target's movement
// Facing check first (in 2D)
Vector vecTargetOrigin = pNPC->GetAbsOrigin();
Vector los = ( vecTargetOrigin - EyePosition() );
los.z = 0;
VectorNormalize( los );
Vector facingDir;
AngleVectors( GetAbsAngles(), &facingDir );
float flDot = DotProduct( los, facingDir );
if ( flDot > 0.8 )
{
/*
// Velocity check (abort if the target isn't moving)
Vector vecTargetVelocity;
pNPC->EstimateAbsVelocity( vecTargetVelocity );
float flSpeed = VectorNormalize(vecTargetVelocity);
Vector vecMyVelocity = GetAbsVelocity();
VectorNormalize(vecMyVelocity);
if ( flSpeed > 1.0 )
{
// Velocity roughly parallel?
if ( DotProduct(vecTargetVelocity,vecMyVelocity) > 0.4 )
{
bShouldModSpeed = true;
}
}
else
{
// NPC's not moving, slow down if we're moving at him
//Msg("Dot: %.2f\n", DotProduct( los, vecMyVelocity ) );
if ( DotProduct( los, vecMyVelocity ) > 0.8 )
{
bShouldModSpeed = true;
}
}
*/
bShouldModSpeed = true;
}
}
if ( !bShouldModSpeed )
{
m_hClosestNPC = NULL;
m_flSpeedModTime = gpGlobals->curtime + cl_npc_speedmod_outtime.GetFloat();
m_flExitSpeedMod = m_flSpeedMod;
return;
}
else
{
if ( m_flSpeedMod != pNPC->GetSpeedModifySpeed() )
{
float flDeltaTime = (m_flSpeedModTime - gpGlobals->curtime);
m_flSpeedMod = RemapValClamped( flDeltaTime, cl_npc_speedmod_intime.GetFloat(), 0, cl_forwardspeed.GetFloat(), pNPC->GetSpeedModifySpeed() );
}
}
}
}
if ( pCmd->forwardmove > 0.0f )
{
pCmd->forwardmove = clamp( pCmd->forwardmove, -m_flSpeedMod, m_flSpeedMod );
}
else
{
pCmd->forwardmove = clamp( pCmd->forwardmove, -m_flSpeedMod, m_flSpeedMod );
}
pCmd->sidemove = clamp( pCmd->sidemove, -m_flSpeedMod, m_flSpeedMod );
//Msg( "fwd %f right %f\n", pCmd->forwardmove, pCmd->sidemove );
}
//-----------------------------------------------------------------------------
// Purpose: Input handling
//-----------------------------------------------------------------------------
bool C_BaseHLPlayer::CreateMove( float flInputSampleTime, CUserCmd *pCmd )
{
bool bResult = BaseClass::CreateMove( flInputSampleTime, pCmd );
if ( !IsInAVehicle() )
{
PerformClientSideObstacleAvoidance( TICK_INTERVAL, pCmd );
PerformClientSideNPCSpeedModifiers( TICK_INTERVAL, pCmd );
}
return bResult;
}
//-----------------------------------------------------------------------------
// Purpose: Input handling
//-----------------------------------------------------------------------------
void C_BaseHLPlayer::BuildTransformations( CStudioHdr *hdr, Vector *pos, Quaternion q[], const matrix3x4_t& cameraTransform, int boneMask, CBoneBitList &boneComputed )
{
BaseClass::BuildTransformations( hdr, pos, q, cameraTransform, boneMask, boneComputed );
BuildFirstPersonMeathookTransformations( hdr, pos, q, cameraTransform, boneMask, boneComputed, "ValveBiped.Bip01_Head1" );
}

View File

@@ -0,0 +1,87 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
// $Workfile: $
// $NoKeywords: $
//=============================================================================//
#if !defined( C_BASEHLPLAYER_H )
#define C_BASEHLPLAYER_H
#ifdef _WIN32
#pragma once
#endif
#include "c_baseplayer.h"
#include "c_hl2_playerlocaldata.h"
class C_BaseHLPlayer : public C_BasePlayer
{
public:
DECLARE_CLASS( C_BaseHLPlayer, C_BasePlayer );
DECLARE_CLIENTCLASS();
DECLARE_PREDICTABLE();
C_BaseHLPlayer();
virtual void OnDataChanged( DataUpdateType_t updateType );
void Weapon_DropPrimary( void );
float GetFOV();
void Zoom( float FOVOffset, float time );
float GetZoom( void );
bool IsZoomed( void ) { return m_HL2Local.m_bZooming; }
//Tony; minor cosmetic really, fix confusion by simply renaming this one; everything calls IsSprinting(), and this isn't really even used.
bool IsSprintActive( void ) { return m_HL2Local.m_bitsActiveDevices & bits_SUIT_DEVICE_SPRINT; }
bool IsFlashlightActive( void ) { return m_HL2Local.m_bitsActiveDevices & bits_SUIT_DEVICE_FLASHLIGHT; }
bool IsBreatherActive( void ) { return m_HL2Local.m_bitsActiveDevices & bits_SUIT_DEVICE_BREATHER; }
#ifdef MAPBASE
bool IsCustomDevice0Active( void ) { return m_HL2Local.m_bitsActiveDevices & bits_SUIT_DEVICE_CUSTOM0; }
bool IsCustomDevice1Active( void ) { return m_HL2Local.m_bitsActiveDevices & bits_SUIT_DEVICE_CUSTOM1; }
bool IsCustomDevice2Active( void ) { return m_HL2Local.m_bitsActiveDevices & bits_SUIT_DEVICE_CUSTOM2; }
#endif
virtual int DrawModel( int flags );
virtual void BuildTransformations( CStudioHdr *hdr, Vector *pos, Quaternion q[], const matrix3x4_t& cameraTransform, int boneMask, CBoneBitList &boneComputed );
LadderMove_t *GetLadderMove() { return &m_HL2Local.m_LadderMove; }
virtual void ExitLadder();
bool IsSprinting() const { return m_fIsSprinting; }
// Input handling
virtual bool CreateMove( float flInputSampleTime, CUserCmd *pCmd );
void PerformClientSideObstacleAvoidance( float flFrameTime, CUserCmd *pCmd );
void PerformClientSideNPCSpeedModifiers( float flFrameTime, CUserCmd *pCmd );
bool IsWeaponLowered( void ) { return m_HL2Local.m_bWeaponLowered; }
public:
C_HL2PlayerLocalData m_HL2Local;
EHANDLE m_hClosestNPC;
float m_flSpeedModTime;
bool m_fIsSprinting;
private:
C_BaseHLPlayer( const C_BaseHLPlayer & ); // not defined, not accessible
bool TestMove( const Vector &pos, float fVertDist, float radius, const Vector &objPos, const Vector &objDir );
float m_flZoomStart;
float m_flZoomEnd;
float m_flZoomRate;
float m_flZoomStartTime;
bool m_bPlayUseDenySound; // Signaled by PlayerUse, but can be unset by HL2 ladder code...
float m_flSpeedMod;
float m_flExitSpeedMod;
friend class CHL2GameMovement;
};
#endif

View File

@@ -0,0 +1,483 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
//=============================================================================//
#include "cbase.h"
#include "particles_simple.h"
#include "citadel_effects_shared.h"
#include "particles_attractor.h"
#include "fx_quad.h"
class C_CitadelEnergyCore : public C_BaseEntity
{
DECLARE_CLASS( C_CitadelEnergyCore, C_BaseEntity );
DECLARE_CLIENTCLASS();
public:
void OnDataChanged( DataUpdateType_t updateType );
RenderGroup_t GetRenderGroup( void );
void ClientThink( void );
void NotifyShouldTransmit( ShouldTransmitState_t state );
void UpdateIdle( float percentage );
void UpdateCharging( float percentage );
void UpdateDischarging( void );
private:
bool SetupEmitters( void );
inline float GetStateDurationPercentage( void );
float m_flScale;
int m_nState;
float m_flDuration;
float m_flStartTime;
int m_spawnflags;
CSmartPtr<CSimpleEmitter> m_pSimpleEmitter;
CSmartPtr<CParticleAttractor> m_pAttractorEmitter;
};
IMPLEMENT_CLIENTCLASS_DT( C_CitadelEnergyCore, DT_CitadelEnergyCore, CCitadelEnergyCore )
RecvPropFloat( RECVINFO(m_flScale) ),
RecvPropInt( RECVINFO(m_nState) ),
RecvPropFloat( RECVINFO(m_flDuration) ),
RecvPropFloat( RECVINFO(m_flStartTime) ),
RecvPropInt( RECVINFO(m_spawnflags) ),
END_RECV_TABLE()
//-----------------------------------------------------------------------------
// Purpose:
// Output : RenderGroup_t
//-----------------------------------------------------------------------------
RenderGroup_t C_CitadelEnergyCore::GetRenderGroup( void )
{
return RENDER_GROUP_TRANSLUCENT_ENTITY;
}
//-----------------------------------------------------------------------------
// Purpose:
// Input : updateType -
//-----------------------------------------------------------------------------
void C_CitadelEnergyCore::OnDataChanged( DataUpdateType_t updateType )
{
BaseClass::OnDataChanged( updateType );
if ( updateType == DATA_UPDATE_CREATED )
{
SetNextClientThink( CLIENT_THINK_ALWAYS );
SetupEmitters();
}
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
bool C_CitadelEnergyCore::SetupEmitters( void )
{
// Setup the basic core emitter
if ( m_pSimpleEmitter.IsValid() == false )
{
m_pSimpleEmitter = CSimpleEmitter::Create( "energycore" );
if ( m_pSimpleEmitter.IsValid() == false )
return false;
}
// Setup the attractor emitter
if ( m_pAttractorEmitter.IsValid() == false )
{
m_pAttractorEmitter = CParticleAttractor::Create( GetAbsOrigin(), "energyattractor" );
if ( m_pAttractorEmitter.IsValid() == false )
return false;
}
return true;
}
//-----------------------------------------------------------------------------
// Purpose:
// Input : percentage -
//-----------------------------------------------------------------------------
void C_CitadelEnergyCore::UpdateIdle( float percentage )
{
// Only do these particles if required
if ( m_spawnflags & SF_ENERGYCORE_NO_PARTICLES )
return;
// Must be active
if ( percentage >= 1.0f )
return;
// Emitters must be valid
if ( SetupEmitters() == false )
return;
// Reset our sort origin
m_pSimpleEmitter->SetSortOrigin( GetAbsOrigin() );
SimpleParticle *sParticle;
// Do the charging particles
m_pAttractorEmitter->SetAttractorOrigin( GetAbsOrigin() );
Vector forward, right, up;
AngleVectors( GetAbsAngles(), &forward, &right, &up );
Vector offset;
float dist;
int numParticles = floor( 4.0f * percentage );
for ( int i = 0; i < numParticles; i++ )
{
dist = random->RandomFloat( 4.0f * percentage, 64.0f * percentage );
offset = forward * dist;
dist = RemapValClamped( dist, 4.0f * percentage, 64.0f * percentage, 6.0f, 1.0f );
offset += right * random->RandomFloat( -4.0f * dist, 4.0f * dist );
offset += up * random->RandomFloat( -4.0f * dist, 4.0f * dist );
offset += GetAbsOrigin();
sParticle = (SimpleParticle *) m_pAttractorEmitter->AddParticle( sizeof(SimpleParticle), m_pAttractorEmitter->GetPMaterial( "effects/strider_muzzle" ), 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 = 0.0f;
float alpha = 255 * percentage;
sParticle->m_uchColor[0] = alpha;
sParticle->m_uchColor[1] = alpha;
sParticle->m_uchColor[2] = alpha;
sParticle->m_uchStartAlpha = alpha;
sParticle->m_uchEndAlpha = 0;
sParticle->m_uchStartSize = random->RandomFloat( 1, 2 );
sParticle->m_uchEndSize = 0;
}
}
//-----------------------------------------------------------------------------
// Purpose:
// Input : percentage -
//-----------------------------------------------------------------------------
void C_CitadelEnergyCore::UpdateCharging( float percentage )
{
// Emitters must be valid
if ( SetupEmitters() == false )
return;
if ( percentage <= 0.0f )
return;
// Reset our sort origin
m_pSimpleEmitter->SetSortOrigin( GetAbsOrigin() );
float flScale = 4.0f * m_flScale * percentage;
SimpleParticle *sParticle;
// Do the core effects
for ( int i = 0; i < 2; i++ )
{
sParticle = (SimpleParticle *) m_pSimpleEmitter->AddParticle( sizeof(SimpleParticle), m_pSimpleEmitter->GetPMaterial( "effects/strider_muzzle" ), GetAbsOrigin() );
if ( sParticle == NULL )
return;
sParticle->m_vecVelocity = vec3_origin;
sParticle->m_flDieTime = 0.1f;
sParticle->m_flLifetime = 0.0f;
sParticle->m_flRoll = Helper_RandomInt( 0, 360 );
sParticle->m_flRollDelta = 0.0f;
float alpha = 255;
sParticle->m_uchColor[0] = alpha;
sParticle->m_uchColor[1] = alpha;
sParticle->m_uchColor[2] = alpha;
sParticle->m_uchStartAlpha = alpha;
sParticle->m_uchEndAlpha = 0;
if ( i < 2 )
{
sParticle->m_uchStartSize = flScale * (i+1);
sParticle->m_uchEndSize = sParticle->m_uchStartSize * 2.0f;
}
else
{
if ( random->RandomInt( 0, 20 ) == 0 )
{
sParticle->m_uchStartSize = flScale * (i+1);
sParticle->m_uchEndSize = sParticle->m_uchStartSize * 4.0f;
sParticle->m_flDieTime = 0.25f;
}
else
{
sParticle->m_uchStartSize = flScale * (i+1);
sParticle->m_uchEndSize = sParticle->m_uchStartSize * 2.0f;
}
}
}
// Only do these particles if required
if ( m_spawnflags & SF_ENERGYCORE_NO_PARTICLES )
return;
// Do the charging particles
m_pAttractorEmitter->SetAttractorOrigin( GetAbsOrigin() );
Vector forward, right, up;
AngleVectors( GetAbsAngles(), &forward, &right, &up );
Vector offset;
float dist;
int numParticles = floor( 4.0f * percentage );
for ( int i = 0; i < numParticles; i++ )
{
dist = random->RandomFloat( 4.0f * percentage, 64.0f * percentage );
offset = forward * dist;
dist = RemapValClamped( dist, 4.0f * percentage, 64.0f * percentage, 6.0f, 1.0f );
offset += right * random->RandomFloat( -4.0f * dist, 4.0f * dist );
offset += up * random->RandomFloat( -4.0f * dist, 4.0f * dist );
offset += GetAbsOrigin();
sParticle = (SimpleParticle *) m_pAttractorEmitter->AddParticle( sizeof(SimpleParticle), m_pAttractorEmitter->GetPMaterial( "effects/strider_muzzle" ), 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 = 0.0f;
float alpha = 255 * percentage;
sParticle->m_uchColor[0] = alpha;
sParticle->m_uchColor[1] = alpha;
sParticle->m_uchColor[2] = alpha;
sParticle->m_uchStartAlpha = alpha;
sParticle->m_uchEndAlpha = 0;
sParticle->m_uchStartSize = random->RandomFloat( 1, 2 );
sParticle->m_uchEndSize = 0;
}
}
//-----------------------------------------------------------------------------
// Purpose:
// Input : percentage -
//-----------------------------------------------------------------------------
void C_CitadelEnergyCore::UpdateDischarging( void )
{
// Emitters must be valid
if ( SetupEmitters() == false )
return;
// Reset our sort origin
m_pSimpleEmitter->SetSortOrigin( GetAbsOrigin() );
float flScale = 8.0f * m_flScale;
Vector forward, right, up;
AngleVectors( GetAbsAngles(), &forward, &right, &up );
SimpleParticle *sParticle;
// Base of the core effect
sParticle = (SimpleParticle *) m_pSimpleEmitter->AddParticle( sizeof(SimpleParticle), m_pSimpleEmitter->GetPMaterial( "effects/strider_muzzle" ), GetAbsOrigin() );
if ( sParticle == NULL )
return;
sParticle->m_vecVelocity = forward * 32.0f;
sParticle->m_flDieTime = 0.2f;
sParticle->m_flLifetime = 0.0f;
sParticle->m_flRoll = Helper_RandomInt( 0, 360 );
sParticle->m_flRollDelta = 0.0f;
float alpha = 128;
sParticle->m_uchColor[0] = alpha;
sParticle->m_uchColor[1] = alpha;
sParticle->m_uchColor[2] = alpha;
sParticle->m_uchStartAlpha = alpha;
sParticle->m_uchEndAlpha = 0;
sParticle->m_uchStartSize = flScale * 2.0f;
sParticle->m_uchEndSize = sParticle->m_uchStartSize * 2.0f;
// Make sure we encompass the complete particle here!
m_pSimpleEmitter->SetParticleCullRadius( sParticle->m_uchEndSize );
// Do the core effects
for ( int i = 0; i < 2; i++ )
{
sParticle = (SimpleParticle *) m_pSimpleEmitter->AddParticle( sizeof(SimpleParticle), m_pSimpleEmitter->GetPMaterial( "effects/combinemuzzle2" ), GetAbsOrigin() );
if ( sParticle == NULL )
return;
sParticle->m_vecVelocity = forward * ( 32.0f * (i+1) );
sParticle->m_flDieTime = 0.2f;
sParticle->m_flLifetime = 0.0f;
sParticle->m_flRoll = Helper_RandomInt( 0, 360 );
sParticle->m_flRollDelta = 0.0f;
float alpha = 100;
sParticle->m_uchColor[0] = alpha;
sParticle->m_uchColor[1] = alpha;
sParticle->m_uchColor[2] = alpha;
sParticle->m_uchStartAlpha = alpha;
sParticle->m_uchEndAlpha = 0;
if ( i < 1 )
{
sParticle->m_uchStartSize = flScale * (i+1);
sParticle->m_uchEndSize = sParticle->m_uchStartSize * 2.0f;
}
else
{
if ( random->RandomInt( 0, 20 ) == 0 )
{
sParticle->m_uchStartSize = flScale * (i+1);
sParticle->m_uchEndSize = 0.0f;
sParticle->m_flDieTime = 0.25f;
}
else
{
sParticle->m_uchStartSize = flScale * (i+1);
sParticle->m_uchEndSize = 0.0f;
}
}
}
// Only do these particles if required
if ( m_spawnflags & SF_ENERGYCORE_NO_PARTICLES )
return;
// Do the charging particles
m_pAttractorEmitter->SetAttractorOrigin( GetAbsOrigin() );
Vector offset;
float dist;
for ( int i = 0; i < 4; i++ )
{
dist = random->RandomFloat( 4.0f * m_flScale, 64.0f * m_flScale );
offset = forward * dist;
dist = RemapValClamped( dist, 4.0f * m_flScale, 64.0f * m_flScale, 6.0f, 1.0f );
offset += right * random->RandomFloat( -2.0f * dist * m_flScale, 2.0f * dist * m_flScale );
offset += up * random->RandomFloat( -2.0f * dist * m_flScale, 2.0f * dist * m_flScale );
offset += GetAbsOrigin();
sParticle = (SimpleParticle *) m_pAttractorEmitter->AddParticle( sizeof(SimpleParticle), m_pAttractorEmitter->GetPMaterial( "effects/combinemuzzle2_dark" ), offset );
if ( sParticle == NULL )
return;
sParticle->m_vecVelocity = Vector(0,0,2);
sParticle->m_flDieTime = 0.5f;
sParticle->m_flLifetime = 0.0f;
sParticle->m_flRoll = Helper_RandomInt( 0, 360 );
sParticle->m_flRollDelta = 0.0f;
float alpha = 255;
sParticle->m_uchColor[0] = alpha;
sParticle->m_uchColor[1] = alpha;
sParticle->m_uchColor[2] = alpha;
sParticle->m_uchStartAlpha = alpha;
sParticle->m_uchEndAlpha = 0;
sParticle->m_uchStartSize = 1;
sParticle->m_uchEndSize = 0;
}
}
//-----------------------------------------------------------------------------
// Purpose:
// Output : inline float
//-----------------------------------------------------------------------------
inline float C_CitadelEnergyCore::GetStateDurationPercentage( void )
{
if ( m_flDuration == 0 )
return 0.0f;
return RemapValClamped( ( gpGlobals->curtime - m_flStartTime ), 0, m_flDuration, 0, 1.0f );;
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void C_CitadelEnergyCore::NotifyShouldTransmit( ShouldTransmitState_t state )
{
BaseClass::NotifyShouldTransmit( state );
// Turn off
if ( state == SHOULDTRANSMIT_END )
{
SetNextClientThink( CLIENT_THINK_NEVER );
}
// Turn on
if ( state == SHOULDTRANSMIT_START )
{
SetNextClientThink( CLIENT_THINK_ALWAYS );
}
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void C_CitadelEnergyCore::ClientThink( void )
{
if ( gpGlobals->frametime <= 0.0f )
return;
float flDuration = GetStateDurationPercentage();
switch( m_nState )
{
case ENERGYCORE_STATE_OFF:
UpdateIdle( 1.0f - flDuration );
break;
case ENERGYCORE_STATE_CHARGING:
UpdateCharging( flDuration );
break;
case ENERGYCORE_STATE_DISCHARGING:
UpdateDischarging( );
break;
}
}

View File

@@ -0,0 +1,66 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose: Implements C_Corpse
//
// $NoKeywords: $
//=============================================================================//
#include "cbase.h"
#include "c_corpse.h"
// memdbgon must be the last include file in a .cpp file!!!
#include "tier0/memdbgon.h"
IMPLEMENT_CLIENTCLASS_DT(C_Corpse, DT_Corpse, CCorpse)
RecvPropInt(RECVINFO(m_nReferencePlayer))
END_RECV_TABLE()
C_Corpse::C_Corpse()
{
m_nReferencePlayer = 0;
}
int C_Corpse::DrawModel( int flags )
{
int drawn = 0;
if ( m_nReferencePlayer <= 0 ||
m_nReferencePlayer > gpGlobals->maxClients )
{
return drawn;
};
// Make sure m_pstudiohdr is valid for drawing
if ( !GetModelPtr() )
{
return drawn;
}
if ( !m_bReadyToDraw )
return 0;
// get copy of player
C_BasePlayer *player = dynamic_cast< C_BasePlayer *>( cl_entitylist->GetEnt( m_nReferencePlayer ) );
if ( player )
{
Vector zero;
zero.Init();
drawn = modelrender->DrawModel(
flags,
this,
MODEL_INSTANCE_INVALID,
m_nReferencePlayer,
GetModel(),
GetAbsOrigin(),
GetAbsAngles(),
m_nSkin,
m_nBody,
m_nHitboxSet );
}
return drawn;
}

View File

@@ -0,0 +1,32 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
// $NoKeywords: $
//=============================================================================//
#if !defined( C_CORPSE_H )
#define C_CORPSE_H
#ifdef _WIN32
#pragma once
#endif
class C_Corpse : public C_BaseAnimating
{
public:
DECLARE_CLASS( C_Corpse, C_BaseAnimating );
DECLARE_CLIENTCLASS();
C_Corpse( void );
virtual int DrawModel( int flags );
public:
// The player whom we are copying our data from
int m_nReferencePlayer;
private:
C_Corpse( const C_Corpse & );
};
#endif // C_CORPSE_H

View File

@@ -0,0 +1,416 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose: Client's energy wave
//
// $Workfile: $
// $Date: $
//
//-----------------------------------------------------------------------------
// $Log: $
//
// $NoKeywords: $
//=============================================================================//
#include "cbase.h"
#include "materialsystem/imaterialsystem.h"
#include "materialsystem/imesh.h"
#include "energy_wave_effect.h"
#include "mathlib/vmatrix.h"
#include "clienteffectprecachesystem.h"
// memdbgon must be the last include file in a .cpp file!!!
#include "tier0/memdbgon.h"
CLIENTEFFECT_REGISTER_BEGIN( PrecacheEnergyWave )
CLIENTEFFECT_MATERIAL( "effects/energywave/energywave" )
CLIENTEFFECT_REGISTER_END()
//-----------------------------------------------------------------------------
// Energy Wave:
//-----------------------------------------------------------------------------
class C_EnergyWave : public C_BaseEntity
{
public:
DECLARE_CLASS( C_EnergyWave, C_BaseEntity );
DECLARE_CLIENTCLASS();
C_EnergyWave();
~C_EnergyWave();
void PostDataUpdate( DataUpdateType_t updateType );
int DrawModel( int flags );
void ComputePoint( float s, float t, Vector& pt, Vector& normal, float& opacity );
void DrawWireframeModel( );
CEnergyWaveEffect m_EWaveEffect;
IMaterial* m_pWireframe;
IMaterial* m_pEWaveMat;
private:
C_EnergyWave( const C_EnergyWave & ); // not defined, not accessible
void ComputeEWavePoints( Vector* pt, Vector* normal, float* opacity );
void DrawEWavePoints(Vector* pt, Vector* normal, float* opacity);
};
EXTERN_RECV_TABLE(DT_BaseEntity);
IMPLEMENT_CLIENTCLASS_DT(C_EnergyWave, DT_EWaveEffect, CEnergyWave)
END_RECV_TABLE()
// ----------------------------------------------------------------------------
// Functions.
// ----------------------------------------------------------------------------
C_EnergyWave::C_EnergyWave() : m_EWaveEffect(NULL, NULL)
{
m_pWireframe = materials->FindMaterial("shadertest/wireframevertexcolor", TEXTURE_GROUP_OTHER);
m_pEWaveMat = materials->FindMaterial("effects/energywave/energywave", TEXTURE_GROUP_CLIENT_EFFECTS);
m_EWaveEffect.Spawn();
}
C_EnergyWave::~C_EnergyWave()
{
}
void C_EnergyWave::PostDataUpdate( DataUpdateType_t updateType )
{
MarkMessageReceived();
// Make sure that origin points to current origin, at least
MoveToLastReceivedPosition();
}
enum
{
NUM_SUBDIVISIONS = 21,
};
static void ComputeIndices( int is, int it, int* idx )
{
int is0 = (is > 0) ? (is - 1) : is;
int it0 = (it > 0) ? (it - 1) : it;
int is1 = (is < EWAVE_NUM_HORIZONTAL_POINTS - 1) ? is + 1 : is;
int it1 = (it < EWAVE_NUM_HORIZONTAL_POINTS - 1) ? it + 1 : it;
int is2 = is + 2;
int it2 = it + 2;
if (is2 >= EWAVE_NUM_HORIZONTAL_POINTS)
is2 = EWAVE_NUM_HORIZONTAL_POINTS - 1;
if (it2 >= EWAVE_NUM_HORIZONTAL_POINTS)
it2 = EWAVE_NUM_HORIZONTAL_POINTS - 1;
idx[0] = is0 + it0 * EWAVE_NUM_HORIZONTAL_POINTS;
idx[1] = is + it0 * EWAVE_NUM_HORIZONTAL_POINTS;
idx[2] = is1 + it0 * EWAVE_NUM_HORIZONTAL_POINTS;
idx[3] = is2 + it0 * EWAVE_NUM_HORIZONTAL_POINTS;
idx[4] = is0 + it * EWAVE_NUM_HORIZONTAL_POINTS;
idx[5] = is + it * EWAVE_NUM_HORIZONTAL_POINTS;
idx[6] = is1 + it * EWAVE_NUM_HORIZONTAL_POINTS;
idx[7] = is2 + it * EWAVE_NUM_HORIZONTAL_POINTS;
idx[8] = is0 + it1 * EWAVE_NUM_HORIZONTAL_POINTS;
idx[9] = is + it1 * EWAVE_NUM_HORIZONTAL_POINTS;
idx[10] = is1 + it1 * EWAVE_NUM_HORIZONTAL_POINTS;
idx[11] = is2 + it1 * EWAVE_NUM_HORIZONTAL_POINTS;
idx[12] = is0 + it2 * EWAVE_NUM_HORIZONTAL_POINTS;
idx[13] = is + it2 * EWAVE_NUM_HORIZONTAL_POINTS;
idx[14] = is1 + it2 * EWAVE_NUM_HORIZONTAL_POINTS;
idx[15] = is2 + it2 * EWAVE_NUM_HORIZONTAL_POINTS;
}
void C_EnergyWave::ComputePoint( float s, float t, Vector& pt, Vector& normal, float& opacity )
{
int is = (int)s;
int it = (int)t;
if( is >= EWAVE_NUM_HORIZONTAL_POINTS )
is -= 1;
if( it >= EWAVE_NUM_VERTICAL_POINTS )
it -= 1;
int idx[16];
ComputeIndices( is, it, idx );
// The patch equation is:
// px = S * M * Gx * M^T * T^T
// py = S * M * Gy * M^T * T^T
// pz = S * M * Gz * M^T * T^T
// where S = [s^3 s^2 s 1], T = [t^3 t^2 t 1]
// M is the patch type matrix, in my case I'm using a catmull-rom
// G is the array of control points. rows have constant t
static VMatrix catmullRom( -0.5, 1.5, -1.5, 0.5,
1, -2.5, 2, -0.5,
-0.5, 0, 0.5, 0,
0, 1, 0, 0 );
VMatrix controlPointsX, controlPointsY, controlPointsZ, controlPointsO;
Vector pos;
for (int i = 0; i < 4; ++i)
{
for (int j = 0; j < 4; ++j)
{
const Vector& v = m_EWaveEffect.GetPoint( idx[i * 4 + j] );
controlPointsX[j][i] = v.x;
controlPointsY[j][i] = v.y;
controlPointsZ[j][i] = v.z;
controlPointsO[j][i] = m_EWaveEffect.ComputeOpacity( v, GetAbsOrigin() );
}
}
float fs = s - is;
float ft = t - it;
VMatrix temp, mgm[4];
MatrixTranspose( catmullRom, temp );
MatrixMultiply( controlPointsX, temp, mgm[0] );
MatrixMultiply( controlPointsY, temp, mgm[1] );
MatrixMultiply( controlPointsZ, temp, mgm[2] );
MatrixMultiply( controlPointsO, temp, mgm[3] );
MatrixMultiply( catmullRom, mgm[0], mgm[0] );
MatrixMultiply( catmullRom, mgm[1], mgm[1] );
MatrixMultiply( catmullRom, mgm[2], mgm[2] );
MatrixMultiply( catmullRom, mgm[3], mgm[3] );
Vector4D svec, tvec;
float ft2 = ft * ft;
tvec[0] = ft2 * ft; tvec[1] = ft2; tvec[2] = ft; tvec[3] = 1.0f;
float fs2 = fs * fs;
svec[0] = fs2 * fs; svec[1] = fs2; svec[2] = fs; svec[3] = 1.0f;
Vector4D tmp;
Vector4DMultiply( mgm[0], tvec, tmp );
pt[0] = DotProduct4D( tmp, svec );
Vector4DMultiply( mgm[1], tvec, tmp );
pt[1] = DotProduct4D( tmp, svec );
Vector4DMultiply( mgm[2], tvec, tmp );
pt[2] = DotProduct4D( tmp, svec );
Vector4DMultiply( mgm[3], tvec, tmp );
opacity = DotProduct4D( tmp, svec );
if ((s == 0.0f) || (t == 0.0f) ||
(s == (EWAVE_NUM_HORIZONTAL_POINTS-1.0f)) || (t == (EWAVE_NUM_VERTICAL_POINTS-1.0f)) )
{
opacity = 0.0f;
}
if ((s <= 0.3) || (t < 0.3))
{
opacity *= 0.35f;
}
if ((s == (EWAVE_NUM_HORIZONTAL_POINTS-0.7f)) || (t == (EWAVE_NUM_VERTICAL_POINTS-0.7f)) )
{
opacity *= 0.35f;
}
if (opacity < 0.0f)
opacity = 0.0f;
else if (opacity > 255.0f)
opacity = 255.0f;
// Normal computation
Vector4D dsvec, dtvec;
dsvec[0] = 3.0f * fs2; dsvec[1] = 2.0f * fs; dsvec[2] = 1.0f; dsvec[3] = 0.0f;
dtvec[0] = 3.0f * ft2; dtvec[1] = 2.0f * ft; dtvec[2] = 1.0f; dtvec[3] = 0.0f;
Vector ds, dt;
Vector4DMultiply( mgm[0], tvec, tmp );
ds[0] = DotProduct4D( tmp, dsvec );
Vector4DMultiply( mgm[1], tvec, tmp );
ds[1] = DotProduct4D( tmp, dsvec );
Vector4DMultiply( mgm[2], tvec, tmp );
ds[2] = DotProduct4D( tmp, dsvec );
Vector4DMultiply( mgm[0], dtvec, tmp );
dt[0] = DotProduct4D( tmp, svec );
Vector4DMultiply( mgm[1], dtvec, tmp );
dt[1] = DotProduct4D( tmp, svec );
Vector4DMultiply( mgm[2], dtvec, tmp );
dt[2] = DotProduct4D( tmp, svec );
CrossProduct( ds, dt, normal );
VectorNormalize( normal );
}
void C_EnergyWave::DrawWireframeModel( )
{
IMesh* pMesh = materials->GetDynamicMesh( true, NULL, NULL, m_pWireframe );
int numLines = (EWAVE_NUM_VERTICAL_POINTS - 1) * EWAVE_NUM_HORIZONTAL_POINTS +
EWAVE_NUM_VERTICAL_POINTS * (EWAVE_NUM_HORIZONTAL_POINTS - 1);
CMeshBuilder meshBuilder;
meshBuilder.Begin( pMesh, MATERIAL_LINES, numLines );
Vector tmp;
for (int i = 0; i < EWAVE_NUM_VERTICAL_POINTS; ++i)
{
for (int j = 0; j < EWAVE_NUM_HORIZONTAL_POINTS; ++j)
{
if ( i > 0 )
{
meshBuilder.Position3fv( m_EWaveEffect.GetPoint( j, i ).Base() );
meshBuilder.Color4ub( 255, 255, 255, 128 );
meshBuilder.AdvanceVertex();
meshBuilder.Position3fv( m_EWaveEffect.GetPoint( j, i - 1 ).Base() );
meshBuilder.Color4ub( 255, 255, 255, 128 );
meshBuilder.AdvanceVertex();
}
if (j > 0)
{
meshBuilder.Position3fv( m_EWaveEffect.GetPoint( j, i ).Base() );
meshBuilder.Color4ub( 255, 255, 255, 128 );
meshBuilder.AdvanceVertex();
meshBuilder.Position3fv( m_EWaveEffect.GetPoint( j - 1, i ).Base() );
meshBuilder.Color4ub( 255, 255, 255, 128 );
meshBuilder.AdvanceVertex();
}
}
}
meshBuilder.End();
pMesh->Draw();
}
//-----------------------------------------------------------------------------
// Compute the ewave points using catmull-rom
//-----------------------------------------------------------------------------
void C_EnergyWave::ComputeEWavePoints( Vector* pt, Vector* normal, float* opacity )
{
int i;
for ( i = 0; i < NUM_SUBDIVISIONS; ++i)
{
float t = (EWAVE_NUM_VERTICAL_POINTS -1 ) * (float)i / (float)(NUM_SUBDIVISIONS - 1);
for (int j = 0; j < NUM_SUBDIVISIONS; ++j)
{
float s = (EWAVE_NUM_HORIZONTAL_POINTS-1) * (float)j / (float)(NUM_SUBDIVISIONS - 1);
int idx = i * NUM_SUBDIVISIONS + j;
ComputePoint( s, t, pt[idx], normal[idx], opacity[idx] );
}
}
}
//-----------------------------------------------------------------------------
// Draws the base ewave
//-----------------------------------------------------------------------------
#define TRANSITION_REGION_WIDTH 0.5f
void C_EnergyWave::DrawEWavePoints(Vector* pt, Vector* normal, float* opacity)
{
IMesh* pMesh = materials->GetDynamicMesh( true, NULL, NULL, m_pEWaveMat );
int numTriangles = (NUM_SUBDIVISIONS - 1) * (NUM_SUBDIVISIONS - 1) * 2;
CMeshBuilder meshBuilder;
meshBuilder.Begin( pMesh, MATERIAL_TRIANGLES, numTriangles );
float du = 1.0f / (float)(NUM_SUBDIVISIONS - 1);
float dv = du;
unsigned char color[3];
color[0] = 255;
color[1] = 255;
color[2] = 255;
for ( int i = 0; i < NUM_SUBDIVISIONS - 1; ++i)
{
float v = i * dv;
for (int j = 0; j < NUM_SUBDIVISIONS - 1; ++j)
{
int idx = i * NUM_SUBDIVISIONS + j;
float u = j * du;
meshBuilder.Position3fv( pt[idx].Base() );
meshBuilder.Color4ub( color[0], color[1], color[2], opacity[idx] );
meshBuilder.Normal3fv( normal[idx].Base() );
meshBuilder.TexCoord2f( 0, u, v );
meshBuilder.AdvanceVertex();
meshBuilder.Position3fv( pt[idx + NUM_SUBDIVISIONS].Base() );
meshBuilder.Color4ub( color[0], color[1], color[2], opacity[idx+NUM_SUBDIVISIONS] );
meshBuilder.Normal3fv( normal[idx + NUM_SUBDIVISIONS].Base() );
meshBuilder.TexCoord2f( 0, u, v + dv );
meshBuilder.AdvanceVertex();
meshBuilder.Position3fv( pt[idx + 1].Base() );
meshBuilder.Color4ub( color[0], color[1], color[2], opacity[idx+1] );
meshBuilder.Normal3fv( normal[idx+1].Base() );
meshBuilder.TexCoord2f( 0, u + du, v );
meshBuilder.AdvanceVertex();
meshBuilder.Position3fv( pt[idx + 1].Base() );
meshBuilder.Color4ub( color[0], color[1], color[2], opacity[idx+1] );
meshBuilder.Normal3fv( normal[idx+1].Base() );
meshBuilder.TexCoord2f( 0, u + du, v );
meshBuilder.AdvanceVertex();
meshBuilder.Position3fv( pt[idx + NUM_SUBDIVISIONS].Base() );
meshBuilder.Color4ub( color[0], color[1], color[2], opacity[idx+NUM_SUBDIVISIONS] );
meshBuilder.Normal3fv( normal[idx + NUM_SUBDIVISIONS].Base() );
meshBuilder.TexCoord2f( 0, u, v + dv );
meshBuilder.AdvanceVertex();
meshBuilder.Position3fv( pt[idx + NUM_SUBDIVISIONS + 1].Base() );
meshBuilder.Color4ub( color[0], color[1], color[2], opacity[idx+NUM_SUBDIVISIONS+1] );
meshBuilder.Normal3fv( normal[idx + NUM_SUBDIVISIONS + 1].Base() );
meshBuilder.TexCoord2f( 0, u + du, v + dv );
meshBuilder.AdvanceVertex();
}
}
meshBuilder.End();
pMesh->Draw();
}
//-----------------------------------------------------------------------------
// Main draw entry point
//-----------------------------------------------------------------------------
int C_EnergyWave::DrawModel( int flags )
{
if ( !m_bReadyToDraw )
return 0;
// NOTE: We've got a stiff spring case here, we need to simulate at
// a fairly fast timestep. A better solution would be to use an
// implicit method, which I'm going to not implement for the moment
float dt = gpGlobals->frametime;
m_EWaveEffect.SetPosition( GetAbsOrigin(), GetAbsAngles() );
m_EWaveEffect.Simulate(dt);
Vector pt[NUM_SUBDIVISIONS * NUM_SUBDIVISIONS];
Vector normal[NUM_SUBDIVISIONS * NUM_SUBDIVISIONS];
float opacity[NUM_SUBDIVISIONS * NUM_SUBDIVISIONS];
ComputeEWavePoints( pt, normal, opacity );
DrawEWavePoints( pt, normal, opacity );
return 1;
}

View File

@@ -0,0 +1,486 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
//=============================================================================//
#include "cbase.h"
#include "particles_simple.h"
#include "citadel_effects_shared.h"
#include "particles_attractor.h"
class C_AlyxEmpEffect : public C_BaseEntity
{
DECLARE_CLASS( C_AlyxEmpEffect, C_BaseEntity );
DECLARE_CLIENTCLASS();
public:
void OnDataChanged( DataUpdateType_t updateType );
RenderGroup_t GetRenderGroup( void );
void ClientThink( void );
void NotifyShouldTransmit( ShouldTransmitState_t state );
void UpdateIdle( float percentage );
void UpdateCharging( float percentage );
void UpdateDischarging( void );
private:
bool SetupEmitters( void );
inline float GetStateDurationPercentage( void );
int m_nState;
float m_flDuration;
float m_flStartTime;
TimedEvent m_tParticleSpawn;
CSmartPtr<CSimpleEmitter> m_pSimpleEmitter;
CSmartPtr<CParticleAttractor> m_pAttractorEmitter;
};
IMPLEMENT_CLIENTCLASS_DT( C_AlyxEmpEffect, DT_AlyxEmpEffect, CAlyxEmpEffect )
RecvPropInt( RECVINFO(m_nState) ),
RecvPropFloat( RECVINFO(m_flDuration) ),
RecvPropFloat( RECVINFO(m_flStartTime) ),
END_RECV_TABLE()
//-----------------------------------------------------------------------------
// Purpose:
// Output : RenderGroup_t
//-----------------------------------------------------------------------------
RenderGroup_t C_AlyxEmpEffect::GetRenderGroup( void )
{
return RENDER_GROUP_TRANSLUCENT_ENTITY;
}
//-----------------------------------------------------------------------------
// Purpose:
// Input : updateType -
//-----------------------------------------------------------------------------
void C_AlyxEmpEffect::OnDataChanged( DataUpdateType_t updateType )
{
BaseClass::OnDataChanged( updateType );
if ( updateType == DATA_UPDATE_CREATED )
{
m_tParticleSpawn.Init( 32 );
SetNextClientThink( CLIENT_THINK_ALWAYS );
SetupEmitters();
}
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
bool C_AlyxEmpEffect::SetupEmitters( void )
{
// Setup the basic core emitter
if ( m_pSimpleEmitter.IsValid() == false )
{
m_pSimpleEmitter = CSimpleEmitter::Create( "energycore" );
if ( m_pSimpleEmitter.IsValid() == false )
return false;
}
// Setup the attractor emitter
if ( m_pAttractorEmitter.IsValid() == false )
{
m_pAttractorEmitter = CParticleAttractor::Create( GetAbsOrigin(), "energyattractor" );
if ( m_pAttractorEmitter.IsValid() == false )
return false;
}
return true;
}
#define EMP_SCALE 0.5f
#define EMP_PARTICLES "effects/ar2_altfire1b"
//-----------------------------------------------------------------------------
// Purpose:
// Input : percentage -
//-----------------------------------------------------------------------------
void C_AlyxEmpEffect::UpdateIdle( float percentage )
{
#if 0
// Must be active
if ( percentage >= 1.0f )
return;
// Emitters must be valid
if ( SetupEmitters() == false )
return;
// Reset our sort origin
m_pSimpleEmitter->SetSortOrigin( GetAbsOrigin() );
SimpleParticle *sParticle;
// Do the charging particles
m_pAttractorEmitter->SetAttractorOrigin( GetAbsOrigin() );
Vector forward, right, up;
AngleVectors( GetAbsAngles(), &forward, &right, &up );
Vector offset;
float dist;
int numParticles = floor( 4.0f * percentage );
float dTime = gpGlobals->frametime;
while ( m_tParticleSpawn.NextEvent( dTime ) )
{
for ( int i = 0; i < numParticles; i++ )
{
dist = random->RandomFloat( 4.0f * EMP_SCALE * percentage, 64.0f * EMP_SCALE * percentage );
offset = forward * dist;
dist = RemapValClamped( dist, 4.0f * EMP_SCALE * percentage, 64.0f * EMP_SCALE * percentage, 6.0f, 1.0f );
offset += right * random->RandomFloat( -4.0f * EMP_SCALE * dist, 4.0f * EMP_SCALE * dist );
offset += up * random->RandomFloat( -4.0f * EMP_SCALE * dist, 4.0f * EMP_SCALE * dist );
offset += GetAbsOrigin();
sParticle = (SimpleParticle *) m_pAttractorEmitter->AddParticle( sizeof(SimpleParticle), m_pAttractorEmitter->GetPMaterial( EMP_PARTICLES ), 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 = 0.0f;
float alpha = 255 * percentage;
sParticle->m_uchColor[0] = alpha;
sParticle->m_uchColor[1] = alpha;
sParticle->m_uchColor[2] = alpha;
sParticle->m_uchStartAlpha = alpha;
sParticle->m_uchEndAlpha = 0;
sParticle->m_uchStartSize = random->RandomFloat( 1, 2 );
sParticle->m_uchEndSize = 0;
}
}
#endif
}
//-----------------------------------------------------------------------------
// Purpose:
// Input : percentage -
//-----------------------------------------------------------------------------
void C_AlyxEmpEffect::UpdateCharging( float percentage )
{
// Emitters must be valid
if ( SetupEmitters() == false )
return;
if ( percentage <= 0.0f )
return;
// Reset our sort origin
m_pSimpleEmitter->SetSortOrigin( GetAbsOrigin() );
float flScale = 4.0f * EMP_SCALE * percentage;
SimpleParticle *sParticle;
float dTime = gpGlobals->frametime;
while ( m_tParticleSpawn.NextEvent( dTime ) )
{
// Do the core effects
sParticle = (SimpleParticle *) m_pSimpleEmitter->AddParticle( sizeof(SimpleParticle), m_pSimpleEmitter->GetPMaterial( EMP_PARTICLES ), GetAbsOrigin() );
if ( sParticle == NULL )
return;
sParticle->m_vecVelocity = vec3_origin;
sParticle->m_flDieTime = 0.1f;
sParticle->m_flLifetime = 0.0f;
sParticle->m_flRoll = Helper_RandomInt( 0, 360 );
sParticle->m_flRollDelta = 0.0f;
float alpha = 255 * percentage;
sParticle->m_uchColor[0] = alpha;
sParticle->m_uchColor[1] = alpha;
sParticle->m_uchColor[2] = alpha;
sParticle->m_uchStartAlpha = alpha;
sParticle->m_uchEndAlpha = 0;
sParticle->m_uchStartSize = flScale;
sParticle->m_uchEndSize = sParticle->m_uchStartSize * 2.0f;
}
#if 0
// Do the charging particles
m_pAttractorEmitter->SetAttractorOrigin( GetAbsOrigin() );
Vector forward, right, up;
AngleVectors( GetAbsAngles(), &forward, &right, &up );
Vector offset;
float dist;
int numParticles = floor( 4.0f * percentage );
for ( i = 0; i < numParticles; i++ )
{
dist = random->RandomFloat( 4.0f * percentage, 64.0f * percentage );
offset = forward * dist;
dist = RemapValClamped( dist, 4.0f * percentage, 64.0f * percentage, 6.0f, 1.0f );
offset += right * random->RandomFloat( -4.0f * dist, 4.0f * dist );
offset += up * random->RandomFloat( -4.0f * dist, 4.0f * dist );
offset += GetAbsOrigin();
sParticle = (SimpleParticle *) m_pAttractorEmitter->AddParticle( sizeof(SimpleParticle), m_pAttractorEmitter->GetPMaterial( EMP_PARTICLES ), 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 = 0.0f;
float alpha = 255 * percentage;
sParticle->m_uchColor[0] = alpha;
sParticle->m_uchColor[1] = alpha;
sParticle->m_uchColor[2] = alpha;
sParticle->m_uchStartAlpha = alpha;
sParticle->m_uchEndAlpha = 0;
sParticle->m_uchStartSize = random->RandomFloat( 1, 2 );
sParticle->m_uchEndSize = 0;
}
#endif
}
//-----------------------------------------------------------------------------
// Purpose:
// Input : percentage -
//-----------------------------------------------------------------------------
void C_AlyxEmpEffect::UpdateDischarging( void )
{
// Emitters must be valid
if ( SetupEmitters() == false )
return;
// Reset our sort origin
m_pSimpleEmitter->SetSortOrigin( GetAbsOrigin() );
float flScale = EMP_SCALE * 8.0f;
Vector forward, right, up;
AngleVectors( GetAbsAngles(), &forward, &right, &up );
SimpleParticle *sParticle;
float dTime = gpGlobals->frametime;
while ( m_tParticleSpawn.NextEvent( dTime ) )
{
// Base of the core effect
sParticle = (SimpleParticle *) m_pSimpleEmitter->AddParticle( sizeof(SimpleParticle), m_pSimpleEmitter->GetPMaterial( EMP_PARTICLES ), GetAbsOrigin() );
if ( sParticle == NULL )
return;
sParticle->m_vecVelocity = vec3_origin;
sParticle->m_flDieTime = 0.25f;
sParticle->m_flLifetime = 0.0f;
sParticle->m_flRoll = Helper_RandomInt( 0, 360 );
sParticle->m_flRollDelta = 0.0f;
float alpha = 64;
sParticle->m_uchColor[0] = alpha;
sParticle->m_uchColor[1] = alpha;
sParticle->m_uchColor[2] = alpha;
sParticle->m_uchStartAlpha = alpha;
sParticle->m_uchEndAlpha = 0;
sParticle->m_uchStartSize = flScale * 4.0f;
sParticle->m_uchEndSize = 0.0f;
// Base of the core effect
sParticle = (SimpleParticle *) m_pSimpleEmitter->AddParticle( sizeof(SimpleParticle), m_pSimpleEmitter->GetPMaterial( EMP_PARTICLES ), GetAbsOrigin() );
if ( sParticle == NULL )
return;
sParticle->m_vecVelocity = vec3_origin;
sParticle->m_flDieTime = 0.1f;
sParticle->m_flLifetime = 0.0f;
sParticle->m_flRoll = Helper_RandomInt( 0, 360 );
sParticle->m_flRollDelta = 0.0f;
alpha = 128;
sParticle->m_uchColor[0] = alpha;
sParticle->m_uchColor[1] = alpha;
sParticle->m_uchColor[2] = alpha;
sParticle->m_uchStartAlpha = alpha;
sParticle->m_uchEndAlpha = 0;
sParticle->m_uchStartSize = 0.0f;
sParticle->m_uchEndSize = flScale * 2.0f;
// Make sure we encompass the complete particle here!
m_pSimpleEmitter->SetParticleCullRadius( sParticle->m_uchEndSize );
// Do the core effects
sParticle = (SimpleParticle *) m_pSimpleEmitter->AddParticle( sizeof(SimpleParticle), m_pSimpleEmitter->GetPMaterial( EMP_PARTICLES ), GetAbsOrigin() );
if ( sParticle == NULL )
return;
sParticle->m_vecVelocity = RandomVector( -32.0f, 32.0f );
sParticle->m_flDieTime = 0.2f;
sParticle->m_flLifetime = 0.0f;
sParticle->m_flRoll = Helper_RandomInt( 0, 360 );
sParticle->m_flRollDelta = 0.0f;
alpha = 255;
sParticle->m_uchColor[0] = alpha;
sParticle->m_uchColor[1] = alpha;
sParticle->m_uchColor[2] = alpha;
sParticle->m_uchStartAlpha = alpha;
sParticle->m_uchEndAlpha = 0;
sParticle->m_uchStartSize = flScale;
sParticle->m_uchEndSize = 0.0f;
}
#if 0
// Do the charging particles
m_pAttractorEmitter->SetAttractorOrigin( GetAbsOrigin() );
Vector offset;
float dist;
for ( i = 0; i < 4; i++ )
{
dist = random->RandomFloat( 4.0f, 64.0f );
offset = forward * dist;
dist = RemapValClamped( dist, 4.0f, 64.0f, 6.0f, 1.0f );
offset += right * random->RandomFloat( -2.0f * dist, 2.0f * dist );
offset += up * random->RandomFloat( -2.0f * dist, 2.0f * dist );
offset += GetAbsOrigin();
sParticle = (SimpleParticle *) m_pAttractorEmitter->AddParticle( sizeof(SimpleParticle), m_pAttractorEmitter->GetPMaterial( "effects/combinemuzzle2_dark" ), offset );
if ( sParticle == NULL )
return;
sParticle->m_vecVelocity = Vector(0,0,2);
sParticle->m_flDieTime = 0.5f;
sParticle->m_flLifetime = 0.0f;
sParticle->m_flRoll = Helper_RandomInt( 0, 360 );
sParticle->m_flRollDelta = 0.0f;
float alpha = 255;
sParticle->m_uchColor[0] = alpha;
sParticle->m_uchColor[1] = alpha;
sParticle->m_uchColor[2] = alpha;
sParticle->m_uchStartAlpha = alpha;
sParticle->m_uchEndAlpha = 0;
sParticle->m_uchStartSize = 1;
sParticle->m_uchEndSize = 0;
}
#endif
}
//-----------------------------------------------------------------------------
// Purpose:
// Output : inline float
//-----------------------------------------------------------------------------
inline float C_AlyxEmpEffect::GetStateDurationPercentage( void )
{
if ( m_flDuration == 0 )
return 0.0f;
return RemapValClamped( ( gpGlobals->curtime - m_flStartTime ), 0, m_flDuration, 0, 1.0f );;
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void C_AlyxEmpEffect::NotifyShouldTransmit( ShouldTransmitState_t state )
{
BaseClass::NotifyShouldTransmit( state );
// Turn off
if ( state == SHOULDTRANSMIT_END )
{
SetNextClientThink( CLIENT_THINK_NEVER );
}
// Turn on
if ( state == SHOULDTRANSMIT_START )
{
SetNextClientThink( CLIENT_THINK_ALWAYS );
}
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void C_AlyxEmpEffect::ClientThink( void )
{
if ( gpGlobals->frametime <= 0.0f )
return;
float flDuration = GetStateDurationPercentage();
switch( m_nState )
{
case ENERGYCORE_STATE_OFF:
UpdateIdle( 1.0f - flDuration );
break;
case ENERGYCORE_STATE_CHARGING:
UpdateCharging( flDuration );
break;
case ENERGYCORE_STATE_DISCHARGING:
UpdateDischarging( );
break;
}
}

View File

@@ -0,0 +1,97 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
// $NoKeywords: $
//=============================================================================//
#include "cbase.h"
#include "fx_explosion.h"
#include "tempentity.h"
#include "c_tracer.h"
#include "env_headcrabcanister_shared.h"
#include "baseparticleentity.h"
// memdbgon must be the last include file in a .cpp file!!!
#include "tier0/memdbgon.h"
//-----------------------------------------------------------------------------
// Headcrab canister Class (Client-side only!)
//-----------------------------------------------------------------------------
class C_EnvHeadcrabCanister : public C_BaseAnimating
{
DECLARE_CLASS( C_EnvHeadcrabCanister, C_BaseAnimating );
DECLARE_CLIENTCLASS();
public:
//-------------------------------------------------------------------------
// Initialization/Destruction
//-------------------------------------------------------------------------
C_EnvHeadcrabCanister();
~C_EnvHeadcrabCanister();
virtual void OnDataChanged( DataUpdateType_t updateType );
virtual void ClientThink();
private:
C_EnvHeadcrabCanister( const C_EnvHeadcrabCanister & );
CEnvHeadcrabCanisterShared m_Shared;
CNetworkVar( bool, m_bLanded );
};
EXTERN_RECV_TABLE(DT_EnvHeadcrabCanisterShared);
IMPLEMENT_CLIENTCLASS_DT( C_EnvHeadcrabCanister, DT_EnvHeadcrabCanister, CEnvHeadcrabCanister )
RecvPropDataTable( RECVINFO_DT( m_Shared ), 0, &REFERENCE_RECV_TABLE(DT_EnvHeadcrabCanisterShared) ),
RecvPropBool( RECVINFO( m_bLanded ) ),
END_RECV_TABLE()
//-----------------------------------------------------------------------------
// Constructor
//-----------------------------------------------------------------------------
C_EnvHeadcrabCanister::C_EnvHeadcrabCanister()
{
}
//-----------------------------------------------------------------------------
// Destructor
//-----------------------------------------------------------------------------
C_EnvHeadcrabCanister::~C_EnvHeadcrabCanister()
{
}
//-----------------------------------------------------------------------------
// On data update
//-----------------------------------------------------------------------------
void C_EnvHeadcrabCanister::OnDataChanged( DataUpdateType_t updateType )
{
BaseClass::OnDataChanged( updateType );
if ( updateType == DATA_UPDATE_CREATED )
{
SetNextClientThink( CLIENT_THINK_ALWAYS );
}
// Stop client-side simulation on landing
if ( m_bLanded )
{
SetNextClientThink( CLIENT_THINK_NEVER );
}
}
//-----------------------------------------------------------------------------
// Compute position
//-----------------------------------------------------------------------------
void C_EnvHeadcrabCanister::ClientThink()
{
Vector vecEndPosition;
QAngle vecEndAngles;
m_Shared.GetPositionAtTime( gpGlobals->curtime, vecEndPosition, vecEndAngles );
SetAbsOrigin( vecEndPosition );
SetAbsAngles( vecEndAngles );
}

View File

@@ -0,0 +1,137 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
// $NoKeywords: $
//=============================================================================//
#include "cbase.h"
#include "engine/IEngineTrace.h"
#include "fx_sparks.h"
#include "particles_ez.h"
#include "view.h"
// memdbgon must be the last include file in a .cpp file!!!
#include "tier0/memdbgon.h"
ConVar cl_starfield_diameter( "cl_starfield_diameter", "128.0", FCVAR_NONE );
ConVar cl_starfield_distance( "cl_starfield_distance", "256.0", FCVAR_NONE );
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
class C_EnvStarfield : public C_BaseEntity
{
DECLARE_CLASS( C_EnvStarfield, C_BaseEntity );
public:
DECLARE_CLIENTCLASS();
C_EnvStarfield();
virtual void OnDataChanged( DataUpdateType_t updateType );
virtual void ClientThink( void );
private:
// Emitter
CSmartPtr<CTrailParticles> m_pEmitter;
bool m_bOn;
float m_flDensity;
float m_flNumParticles;
private:
C_EnvStarfield( const C_EnvStarfield & );
};
IMPLEMENT_CLIENTCLASS_DT( C_EnvStarfield, DT_EnvStarfield, CEnvStarfield )
RecvPropInt( RECVINFO(m_bOn) ),
RecvPropFloat( RECVINFO(m_flDensity) ),
END_RECV_TABLE()
// ------------------------------------------------------------------------- //
// C_EnvStarfield
// ------------------------------------------------------------------------- //
C_EnvStarfield::C_EnvStarfield()
{
m_bOn = false;
m_flDensity = 1.0;
m_flNumParticles = 0;
}
//-----------------------------------------------------------------------------
// Purpose:
// Input : updateType -
//-----------------------------------------------------------------------------
void C_EnvStarfield::OnDataChanged( DataUpdateType_t updateType )
{
if ( updateType == DATA_UPDATE_CREATED )
{
m_pEmitter = CTrailParticles::Create( "EnvStarfield" );
Vector vecCenter = MainViewOrigin() + (MainViewForward() * cl_starfield_distance.GetFloat() );
m_pEmitter->Setup( (Vector &) vecCenter,
NULL,
0.0,
0,
64,
0,
0,
bitsPARTICLE_TRAIL_VELOCITY_DAMPEN | bitsPARTICLE_TRAIL_FADE | bitsPARTICLE_TRAIL_FADE_IN );
// Start thinking
SetNextClientThink( CLIENT_THINK_ALWAYS );
}
BaseClass::OnDataChanged( updateType );
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void C_EnvStarfield::ClientThink( void )
{
if ( !m_bOn || !m_flDensity )
return;
#ifdef MAPBASE
if ( engine->IsPaused() )
return;
#endif
PMaterialHandle hParticleMaterial = m_pEmitter->GetPMaterial( "effects/spark_noz" );
// Find a start & end point for the particle
// Start particles straight ahead of the client
Vector vecViewOrigin = MainViewOrigin();
// Determine the number of particles
m_flNumParticles += 1.0 * (m_flDensity);
int iNumParticles = floor(m_flNumParticles);
m_flNumParticles -= iNumParticles;
// Add particles
for ( int i = 0; i < iNumParticles; i++ )
{
float flDiameter = cl_starfield_diameter.GetFloat();
Vector vecStart = vecViewOrigin + (MainViewForward() * cl_starfield_distance.GetFloat() );
Vector vecEnd = vecViewOrigin + (MainViewRight() * RandomFloat(-flDiameter,flDiameter)) + (MainViewUp() * RandomFloat(-flDiameter,flDiameter));
Vector vecDir = (vecEnd - vecStart);
float flDistance = VectorNormalize( vecDir );
float flTravelTime = 2.0;
// Start a random amount along the path
vecStart += vecDir * ( RandomFloat(0.1,0.3) * flDistance );
TrailParticle *pParticle = (TrailParticle *) m_pEmitter->AddParticle( sizeof(TrailParticle), hParticleMaterial, vecStart );
if ( pParticle )
{
pParticle->m_vecVelocity = vecDir * (flDistance / flTravelTime);
pParticle->m_flDieTime = flTravelTime;
pParticle->m_flLifetime = 0;
pParticle->m_flWidth = RandomFloat( 1, 3 );
pParticle->m_flLength = RandomFloat( 0.05, 0.4 );
pParticle->m_color.r = 255;
pParticle->m_color.g = 255;
pParticle->m_color.b = 255;
pParticle->m_color.a = 255;
}
}
}

View File

@@ -0,0 +1,413 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
// $NoKeywords: $
//=============================================================================//
#include "cbase.h"
#include "particles_simple.h"
#include "baseparticleentity.h"
#include "iefx.h"
#include "decals.h"
#include "beamdraw.h"
#include "hud.h"
#include "clienteffectprecachesystem.h"
// memdbgon must be the last include file in a .cpp file!!!
#include "tier0/memdbgon.h"
CLIENTEFFECT_REGISTER_BEGIN( PrecacheExtinguisher )
CLIENTEFFECT_MATERIAL( "particle/particle_smokegrenade" )
CLIENTEFFECT_REGISTER_END()
class C_ExtinguisherJet : public C_BaseEntity
{
public:
DECLARE_CLIENTCLASS();
DECLARE_CLASS( C_ExtinguisherJet, C_BaseEntity );
C_ExtinguisherJet();
~C_ExtinguisherJet();
void OnDataChanged( DataUpdateType_t updateType );
void Update( float fTimeDelta );
void Start( void );
int DrawModel( int flags );
bool ShouldDraw( void ) { return m_bEmit; }
protected:
void AddExtinguisherDecal( trace_t &tr );
bool m_bEmit;
bool m_bUseMuzzlePoint;
int m_nLength;
int m_nSize;
PMaterialHandle m_MaterialHandle;
PMaterialHandle m_EmberMaterialHandle;
TimedEvent m_ParticleSpawn;
CSmartPtr<CSimpleEmitter> m_pEmitter;
CSmartPtr<CEmberEffect> m_pEmberEmitter;
private:
C_ExtinguisherJet( const C_ExtinguisherJet & );
};
//Datatable
IMPLEMENT_CLIENTCLASS_DT( C_ExtinguisherJet, DT_ExtinguisherJet, CExtinguisherJet )
RecvPropInt(RECVINFO(m_bEmit), 0),
RecvPropInt(RECVINFO(m_bUseMuzzlePoint), 0),
RecvPropInt(RECVINFO(m_nLength), 0),
RecvPropInt(RECVINFO(m_nSize), 0),
END_RECV_TABLE()
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
C_ExtinguisherJet::C_ExtinguisherJet( void )
{
m_bEmit = false;
m_pEmitter = NULL;
m_pEmberEmitter = NULL;
}
C_ExtinguisherJet::~C_ExtinguisherJet( void )
{
}
//-----------------------------------------------------------------------------
// Purpose:
// Input : bnewentity -
//-----------------------------------------------------------------------------
void C_ExtinguisherJet::OnDataChanged( DataUpdateType_t updateType )
{
C_BaseEntity::OnDataChanged(updateType);
if( updateType == DATA_UPDATE_CREATED )
{
Start();
}
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void C_ExtinguisherJet::Start( void )
{
AddToLeafSystem( RENDER_GROUP_TRANSLUCENT_ENTITY );
m_ParticleSpawn.Init( 100 ); //Events per second
//Create the basic emitter
m_pEmitter = CSimpleEmitter::Create("C_ExtinguisherJet::m_pEmitter");
Assert( m_pEmitter.IsValid() );
if ( m_pEmitter.IsValid() )
{
m_MaterialHandle = g_Mat_DustPuff[0];
m_pEmitter->SetSortOrigin( GetAbsOrigin() );
}
//Create the "ember" emitter for the smaller flecks
m_pEmberEmitter = CEmberEffect::Create( "C_ExtinguisherJet::m_pEmberEmitter" );
Assert( m_pEmberEmitter.IsValid() );
if ( m_pEmberEmitter.IsValid() )
{
m_EmberMaterialHandle = g_Mat_DustPuff[0];
m_pEmberEmitter->SetSortOrigin( GetAbsOrigin() );
}
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void C_ExtinguisherJet::AddExtinguisherDecal( trace_t &tr )
{
C_BaseEntity *ent = cl_entitylist->GetEnt( 0 );
if ( ent != NULL )
{
int index = decalsystem->GetDecalIndexForName( "Extinguish" );
if ( index >= 0 )
{
Vector endpos;
endpos.Random( -24.0f, 24.0f );
endpos += tr.endpos;
effects->DecalShoot( index, 0, ent->GetModel(), ent->GetAbsOrigin(), ent->GetAbsAngles(), endpos, 0, 0 );
}
}
}
//-----------------------------------------------------------------------------
// Purpose:
// Input : fTimeDelta -
//-----------------------------------------------------------------------------
void C_ExtinguisherJet::Update( float fTimeDelta )
{
if ( m_bEmit == false )
return;
C_BasePlayer *player = C_BasePlayer::GetLocalPlayer();
if ( m_bUseMuzzlePoint )
{
C_BaseViewModel *vm = player ? player->GetViewModel( 0 ) : NULL;
if ( vm )
{
int iAttachment = vm->LookupAttachment( "muzzle" );
Vector origin;
QAngle angles;
vm->GetAttachment( iAttachment, origin, angles );
Assert( !GetMoveParent() );
SetLocalOrigin( origin );
SetLocalAngles( angles );
}
}
trace_t tr;
Vector shotDir, vRight, vUp;
AngleVectors( GetAbsAngles(), &shotDir, &vRight, &vUp );
//FIXME: Muzzle point is incorrect on the model!
if ( m_bUseMuzzlePoint )
{
shotDir.Negate();
}
Vector endPoint = GetAbsOrigin() + ( shotDir * 150.0f );
UTIL_TraceLine( GetAbsOrigin(), endPoint, MASK_SHOT, NULL, COLLISION_GROUP_NONE, &tr );
bool hitWall = ( tr.fraction < 1.0f );
//Add normal jet
if ( m_pEmitter.IsValid() )
{
SimpleParticle *pParticle;
m_pEmitter->SetSortOrigin( GetAbsOrigin() );
float tempDelta = fTimeDelta;
//FIXME: All particles need to be within this loop
while( m_ParticleSpawn.NextEvent( tempDelta ) )
{
pParticle = (SimpleParticle *) m_pEmitter->AddParticle( sizeof(SimpleParticle), m_MaterialHandle, GetAbsOrigin() );
if ( pParticle )
{
pParticle->m_flDieTime = 0.2f;
pParticle->m_flLifetime = 0.0f;
pParticle->m_flRoll = random->RandomInt( 0, 360 );
pParticle->m_flRollDelta= random->RandomFloat( -4.0f, 4.0f );
pParticle->m_uchStartSize = 1;
pParticle->m_uchEndSize = random->RandomInt( 32, 48 );
pParticle->m_uchStartAlpha = random->RandomInt( 128, 164 );
pParticle->m_uchEndAlpha = 0;
int cScale = random->RandomInt( 192, 255 );
pParticle->m_uchColor[0] = cScale;
pParticle->m_uchColor[1] = cScale;
pParticle->m_uchColor[2] = cScale;
Vector dir;
QAngle ofsAngles;
ofsAngles.Random( -8.0f, 8.0f );
ofsAngles += GetAbsAngles();
AngleVectors( ofsAngles, &dir );
if ( m_bUseMuzzlePoint )
{
dir.Negate();
}
pParticle->m_vecVelocity = dir * random->RandomInt( 400, 800 );
}
//Add muzzle effect
pParticle = (SimpleParticle *) m_pEmitter->AddParticle( sizeof(SimpleParticle), m_MaterialHandle, GetAbsOrigin() );
if ( pParticle )
{
pParticle->m_flDieTime = 0.1f;
pParticle->m_flLifetime = 0.0f;
pParticle->m_flRoll = random->RandomInt( 0, 360 );
pParticle->m_flRollDelta= random->RandomFloat( -4.0f, 4.0f );
pParticle->m_uchStartSize = 1;
pParticle->m_uchEndSize = random->RandomInt( 8, 16 );
pParticle->m_uchStartAlpha = random->RandomInt( 128, 255 );
pParticle->m_uchEndAlpha = 0;
int cScale = random->RandomInt( 192, 255 );
pParticle->m_uchColor[0] = cScale;
pParticle->m_uchColor[1] = cScale;
pParticle->m_uchColor[2] = cScale;
Vector dir;
QAngle ofsAngles;
ofsAngles.Random( -64.0f, 64.0f );
ofsAngles += GetAbsAngles();
AngleVectors( ofsAngles, &dir );
if ( m_bUseMuzzlePoint )
{
dir.Negate();
}
pParticle->m_vecVelocity = dir * random->RandomInt( 32, 64 );
}
//Add a wall effect if needed
if ( hitWall )
{
AddExtinguisherDecal( tr );
Vector offDir;
offDir.Random( -16.0f, 16.0f );
pParticle = (SimpleParticle *) m_pEmitter->AddParticle( sizeof(SimpleParticle), m_MaterialHandle, ( tr.endpos + ( tr.plane.normal * 8.0f ) ) + offDir );
if ( pParticle )
{
pParticle->m_flDieTime = 0.4f;
pParticle->m_flLifetime = 0.0f;
pParticle->m_flRoll = random->RandomInt( 0, 360 );
pParticle->m_flRollDelta= random->RandomFloat( -2.0f, 2.0f );
pParticle->m_uchStartSize = random->RandomInt( 8, 16 );
pParticle->m_uchEndSize = random->RandomInt( 24, 32 );
pParticle->m_uchStartAlpha = random->RandomInt( 64, 128 );
pParticle->m_uchEndAlpha = 0;
int cScale = random->RandomInt( 192, 255 );
pParticle->m_uchColor[0] = cScale;
pParticle->m_uchColor[1] = cScale;
pParticle->m_uchColor[2] = cScale;
Vector rDir;
rDir = tr.plane.normal;
rDir[0] += random->RandomFloat( -0.9f, 0.9f );
rDir[1] += random->RandomFloat( -0.9f, 0.9f );
rDir[2] += random->RandomFloat( -0.9f, 0.9f );
pParticle->m_vecVelocity = rDir * random->RandomInt( 32, 64 );
}
}
//Add small ember-like particles
if ( random->RandomInt( 0, 1 ) == 0 )
{
m_pEmberEmitter->SetSortOrigin( GetAbsOrigin() );
pParticle = (SimpleParticle *) m_pEmberEmitter->AddParticle( sizeof(SimpleParticle), g_Mat_DustPuff[0], GetAbsOrigin() );
assert(pParticle);
if ( pParticle )
{
pParticle->m_flLifetime = 0.0f;
pParticle->m_flDieTime = 1.0f;
pParticle->m_flRoll = 0;
pParticle->m_flRollDelta = 0;
pParticle->m_uchColor[0] = 255;
pParticle->m_uchColor[1] = 255;
pParticle->m_uchColor[2] = 255;
pParticle->m_uchStartAlpha = 255;
pParticle->m_uchEndAlpha = 0;
pParticle->m_uchStartSize = 1;
pParticle->m_uchEndSize = 0;
Vector dir;
QAngle ofsAngles;
ofsAngles.Random( -8.0f, 8.0f );
ofsAngles += GetAbsAngles();
AngleVectors( ofsAngles, &dir );
if ( m_bUseMuzzlePoint )
{
dir.Negate();
}
pParticle->m_vecVelocity = dir * random->RandomInt( 400, 800 );
}
}
}
}
// Inner beam
CBeamSegDraw beamDraw;
CBeamSeg seg;
const int numPoints = 4;
Vector beamPoints[numPoints];
beamPoints[0] = GetAbsOrigin();
// Create our beam points
int i;
for ( i = 0; i < numPoints; i++ )
{
beamPoints[i] = GetAbsOrigin() + ( shotDir * (32*i*i) );
beamPoints[i] += vRight * sin( gpGlobals->curtime * 4.0f ) * (2.0f*i);
beamPoints[i] += vUp * sin( gpGlobals->curtime * 8.0f ) * (1.0f*i);
beamPoints[i] += shotDir * sin( gpGlobals->curtime * (16.0f*i) ) * (1.0f*i);
}
IMaterial *pMat = materials->FindMaterial( "particle/particle_smokegrenade", TEXTURE_GROUP_PARTICLE );
beamDraw.Start( numPoints, pMat );
//Setup and draw those points
for( i = 0; i < numPoints; i++ )
{
float t = (float) i / (numPoints - 1);
float color = 1.0f * (1.0f - t);
seg.m_vColor = Vector( color, color, color );
seg.m_vPos = beamPoints[i];
seg.m_flTexCoord = (float)i/(float)(numPoints-1) - ((gpGlobals->curtime - (int)gpGlobals->curtime) * 4.0f );
seg.m_flWidth = 4.0f + ( (64.0f*t) * (fabs( sin( gpGlobals->curtime * 16.0f ) )) );
seg.m_flAlpha = color;
beamDraw.NextSeg( &seg );
}
beamDraw.End();
}
//-----------------------------------------------------------------------------
// Purpose:
// Input : flags -
//-----------------------------------------------------------------------------
int C_ExtinguisherJet::DrawModel( int flags )
{
if ( m_bEmit == false )
return 1;
Update( Helper_GetFrameTime() );
return 1;
}

View File

@@ -0,0 +1,249 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
//=============================================================================//
#include "cbase.h"
#include "fx_quad.h"
#include "fx.h"
class C_MortarShell : public C_BaseEntity
{
public:
DECLARE_CLASS( C_MortarShell, C_BaseEntity );
DECLARE_CLIENTCLASS();
void OnDataChanged( DataUpdateType_t updateType );
int DrawModel( int flags );
RenderGroup_t GetRenderGroup( void ) { return RENDER_GROUP_TRANSLUCENT_ENTITY; }
private:
void AddRisingParticles( float flPerc );
void AddExplodingParticles( float flPerc );
inline float GetStartPerc( void );
inline float GetEndPerc( void );
CSmartPtr<CSimpleEmitter> m_pEmitter;
TimedEvent m_ParticleEvent;
float m_flLifespan;
float m_flRadius;
float m_flStarttime;
Vector m_vecSurfaceNormal;
};
IMPLEMENT_CLIENTCLASS_DT( C_MortarShell, DT_MortarShell, CMortarShell )
RecvPropFloat( RECVINFO( m_flLifespan ) ),
RecvPropFloat( RECVINFO( m_flRadius ) ),
RecvPropVector( RECVINFO( m_vecSurfaceNormal ) ),
END_RECV_TABLE()
//-----------------------------------------------------------------------------
// Purpose:
// Input : updateType -
//-----------------------------------------------------------------------------
void C_MortarShell::OnDataChanged( DataUpdateType_t updateType )
{
BaseClass::OnDataChanged( updateType );
if ( updateType == DATA_UPDATE_CREATED )
{
m_flStarttime = gpGlobals->curtime;
AddToLeafSystem( RENDER_GROUP_TRANSLUCENT_ENTITY );
m_pEmitter = CSimpleEmitter::Create( "C_EntityDissolve" );
m_pEmitter->SetSortOrigin( GetAbsOrigin() );
m_ParticleEvent.Init( 128 );
}
}
//-----------------------------------------------------------------------------
// Purpose:
// Input : flPerc -
//-----------------------------------------------------------------------------
void C_MortarShell::AddRisingParticles( float flPerc )
{
SimpleParticle *sParticle;
Vector offset;
float radius = m_flRadius * 0.25f * flPerc;
float val = RemapValClamped( gpGlobals->curtime, m_flStarttime, m_flStarttime + m_flLifespan, 0.0f, 1.0f );
float flCur = gpGlobals->frametime;
// Anime ground effects
while ( m_ParticleEvent.NextEvent( flCur ) )
{
offset.x = random->RandomFloat( -radius, radius );
offset.y = random->RandomFloat( -radius, radius );
offset.z = random->RandomFloat( -8.0f, 8.0f );
offset += GetAbsOrigin();
sParticle = (SimpleParticle *) m_pEmitter->AddParticle( sizeof(SimpleParticle), m_pEmitter->GetPMaterial( "effects/spark" ), offset );
if ( sParticle == NULL )
return;
sParticle->m_vecVelocity = Vector( Helper_RandomFloat( -4.0f, 4.0f ), Helper_RandomFloat( -4.0f, 4.0f ), Helper_RandomFloat( 32.0f, 256.0f ) * Bias( val, 0.25f ) );
sParticle->m_uchStartSize = random->RandomFloat( 4, 8 ) * flPerc;
sParticle->m_flDieTime = random->RandomFloat( 0.5f, 1.0f );
sParticle->m_flLifetime = 0.0f;
sParticle->m_flRoll = Helper_RandomInt( 0, 360 );
float alpha = 255 * flPerc;
sParticle->m_flRollDelta = Helper_RandomFloat( -8.0f * flPerc, 8.0f * flPerc );
sParticle->m_uchColor[0] = alpha;
sParticle->m_uchColor[1] = alpha;
sParticle->m_uchColor[2] = alpha;
sParticle->m_uchStartAlpha = alpha;
sParticle->m_uchEndAlpha = 0;
sParticle->m_uchEndSize = 0;
}
}
//-----------------------------------------------------------------------------
// Purpose:
// Input : flPerc -
//-----------------------------------------------------------------------------
void C_MortarShell::AddExplodingParticles( float flPerc )
{
SimpleParticle *sParticle;
Vector offset;
float radius = 48.0f * flPerc;
float flCur = gpGlobals->frametime;
// Anime ground effects
while ( m_ParticleEvent.NextEvent( flCur ) )
{
offset.x = random->RandomFloat( -radius, radius );
offset.y = random->RandomFloat( -radius, radius );
offset.z = random->RandomFloat( -8.0f, 8.0f );
offset += GetAbsOrigin();
sParticle = (SimpleParticle *) m_pEmitter->AddParticle( sizeof(SimpleParticle), m_pEmitter->GetPMaterial( "effects/spark" ), offset );
if ( sParticle == NULL )
return;
sParticle->m_vecVelocity = RandomVector( -1.0f, 1.0f ) + Vector( 0, 0, 1 );
sParticle->m_vecVelocity *= ( 750.0f * flPerc );
sParticle->m_uchStartSize = random->RandomFloat( 2, 4 ) * flPerc;
sParticle->m_flDieTime = random->RandomFloat( 0.25f, 0.5f );
sParticle->m_flLifetime = 0.0f;
sParticle->m_flRoll = Helper_RandomInt( 0, 360 );
float alpha = 255 * flPerc;
sParticle->m_flRollDelta = Helper_RandomFloat( -8.0f * flPerc, 8.0f * flPerc );
sParticle->m_uchColor[0] = alpha;
sParticle->m_uchColor[1] = alpha;
sParticle->m_uchColor[2] = alpha;
sParticle->m_uchStartAlpha = alpha;
sParticle->m_uchEndAlpha = 0;
sParticle->m_uchEndSize = 0;
}
}
//-----------------------------------------------------------------------------
// Purpose:
// Output : inline float
//-----------------------------------------------------------------------------
inline float C_MortarShell::GetStartPerc( void )
{
float val = RemapValClamped( gpGlobals->curtime, m_flStarttime, m_flStarttime + m_flLifespan, 0.0f, 1.0f );
return ( Gain( val, 0.2f ) );
}
//-----------------------------------------------------------------------------
// Purpose:
// Output : inline float
//-----------------------------------------------------------------------------
inline float C_MortarShell::GetEndPerc( void )
{
float val = RemapValClamped( gpGlobals->curtime, m_flStarttime + m_flLifespan, m_flStarttime + m_flLifespan + 1.0f, 1.0f, 0.0f );
return ( Gain( val, 0.75f ) );
}
#define ALPHA_MIN 0.0f
#define ALPHA_MAX 1.0f
#define SCALE_MIN 8
#define SCALE_MAX 200
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
int C_MortarShell::DrawModel( int flags )
{
if ( gpGlobals->frametime <= 0.0f )
return 0;
float flPerc;
bool ending;
// See if we're in the beginning phase
if ( gpGlobals->curtime < ( m_flStarttime + m_flLifespan ) )
{
flPerc = GetStartPerc();
ending = false;
}
else
{
flPerc = GetEndPerc();
ending = true;
}
float flAlpha = ALPHA_MIN + ( ( ALPHA_MAX - ALPHA_MIN ) * flPerc );
float flScale = ( ending ) ? m_flRadius : ( (m_flRadius*0.1f)+ ( ( m_flRadius - (m_flRadius*0.1f) ) * flPerc ) );
// Do the ground effect
FX_AddQuad( GetAbsOrigin() + ( m_vecSurfaceNormal * 2.0f ),
m_vecSurfaceNormal,
flScale,
flScale,
1.0f,
flAlpha,
flAlpha,
1.0f,
0,
0,
Vector( 1.0f, 1.0f, 1.0f ),
0.0001f,
"effects/combinemuzzle2_nocull",
0 );
if ( !ending )
{
// Add extra effects on startup
AddRisingParticles( flPerc );
}
else
{
// Add exploding particles after the impact
AddExplodingParticles( flPerc );
}
return 1;
}

View File

@@ -0,0 +1,52 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
// $NoKeywords: $
//=============================================================================//
#include "cbase.h"
#include "c_hl2_playerlocaldata.h"
#include "dt_recv.h"
// memdbgon must be the last include file in a .cpp file!!!
#include "tier0/memdbgon.h"
BEGIN_RECV_TABLE_NOBASE( C_HL2PlayerLocalData, DT_HL2Local )
RecvPropFloat( RECVINFO(m_flSuitPower) ),
RecvPropInt( RECVINFO(m_bZooming) ),
RecvPropInt( RECVINFO(m_bitsActiveDevices) ),
RecvPropInt( RECVINFO(m_iSquadMemberCount) ),
RecvPropInt( RECVINFO(m_iSquadMedicCount) ),
RecvPropBool( RECVINFO(m_fSquadInFollowMode) ),
RecvPropBool( RECVINFO(m_bWeaponLowered) ),
RecvPropEHandle( RECVINFO(m_hAutoAimTarget) ),
RecvPropVector( RECVINFO(m_vecAutoAimPoint) ),
RecvPropEHandle( RECVINFO(m_hLadder) ),
RecvPropBool( RECVINFO(m_bDisplayReticle) ),
RecvPropBool( RECVINFO(m_bStickyAutoAim) ),
RecvPropBool( RECVINFO(m_bAutoAimTarget) ),
#ifdef HL2_EPISODIC
RecvPropFloat( RECVINFO(m_flFlashBattery) ),
RecvPropVector( RECVINFO(m_vecLocatorOrigin) ),
#endif
END_RECV_TABLE()
BEGIN_PREDICTION_DATA_NO_BASE( C_HL2PlayerLocalData )
DEFINE_PRED_FIELD( m_hLadder, FIELD_EHANDLE, FTYPEDESC_INSENDTABLE ),
END_PREDICTION_DATA()
C_HL2PlayerLocalData::C_HL2PlayerLocalData()
{
m_flSuitPower = 0.0;
m_bZooming = false;
m_iSquadMemberCount = 0;
m_iSquadMedicCount = 0;
m_fSquadInFollowMode = false;
m_bWeaponLowered = false;
m_hLadder = NULL;
#ifdef HL2_EPISODIC
m_flFlashBattery = 0.0f;
m_vecLocatorOrigin = vec3_origin;
#endif
}

View File

@@ -0,0 +1,55 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
// $Workfile: $
// $NoKeywords: $
//=============================================================================//
#if !defined( C_HL2_PLAYERLOCALDATA_H )
#define C_HL2_PLAYERLOCALDATA_H
#ifdef _WIN32
#pragma once
#endif
#include "dt_recv.h"
#include "hl2/hl_movedata.h"
EXTERN_RECV_TABLE( DT_HL2Local );
class C_HL2PlayerLocalData
{
public:
DECLARE_PREDICTABLE();
DECLARE_CLASS_NOBASE( C_HL2PlayerLocalData );
DECLARE_EMBEDDED_NETWORKVAR();
C_HL2PlayerLocalData();
float m_flSuitPower;
bool m_bZooming;
int m_bitsActiveDevices;
int m_iSquadMemberCount;
int m_iSquadMedicCount;
bool m_fSquadInFollowMode;
bool m_bWeaponLowered;
EHANDLE m_hAutoAimTarget;
Vector m_vecAutoAimPoint;
bool m_bDisplayReticle;
bool m_bStickyAutoAim;
bool m_bAutoAimTarget;
#ifdef HL2_EPISODIC
float m_flFlashBattery;
Vector m_vecLocatorOrigin;
#endif
// Ladder related data
EHANDLE m_hLadder;
LadderMove_t m_LadderMove;
};
#endif

View File

@@ -0,0 +1,194 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
// $NoKeywords: $
//=============================================================================//
#include "cbase.h"
#include "c_vguiscreen.h"
#include <vgui/IVGui.h>
#include <vgui_controls/Controls.h>
#include <vgui_controls/Label.h>
#include "clientmode_hlnormal.h"
#include "tier1/utllinkedlist.h"
// memdbgon must be the last include file in a .cpp file!!!
#include "tier0/memdbgon.h"
//-----------------------------------------------------------------------------
// Amount of time before breen teleports away
//-----------------------------------------------------------------------------
class C_InfoTeleporterCountdown : public C_BaseEntity
{
public:
DECLARE_CLASS( C_InfoTeleporterCountdown, C_BaseEntity );
DECLARE_CLIENTCLASS();
public:
C_InfoTeleporterCountdown();
~C_InfoTeleporterCountdown();
virtual bool ShouldDraw() { return false; }
private:
bool m_bCountdownStarted;
bool m_bDisabled;
float m_flStartTime;
float m_flTimeRemaining;
friend class CTeleportCountdownScreen;
};
//-----------------------------------------------------------------------------
// Global list of teleporters
//-----------------------------------------------------------------------------
CUtlFixedLinkedList<C_InfoTeleporterCountdown *> g_InfoTeleporterCountdownList;
//-----------------------------------------------------------------------------
// Networking
//-----------------------------------------------------------------------------
IMPLEMENT_CLIENTCLASS_DT( C_InfoTeleporterCountdown, DT_InfoTeleporterCountdown, CInfoTeleporterCountdown )
RecvPropInt( RECVINFO( m_bCountdownStarted ) ),
RecvPropInt( RECVINFO( m_bDisabled ) ),
RecvPropTime( RECVINFO( m_flStartTime ) ),
RecvPropFloat( RECVINFO( m_flTimeRemaining ) ),
END_RECV_TABLE()
//-----------------------------------------------------------------------------
// Constructor, destructor
//-----------------------------------------------------------------------------
C_InfoTeleporterCountdown::C_InfoTeleporterCountdown()
{
g_InfoTeleporterCountdownList.AddToTail( this );
}
C_InfoTeleporterCountdown::~C_InfoTeleporterCountdown()
{
g_InfoTeleporterCountdownList.FindAndRemove( this );
}
//-----------------------------------------------------------------------------
//
// In-game vgui panel which shows the teleporter countdown
//
//-----------------------------------------------------------------------------
class CTeleportCountdownScreen : public CVGuiScreenPanel
{
DECLARE_CLASS( CTeleportCountdownScreen, CVGuiScreenPanel );
public:
CTeleportCountdownScreen( vgui::Panel *parent, const char *panelName );
virtual bool Init( KeyValues* pKeyValues, VGuiScreenInitData_t* pInitData );
virtual void OnTick();
private:
vgui::Label *m_pTimeRemainingTitleLabel;
vgui::Label *m_pTimeRemainingLabel;
vgui::Label *m_pMalfunctionLabel;
};
//-----------------------------------------------------------------------------
// Standard VGUI panel for objects
//-----------------------------------------------------------------------------
DECLARE_VGUI_SCREEN_FACTORY( CTeleportCountdownScreen, "teleport_countdown_screen" );
//-----------------------------------------------------------------------------
// Constructor:
//-----------------------------------------------------------------------------
CTeleportCountdownScreen::CTeleportCountdownScreen( vgui::Panel *parent, const char *panelName )
: BaseClass( parent, panelName, g_hVGuiCombineScheme )
{
}
//-----------------------------------------------------------------------------
// Initialization
//-----------------------------------------------------------------------------
bool CTeleportCountdownScreen::Init( KeyValues* pKeyValues, VGuiScreenInitData_t* pInitData )
{
// Load all of the controls in
if ( !BaseClass::Init(pKeyValues, pInitData) )
return false;
// Make sure we get ticked...
vgui::ivgui()->AddTickSignal( GetVPanel() );
// Grab ahold of certain well-known controls
// NOTE: it is valid for these controls to not exist!
m_pTimeRemainingTitleLabel = dynamic_cast<vgui::Label*>(FindChildByName( "TimeRemainingTitle" ));
m_pTimeRemainingLabel = dynamic_cast<vgui::Label*>(FindChildByName( "TimeRemaining" ));
m_pMalfunctionLabel = dynamic_cast<vgui::Label*>( FindChildByName( "MalfunctionLabel" ) );
return true;
}
//-----------------------------------------------------------------------------
// Frame-based update
//-----------------------------------------------------------------------------
void CTeleportCountdownScreen::OnTick()
{
BaseClass::OnTick();
// Find the active info teleporter countdown
C_InfoTeleporterCountdown *pActiveCountdown = NULL;
for ( int i = g_InfoTeleporterCountdownList.Head(); i != g_InfoTeleporterCountdownList.InvalidIndex();
i = g_InfoTeleporterCountdownList.Next(i) )
{
if ( g_InfoTeleporterCountdownList[i]->m_bCountdownStarted )
{
pActiveCountdown = g_InfoTeleporterCountdownList[i];
break;
}
}
if ( !GetEntity() || !pActiveCountdown )
{
m_pTimeRemainingTitleLabel->SetVisible( false );
m_pTimeRemainingLabel->SetVisible( false );
m_pMalfunctionLabel->SetVisible( false );
return;
}
// Make the appropriate labels visible
bool bMalfunction = pActiveCountdown->m_bDisabled;
m_pTimeRemainingTitleLabel->SetVisible( !bMalfunction );
m_pTimeRemainingLabel->SetVisible( !bMalfunction );
// This will make it flash
m_pMalfunctionLabel->SetVisible( bMalfunction && (((int)(gpGlobals->curtime) & 0x1) == 0x1) );
// Update the time remaining
if ( !bMalfunction )
{
char buf[32];
if (m_pTimeRemainingLabel)
{
float dt = gpGlobals->curtime - pActiveCountdown->m_flStartTime;
if ( dt < 0.0f )
{
dt = 0.0f;
}
int nTimeRemaining = (int)(pActiveCountdown->m_flTimeRemaining - dt + 0.5f);
if ( nTimeRemaining < 0 )
{
nTimeRemaining = 0;
}
Q_snprintf( buf, sizeof( buf ), "%d", nTimeRemaining );
m_pTimeRemainingLabel->SetText( buf );
}
}
}

View File

@@ -0,0 +1,160 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Client side antlion guard. Used to create dlight for the cave guard.
//
//=============================================================================
#include "cbase.h"
#include "c_ai_basenpc.h"
#include "dlight.h"
#include "iefx.h"
// memdbgon must be the last include file in a .cpp file!!!
#include "tier0/memdbgon.h"
#if HL2_EPISODIC
// When enabled, add code to have the antlion bleed profusely as it is badly injured.
#define ANTLIONGUARD_BLOOD_EFFECTS 2
#endif
class C_NPC_AntlionGuard : public C_AI_BaseNPC
{
public:
C_NPC_AntlionGuard() {}
DECLARE_CLASS( C_NPC_AntlionGuard, C_AI_BaseNPC );
DECLARE_CLIENTCLASS();
DECLARE_DATADESC();
virtual void OnDataChanged( DataUpdateType_t type );
virtual void ClientThink();
private:
bool m_bCavernBreed;
bool m_bInCavern;
dlight_t *m_dlight;
#if HL2_EPISODIC
unsigned char m_iBleedingLevel; //< the version coming from the server
unsigned char m_iPerformingBleedingLevel; //< the version we're currently performing (for comparison to one above)
CNewParticleEffect *m_pBleedingFX;
/// update the hemorrhage particle effect
virtual void UpdateBleedingPerformance( void );
#endif
C_NPC_AntlionGuard( const C_NPC_AntlionGuard & );
};
//-----------------------------------------------------------------------------
// Save/restore
//-----------------------------------------------------------------------------
BEGIN_DATADESC( C_NPC_AntlionGuard )
END_DATADESC()
//-----------------------------------------------------------------------------
// Networking
//-----------------------------------------------------------------------------
IMPLEMENT_CLIENTCLASS_DT(C_NPC_AntlionGuard, DT_NPC_AntlionGuard, CNPC_AntlionGuard)
RecvPropBool( RECVINFO( m_bCavernBreed ) ),
RecvPropBool( RECVINFO( m_bInCavern ) ),
#if ANTLIONGUARD_BLOOD_EFFECTS
RecvPropInt( RECVINFO( m_iBleedingLevel ) ),
#endif
END_RECV_TABLE()
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
void C_NPC_AntlionGuard::OnDataChanged( DataUpdateType_t type )
{
BaseClass::OnDataChanged( type );
if ( (type == DATA_UPDATE_CREATED) && m_bCavernBreed && m_bInCavern )
{
SetNextClientThink( CLIENT_THINK_ALWAYS );
}
#if HL2_EPISODIC
if (m_iBleedingLevel != m_iPerformingBleedingLevel)
{
UpdateBleedingPerformance();
}
#endif
}
#if HL2_EPISODIC
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
void C_NPC_AntlionGuard::UpdateBleedingPerformance()
{
// get my particles
CParticleProperty * pProp = ParticleProp();
// squelch the prior effect if it exists
if (m_pBleedingFX)
{
pProp->StopEmission(m_pBleedingFX);
m_pBleedingFX = NULL;
}
// kick off a new effect
switch (m_iBleedingLevel)
{
case 1: // light bleeding
{
m_pBleedingFX = pProp->Create( "blood_antlionguard_injured_light", PATTACH_ABSORIGIN_FOLLOW );
AssertMsg1( m_pBleedingFX, "Particle system couldn't make %s", "blood_antlionguard_injured_light" );
if ( m_pBleedingFX )
{
pProp->AddControlPoint( m_pBleedingFX, 1, this, PATTACH_ABSORIGIN_FOLLOW );
}
}
break;
case 2: // severe bleeding
{
m_pBleedingFX = pProp->Create( "blood_antlionguard_injured_heavy", PATTACH_ABSORIGIN_FOLLOW );
AssertMsg1( m_pBleedingFX, "Particle system couldn't make %s", "blood_antlionguard_injured_heavy" );
if ( m_pBleedingFX )
{
pProp->AddControlPoint( m_pBleedingFX, 1, this, PATTACH_ABSORIGIN_FOLLOW );
}
}
break;
}
m_iPerformingBleedingLevel = m_iBleedingLevel;
}
#endif
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
void C_NPC_AntlionGuard::ClientThink()
{
// update the dlight. (always done because clienthink only exists for cavernguard)
if (!m_dlight)
{
m_dlight = effects->CL_AllocDlight( index );
m_dlight->color.r = 220;
m_dlight->color.g = 255;
m_dlight->color.b = 80;
m_dlight->radius = 180;
m_dlight->minlight = 128.0 / 256.0f;
m_dlight->flags = DLIGHT_NO_MODEL_ILLUMINATION;
}
m_dlight->origin = GetAbsOrigin();
// dl->die = gpGlobals->curtime + 0.1f;
BaseClass::ClientThink();
}

View File

@@ -0,0 +1,476 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
//=============================================================================//
#include "cbase.h"
#include "c_basehelicopter.h"
#include "fx_impact.h"
#include "IEffects.h"
#include "simple_keys.h"
#include "fx_envelope.h"
#include "fx_line.h"
#include "iefx.h"
#include "dlight.h"
#include "c_sprite.h"
#include "clienteffectprecachesystem.h"
#include <bitbuf.h>
// memdbgon must be the last include file in a .cpp file!!!
#include "tier0/memdbgon.h"
#define GUNSHIP_MSG_BIG_SHOT 1
#define GUNSHIP_MSG_STREAKS 2
#define GUNSHIP_MSG_DEAD 3
#define GUNSHIPFX_BIG_SHOT_TIME 3.0f
CLIENTEFFECT_REGISTER_BEGIN( PrecacheGunshipFX )
CLIENTEFFECT_MATERIAL( "sprites/bluelaser1" )
CLIENTEFFECT_REGISTER_END()
//-----------------------------------------------------------------------------
// Big belly shot FX
//-----------------------------------------------------------------------------
class C_GunshipFX : public C_EnvelopeFX
{
public:
typedef C_EnvelopeFX BaseClass;
C_GunshipFX();
void Update( C_BaseEntity *pOwner, const Vector &targetPos );
// Returns the bounds relative to the origin (render bounds)
virtual void GetRenderBounds( Vector& mins, Vector& maxs )
{
ClearBounds( mins, maxs );
AddPointToBounds( m_worldPosition, mins, maxs );
AddPointToBounds( m_targetPosition, mins, maxs );
mins -= GetRenderOrigin();
maxs -= GetRenderOrigin();
}
virtual int DrawModel( int flags );
C_BaseEntity *m_pOwner;
Vector m_targetPosition;
Vector m_beamEndPosition;
};
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
C_GunshipFX::C_GunshipFX( void )
{
m_pOwner = NULL;
}
enum
{
GUNSHIPFX_WARP_SCALE = 0,
GUNSHIPFX_DARKNESS,
GUNSHIPFX_FLARE_COLOR,
GUNSHIPFX_FLARE_SIZE,
GUNSHIPFX_NARROW_BEAM_COLOR,
GUNSHIPFX_NARROW_BEAM_SIZE,
GUNSHIPFX_WIDE_BEAM_COLOR,
GUNSHIPFX_WIDE_BEAM_SIZE,
GUNSHIPFX_AFTERGLOW_COLOR,
GUNSHIPFX_WIDE_BEAM_LENGTH,
// must be last
GUNSHIPFX_PARAMETERS,
};
class CGunshipFXEnvelope
{
public:
CGunshipFXEnvelope();
void AddKey( int parameterIndex, const CSimpleKeyInterp &key )
{
Assert( parameterIndex >= 0 && parameterIndex < GUNSHIPFX_PARAMETERS );
if ( parameterIndex >= 0 && parameterIndex < GUNSHIPFX_PARAMETERS )
{
m_parameters[parameterIndex].Insert( key );
}
}
CSimpleKeyList m_parameters[GUNSHIPFX_PARAMETERS];
};
// NOTE: Beam widths are half-widths or radii, so this is a beam that represents a cylinder with 2" radius
const float NARROW_BEAM_WIDTH = 32;
const float WIDE_BEAM_WIDTH = 2;
const float FLARE_SIZE = 128;
const float DARK_SIZE = 16;
const float AFTERGLOW_SIZE = 64;
CGunshipFXEnvelope::CGunshipFXEnvelope()
{
// Glow flare
AddKey( GUNSHIPFX_FLARE_COLOR, CSimpleKeyInterp( 0.0, KEY_LINEAR, 0 ) );
AddKey( GUNSHIPFX_FLARE_COLOR, CSimpleKeyInterp( 0.5, KEY_SPLINE, 1 ) );
AddKey( GUNSHIPFX_FLARE_COLOR, CSimpleKeyInterp( 2.9, KEY_LINEAR, 1 ) );
AddKey( GUNSHIPFX_FLARE_COLOR, CSimpleKeyInterp( 3.2, KEY_DECELERATE, 0 ) );
AddKey( GUNSHIPFX_FLARE_SIZE, CSimpleKeyInterp( 0.0, KEY_LINEAR, 0 ) );
AddKey( GUNSHIPFX_FLARE_SIZE, CSimpleKeyInterp( 2.9, KEY_ACCELERATE, 1 ) );
AddKey( GUNSHIPFX_FLARE_SIZE, CSimpleKeyInterp( 5.0, KEY_LINEAR, 1 ) );
// Ground beam
AddKey( GUNSHIPFX_NARROW_BEAM_COLOR, CSimpleKeyInterp( 0.0, KEY_LINEAR, 0.0 ) );
AddKey( GUNSHIPFX_NARROW_BEAM_COLOR, CSimpleKeyInterp( 2.5, KEY_SPLINE, 1.0 ) );
AddKey( GUNSHIPFX_NARROW_BEAM_COLOR, CSimpleKeyInterp( 3.0, KEY_LINEAR, 1 ) );
AddKey( GUNSHIPFX_NARROW_BEAM_COLOR, CSimpleKeyInterp( 3.2, KEY_ACCELERATE, 0 ) );
AddKey( GUNSHIPFX_NARROW_BEAM_SIZE, CSimpleKeyInterp( 0.0, KEY_LINEAR, 0 ) );
AddKey( GUNSHIPFX_NARROW_BEAM_SIZE, CSimpleKeyInterp( 2.5, KEY_SPLINE, 0.25 ) );
AddKey( GUNSHIPFX_NARROW_BEAM_SIZE, CSimpleKeyInterp( 2.8, KEY_ACCELERATE, 1 ) );
AddKey( GUNSHIPFX_NARROW_BEAM_SIZE, CSimpleKeyInterp( 3.0, KEY_ACCELERATE, 4 ) );
AddKey( GUNSHIPFX_NARROW_BEAM_SIZE, CSimpleKeyInterp( 3.2, KEY_DECELERATE, 0 ) );
// Glow color on the ship
AddKey( GUNSHIPFX_AFTERGLOW_COLOR, CSimpleKeyInterp( 0.0, KEY_LINEAR, 0 ) );
AddKey( GUNSHIPFX_AFTERGLOW_COLOR, CSimpleKeyInterp( 3.0, KEY_LINEAR, 1 ) );
AddKey( GUNSHIPFX_AFTERGLOW_COLOR, CSimpleKeyInterp( 5.0, KEY_SPLINE, 0 ) );
}
CGunshipFXEnvelope g_GunshipCannonEnvelope;
static void ScaleColor( color32 &out, const color32 &in, float scale )
{
out.r = (byte)(int)((float)in.r * scale);
out.g = (byte)(int)((float)in.g * scale);
out.b = (byte)(int)((float)in.b * scale);
out.a = (byte)(int)((float)in.a * scale);
}
static void DrawSpriteTangentSpace( const Vector &vecOrigin, float flWidth, float flHeight, color32 color )
{
unsigned char pColor[4] = { color.r, color.g, color.b, color.a };
// Generate half-widths
flWidth *= 0.5f;
flHeight *= 0.5f;
// Compute direction vectors for the sprite
Vector fwd, right( 1, 0, 0 ), up( 0, 1, 0 );
VectorSubtract( CurrentViewOrigin(), vecOrigin, fwd );
float flDist = VectorNormalize( fwd );
if (flDist >= 1e-3)
{
CrossProduct( CurrentViewUp(), fwd, right );
flDist = VectorNormalize( right );
if (flDist >= 1e-3)
{
CrossProduct( fwd, right, up );
}
else
{
// In this case, fwd == g_vecVUp, it's right above or
// below us in screen space
CrossProduct( fwd, CurrentViewRight(), up );
VectorNormalize( up );
CrossProduct( up, fwd, right );
}
}
Vector left = -right;
Vector down = -up;
Vector back = -fwd;
CMatRenderContextPtr pRenderContext( materials );
CMeshBuilder meshBuilder;
Vector point;
IMesh* pMesh = pRenderContext->GetDynamicMesh( );
meshBuilder.Begin( pMesh, MATERIAL_QUADS, 1 );
meshBuilder.Color4ubv (pColor);
meshBuilder.TexCoord2f (0, 0, 1);
VectorMA (vecOrigin, -flHeight, up, point);
VectorMA (point, -flWidth, right, point);
meshBuilder.TangentS3fv( left.Base() );
meshBuilder.TangentT3fv( down.Base() );
meshBuilder.Normal3fv( back.Base() );
meshBuilder.Position3fv (point.Base());
meshBuilder.AdvanceVertex();
meshBuilder.Color4ubv (pColor);
meshBuilder.TexCoord2f (0, 0, 0);
VectorMA (vecOrigin, flHeight, up, point);
VectorMA (point, -flWidth, right, point);
meshBuilder.TangentS3fv( left.Base() );
meshBuilder.TangentT3fv( down.Base() );
meshBuilder.Normal3fv( back.Base() );
meshBuilder.Position3fv (point.Base());
meshBuilder.AdvanceVertex();
meshBuilder.Color4ubv (pColor);
meshBuilder.TexCoord2f (0, 1, 0);
VectorMA (vecOrigin, flHeight, up, point);
VectorMA (point, flWidth, right, point);
meshBuilder.TangentS3fv( left.Base() );
meshBuilder.TangentT3fv( down.Base() );
meshBuilder.Normal3fv( back.Base() );
meshBuilder.Position3fv (point.Base());
meshBuilder.AdvanceVertex();
meshBuilder.Color4ubv (pColor);
meshBuilder.TexCoord2f (0, 1, 1);
VectorMA (vecOrigin, -flHeight, up, point);
VectorMA (point, flWidth, right, point);
meshBuilder.TangentS3fv( left.Base() );
meshBuilder.TangentT3fv( down.Base() );
meshBuilder.Normal3fv( back.Base() );
meshBuilder.Position3fv (point.Base());
meshBuilder.AdvanceVertex();
meshBuilder.End();
pMesh->Draw();
}
void Gunship_DrawSprite( const Vector &vecOrigin, float size, const color32 &color, bool glow )
{
if ( glow )
{
pixelvis_queryparams_t params;
params.Init( vecOrigin );
if ( PixelVisibility_FractionVisible( params, NULL ) <= 0.0f )
return;
}
DrawSpriteTangentSpace( vecOrigin, size, size, color );
}
//-----------------------------------------------------------------------------
// Purpose:
// Input : int -
//-----------------------------------------------------------------------------
int C_GunshipFX::DrawModel( int )
{
static color32 white = {255,255,255,255};
Vector params[GUNSHIPFX_PARAMETERS];
bool hasParam[GUNSHIPFX_PARAMETERS];
if ( !m_active )
return 1;
C_BaseEntity *ent = cl_entitylist->GetEnt( m_entityIndex );
if ( ent )
{
QAngle angles;
ent->GetAttachment( m_attachment, m_worldPosition, angles );
}
Vector test;
m_t += gpGlobals->frametime;
if ( m_tMax > 0 )
{
m_t = clamp( m_t, 0, m_tMax );
m_beamEndPosition = m_worldPosition;
}
float t = m_t;
bool hasAny = false;
memset( hasParam, 0, sizeof(hasParam) );
for ( int i = 0; i < GUNSHIPFX_PARAMETERS; i++ )
{
hasParam[i] = g_GunshipCannonEnvelope.m_parameters[i].Interp( params[i], t );
hasAny = hasAny || hasParam[i];
}
// draw the narrow beam
if ( hasParam[GUNSHIPFX_NARROW_BEAM_COLOR] && hasParam[GUNSHIPFX_NARROW_BEAM_SIZE] )
{
IMaterial *pMat = materials->FindMaterial( "sprites/bluelaser1", TEXTURE_GROUP_CLIENT_EFFECTS );
float width = NARROW_BEAM_WIDTH * params[GUNSHIPFX_NARROW_BEAM_SIZE].x;
color32 color;
float bright = params[GUNSHIPFX_NARROW_BEAM_COLOR].x;
ScaleColor( color, white, bright );
//Gunship_DrawLine( m_beamEndPosition, m_targetPosition, width, pMat, color );
FX_DrawLine( m_beamEndPosition, m_targetPosition, width, pMat, color );
}
// glowy blue flare sprite
if ( hasParam[GUNSHIPFX_FLARE_COLOR] && hasParam[GUNSHIPFX_FLARE_SIZE] )
{
IMaterial *pMat = materials->FindMaterial( "effects/blueblackflash", TEXTURE_GROUP_CLIENT_EFFECTS );
float size = FLARE_SIZE * params[GUNSHIPFX_FLARE_SIZE].x;
color32 color;
float bright = params[GUNSHIPFX_FLARE_COLOR].x;
ScaleColor( color, white, bright );
color.a = (int)(255 * params[GUNSHIPFX_DARKNESS].x);
CMatRenderContextPtr pRenderContext( materials );
pRenderContext->Bind( pMat, (IClientRenderable*)this );
Gunship_DrawSprite( m_worldPosition, size, color, true );
}
if ( hasParam[GUNSHIPFX_AFTERGLOW_COLOR] )
{
// Muzzle effect
dlight_t *dl = effects->CL_AllocDlight( m_entityIndex );
dl->origin = m_worldPosition;
dl->color.r = 40*params[GUNSHIPFX_AFTERGLOW_COLOR].x;
dl->color.g = 60*params[GUNSHIPFX_AFTERGLOW_COLOR].x;
dl->color.b = 255*params[GUNSHIPFX_AFTERGLOW_COLOR].x;
dl->color.exponent = 5;
dl->radius = 128.0f;
dl->die = gpGlobals->curtime + 0.001;
}
if ( m_t >= 4.0 && !hasAny )
{
EffectShutdown();
}
return 1;
}
//-----------------------------------------------------------------------------
// Purpose:
// Input : *pOwner -
// &targetPos -
//-----------------------------------------------------------------------------
void C_GunshipFX::Update( C_BaseEntity *pOwner, const Vector &targetPos )
{
BaseClass::Update();
m_pOwner = pOwner;
if ( m_active )
{
m_targetPosition = targetPos;
}
}
//-----------------------------------------------------------------------------
// Gunship
//-----------------------------------------------------------------------------
class C_CombineGunship : public C_BaseHelicopter
{
DECLARE_CLASS( C_CombineGunship, C_BaseHelicopter );
public:
DECLARE_CLIENTCLASS();
C_CombineGunship( void ) {}
virtual ~C_CombineGunship( void )
{
m_cannonFX.EffectShutdown();
}
C_GunshipFX m_cannonFX;
Vector m_vecHitPos;
//-----------------------------------------------------------------------------
// Purpose:
// Input : length -
// *data -
// Output : void
//-----------------------------------------------------------------------------
void 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 GUNSHIP_MSG_STREAKS:
{
Vector pos;
msg.ReadBitVec3Coord( pos );
m_cannonFX.SetRenderOrigin( pos );
m_cannonFX.EffectInit( entindex(), LookupAttachment( "BellyGun" ) );
m_cannonFX.LimitTime( GUNSHIPFX_BIG_SHOT_TIME );
}
break;
case GUNSHIP_MSG_BIG_SHOT:
{
Vector tmp;
msg.ReadBitVec3Coord( tmp );
m_cannonFX.SetTime( GUNSHIPFX_BIG_SHOT_TIME );
m_cannonFX.LimitTime( 0 );
}
break;
case GUNSHIP_MSG_DEAD:
{
m_cannonFX.EffectShutdown();
}
break;
}
}
void OnDataChanged( DataUpdateType_t updateType )
{
BaseClass::OnDataChanged( updateType );
m_cannonFX.Update( this, m_vecHitPos );
}
virtual RenderGroup_t GetRenderGroup()
{
if ( hl2_episodic.GetBool() == true )
{
return RENDER_GROUP_TWOPASS;
}
else
{
return BaseClass::GetRenderGroup();
}
}
private:
C_CombineGunship( const C_CombineGunship & ) {}
};
IMPLEMENT_CLIENTCLASS_DT( C_CombineGunship, DT_CombineGunship, CNPC_CombineGunship )
RecvPropVector(RECVINFO(m_vecHitPos)),
END_RECV_TABLE()
//-----------------------------------------------------------------------------
// Purpose: Handle gunship impacts
//-----------------------------------------------------------------------------
void ImpactGunshipCallback( const CEffectData &data )
{
trace_t tr;
Vector vecOrigin, vecStart, vecShotDir;
int iMaterial, iDamageType, iHitbox;
short nSurfaceProp;
C_BaseEntity *pEntity = ParseImpactData( data, &vecOrigin, &vecStart, &vecShotDir, nSurfaceProp, iMaterial, iDamageType, iHitbox );
if ( !pEntity )
return;
// If we hit, perform our custom effects and play the sound
if ( Impact( vecOrigin, vecStart, iMaterial, iDamageType, iHitbox, pEntity, tr ) )
{
// Check for custom effects based on the Decal index
PerformCustomEffects( vecOrigin, tr, vecShotDir, iMaterial, 3 );
}
PlayImpactSound( pEntity, tr, vecOrigin, nSurfaceProp );
}
DECLARE_CLIENT_EFFECT( "ImpactGunship", ImpactGunshipCallback );

View File

@@ -0,0 +1,386 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
// $NoKeywords: $
//=============================================================================//
#include "cbase.h"
#include "bone_setup.h"
#include "c_ai_basenpc.h"
#include "engine/ivdebugoverlay.h"
#include "tier0/vprof.h"
#include "soundinfo.h"
// memdbgon must be the last include file in a .cpp file!!!
#include "tier0/memdbgon.h"
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
class C_NPC_Hydra : public C_AI_BaseNPC
{
public:
DECLARE_CLASS( C_NPC_Hydra, C_AI_BaseNPC );
DECLARE_CLIENTCLASS();
DECLARE_INTERPOLATION();
C_NPC_Hydra();
virtual ~C_NPC_Hydra();
// model specific
virtual void OnLatchInterpolatedVariables( int flags );
virtual bool SetupBones( matrix3x4_t *pBoneToWorldOut, int nMaxBones, int boneMask, float currentTime );
virtual void StandardBlendingRules( Vector pos[], Quaternion q[], float currentTime, int boneMask );
void CalcBoneChain( Vector pos[], const Vector chain[] );
void CalcBoneAngles( const Vector pos[], Quaternion q[] );
virtual bool GetSoundSpatialization( SpatializationInfo_t& info );
virtual void ResetLatched();
#define CHAIN_LINKS 32
bool m_bNewChain;
int m_fLatchFlags;
Vector m_vecChain[CHAIN_LINKS];
Vector m_vecHeadDir;
CInterpolatedVar< Vector > m_iv_vecHeadDir;
//Vector m_vecInterpHeadDir;
float m_flRelaxedLength;
Vector *m_vecPos; // current animation
CInterpolatedVar< Vector > *m_iv_vecPos;
int m_numHydraBones;
float *m_boneLength;
float m_maxPossibleLength;
private:
C_NPC_Hydra( const C_NPC_Hydra & ); // not defined, not accessible
};
IMPLEMENT_CLIENTCLASS_DT(C_NPC_Hydra, DT_NPC_Hydra, CNPC_Hydra)
RecvPropVector ( RECVINFO( m_vecChain[0] ) ),
RecvPropVector ( RECVINFO( m_vecChain[1] ) ),
RecvPropVector ( RECVINFO( m_vecChain[2] ) ),
RecvPropVector ( RECVINFO( m_vecChain[3] ) ),
RecvPropVector ( RECVINFO( m_vecChain[4] ) ),
RecvPropVector ( RECVINFO( m_vecChain[5] ) ),
RecvPropVector ( RECVINFO( m_vecChain[6] ) ),
RecvPropVector ( RECVINFO( m_vecChain[7] ) ),
RecvPropVector ( RECVINFO( m_vecChain[8] ) ),
RecvPropVector ( RECVINFO( m_vecChain[9] ) ),
RecvPropVector ( RECVINFO( m_vecChain[10] ) ),
RecvPropVector ( RECVINFO( m_vecChain[11] ) ),
RecvPropVector ( RECVINFO( m_vecChain[12] ) ),
RecvPropVector ( RECVINFO( m_vecChain[13] ) ),
RecvPropVector ( RECVINFO( m_vecChain[14] ) ),
RecvPropVector ( RECVINFO( m_vecChain[15] ) ),
RecvPropVector ( RECVINFO( m_vecChain[16] ) ),
RecvPropVector ( RECVINFO( m_vecChain[17] ) ),
RecvPropVector ( RECVINFO( m_vecChain[18] ) ),
RecvPropVector ( RECVINFO( m_vecChain[19] ) ),
RecvPropVector ( RECVINFO( m_vecChain[20] ) ),
RecvPropVector ( RECVINFO( m_vecChain[21] ) ),
RecvPropVector ( RECVINFO( m_vecChain[22] ) ),
RecvPropVector ( RECVINFO( m_vecChain[23] ) ),
RecvPropVector ( RECVINFO( m_vecChain[24] ) ),
RecvPropVector ( RECVINFO( m_vecChain[25] ) ),
RecvPropVector ( RECVINFO( m_vecChain[26] ) ),
RecvPropVector ( RECVINFO( m_vecChain[27] ) ),
RecvPropVector ( RECVINFO( m_vecChain[28] ) ),
RecvPropVector ( RECVINFO( m_vecChain[29] ) ),
RecvPropVector ( RECVINFO( m_vecChain[30] ) ),
RecvPropVector ( RECVINFO( m_vecChain[31] ) ),
RecvPropVector ( RECVINFO( m_vecHeadDir ) ),
RecvPropFloat ( RECVINFO( m_flRelaxedLength ) ),
END_RECV_TABLE()
C_NPC_Hydra::C_NPC_Hydra() : m_iv_vecHeadDir( "C_NPC_Hydra::m_iv_vecHeadDir" )
{
AddVar( &m_vecHeadDir, &m_iv_vecHeadDir, LATCH_ANIMATION_VAR );
m_numHydraBones = 0;
m_boneLength = NULL;
m_maxPossibleLength = 1;
m_vecPos = NULL;
m_iv_vecPos = NULL;
}
C_NPC_Hydra::~C_NPC_Hydra()
{
delete m_boneLength;
delete m_vecPos;
delete[] m_iv_vecPos;
m_iv_vecPos = NULL;
}
void C_NPC_Hydra::OnLatchInterpolatedVariables( int flags )
{
m_bNewChain = true;
m_fLatchFlags = flags;
BaseClass::OnLatchInterpolatedVariables( flags );
}
void C_NPC_Hydra::ResetLatched()
{
for (int i = 0; i < m_numHydraBones; i++)
{
m_iv_vecPos[i].Reset();
}
BaseClass::ResetLatched();
}
bool C_NPC_Hydra::SetupBones( matrix3x4_t *pBoneToWorldOut, int nMaxBones, int boneMask, float currentTime )
{
return BaseClass::SetupBones( pBoneToWorldOut, nMaxBones, boneMask, currentTime );
}
void C_NPC_Hydra::StandardBlendingRules( Vector pos[], Quaternion q[], float currentTime, int boneMask )
{
VPROF( "C_NPC_Hydra::StandardBlendingRules" );
studiohdr_t *hdr = GetModelPtr();
if ( !hdr )
{
return;
}
int i;
// check for changing model memory requirements
bool bNewlyInited = false;
if (m_numHydraBones != hdr->numbones)
{
m_numHydraBones = hdr->numbones;
// build root animation
float poseparam[MAXSTUDIOPOSEPARAM];
for (i = 0; i < hdr->GetNumPoseParameters(); i++)
{
poseparam[i] = 0;
}
CalcPose( hdr, NULL, pos, q, 0.0f, 0.0f, poseparam, BONE_USED_BY_ANYTHING );
// allocate arrays
if (m_boneLength)
{
delete[] m_boneLength;
}
m_boneLength = new float [m_numHydraBones];
if (m_vecPos)
{
delete[] m_vecPos;
}
m_vecPos = new Vector [m_numHydraBones];
if (m_iv_vecPos)
{
delete m_iv_vecPos;
}
m_iv_vecPos = new CInterpolatedVar< Vector >[m_numHydraBones];
for ( i = 0; i < m_numHydraBones; i++ )
{
m_iv_vecPos[ i ].Setup( &m_vecPos[ i ], LATCH_SIMULATION_VAR | EXCLUDE_AUTO_LATCH | EXCLUDE_AUTO_INTERPOLATE );
}
// calc models bone lengths
m_maxPossibleLength = 0;
for (i = 0; i < m_numHydraBones-1; i++)
{
m_boneLength[i] = (pos[i+1] - pos[i]).Length();
m_maxPossibleLength += m_boneLength[i];
}
m_boneLength[i] = 0.0f;
bNewlyInited = true;
}
// calc new bone setup if networked.
if (m_bNewChain)
{
CalcBoneChain( m_vecPos, m_vecChain );
for (i = 0; i < m_numHydraBones; i++)
{
// debugoverlay->AddLineOverlay( m_vecPos[i], m_vecPos[i<m_numHydraBones-1?i+1:m_numHydraBones-1], 0, 255, 0, false, 0.1 );
m_vecPos[i] = m_vecPos[i] - GetAbsOrigin();
if ( m_fLatchFlags & LATCH_SIMULATION_VAR )
{
m_iv_vecPos[i].NoteChanged( currentTime, true );
}
}
m_bNewChain = false;
}
// if just allocated, initialize bones
if (bNewlyInited)
{
for (i = 0; i < m_numHydraBones; i++)
{
m_iv_vecPos[i].Reset();
}
}
for (i = 0; i < m_numHydraBones; i++)
{
m_iv_vecPos[i].Interpolate( currentTime );
pos[ i ] = m_vecPos[ i ];
}
// calculate bone angles
CalcBoneAngles( pos, q );
// rotate the last bone of the hydra 90 degrees since it's oriented differently than the others
Quaternion qTmp;
AngleQuaternion( QAngle( 0, -90, 0) , qTmp );
QuaternionMult( q[m_numHydraBones - 1], qTmp, q[m_numHydraBones - 1] );
}
//-----------------------------------------------------------------------------
// Purpose: Fits skeleton of hydra to the variable segment length "chain" array
// Adjusts overall hydra so that "m_flRelaxedLength" of texture fits over
// the actual length of the chain
//-----------------------------------------------------------------------------
void C_NPC_Hydra::CalcBoneChain( Vector pos[], const Vector chain[] )
{
int i, j;
// Find the dist chain link that's not zero length
i = CHAIN_LINKS-1;
while (i > 0)
{
if ((chain[i] - chain[i-1]).LengthSqr() > 0.0)
{
break;
}
i--;
}
// initialize the last bone to the last bone
j = m_numHydraBones - 1;
// clamp length
float totalLength = 0;
for (int k = i; k > 0; k--)
{
// debugoverlay->AddLineOverlay( chain[k], chain[k-1], 255, 255, 255, false, 0 );
totalLength += (chain[k] - chain[k-1]).Length();
}
totalLength = clamp( totalLength, 1.0, m_maxPossibleLength );
float scale = m_flRelaxedLength / totalLength;
// starting from the head, fit the hydra skeleton onto the chain spline
float dist = -16;
while (j >= 0 && i > 0)
{
// debugoverlay->AddLineOverlay( chain[i], chain[i-1], 255, 255, 255, false, 0 );
float dt = (chain[i] - chain[i-1]).Length() * scale;
float dx = dt;
while (j >= 0 && dist + dt >= m_boneLength[j])
{
float s = (dx - (dt - (m_boneLength[j] - dist))) / dx;
if (s < 0 || s > 1.)
s = 0;
// pos[j] = chain[i] * (1 - s) + chain[i-1] * s;
Catmull_Rom_Spline( chain[(i<CHAIN_LINKS-1)?i+1:CHAIN_LINKS-1], chain[i], chain[(i>0)?i-1:0], chain[(i>1)?i-2:0], s, pos[j] );
// debugoverlay->AddLineOverlay( pos[j], chain[i], 0, 255, 0, false, 0 );
// debugoverlay->AddLineOverlay( pos[j], chain[i-1], 0, 255, 0, false, 0 );
dt = dt - (m_boneLength[j] - dist);
j--;
dist = 0;
}
dist += dt;
i--;
}
while (j >= 0)
{
pos[j] = chain[0];
j--;
}
}
//-----------------------------------------------------------------------------
// Purpose: Minimize the amount of twist between bone segments
//-----------------------------------------------------------------------------
void C_NPC_Hydra::CalcBoneAngles( const Vector pos[], Quaternion q[] )
{
int i;
matrix3x4_t bonematrix;
for (i = m_numHydraBones - 1; i >= 0; i--)
{
Vector forward;
Vector left2;
if (i != m_numHydraBones - 1)
{
QuaternionMatrix( q[i+1], bonematrix );
MatrixGetColumn( bonematrix, 1, left2 );
forward = (pos[i+1] - pos[i]) /* + (pos[i] - pos[i-1])*/;
float length = VectorNormalize( forward );
if (length == 0.0)
{
q[i] = q[i+1];
continue;
}
}
else
{
forward = m_vecHeadDir;
VectorNormalize( forward );
VectorMatrix( forward, bonematrix );
MatrixGetColumn( bonematrix, 1, left2 );
}
Vector up = CrossProduct( forward, left2 );
VectorNormalize( up );
Vector left = CrossProduct( up, forward );
MatrixSetColumn( forward, 0, bonematrix );
MatrixSetColumn( left, 1, bonematrix );
MatrixSetColumn( up, 2, bonematrix );
// MatrixQuaternion( bonematrix, q[i] );
QAngle angles;
MatrixAngles( bonematrix, angles );
AngleQuaternion( angles, q[i] );
}
}
bool C_NPC_Hydra::GetSoundSpatialization( SpatializationInfo_t& info )
{
bool bret = BaseClass::GetSoundSpatialization( info );
// Default things it's audible, put it at a better spot?
if ( bret )
{
// TODO: Note, this is where you could override the sound position and orientation and use
// an attachment points position as the sound source
// You might have to issue C_BaseAnimating::AllowBoneAccess( true, false ); to allow
// bone setup during sound spatialization if you run into asserts...
}
return bret;
}

View File

@@ -0,0 +1,182 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
// $NoKeywords: $
//=============================================================================//
#include "cbase.h"
#include "c_ai_basenpc.h"
#include "soundenvelope.h"
// memdbgon must be the last include file in a .cpp file!!!
#include "tier0/memdbgon.h"
class C_NPC_Manhack : public C_AI_BaseNPC
{
public:
C_NPC_Manhack() {}
DECLARE_CLASS( C_NPC_Manhack, C_AI_BaseNPC );
DECLARE_CLIENTCLASS();
DECLARE_DATADESC();
// Purpose: Start the manhack's engine sound.
virtual void OnDataChanged( DataUpdateType_t type );
virtual void UpdateOnRemove( void );
virtual void OnRestore();
private:
C_NPC_Manhack( const C_NPC_Manhack & );
// Purpose: Start + stop the manhack's engine sound.
void SoundInit( void );
void SoundShutdown( void );
CSoundPatch *m_pEngineSound1;
CSoundPatch *m_pEngineSound2;
CSoundPatch *m_pBladeSound;
int m_nEnginePitch1;
int m_nEnginePitch2;
float m_flEnginePitch1Time;
float m_flEnginePitch2Time;
};
//-----------------------------------------------------------------------------
// Save/restore
//-----------------------------------------------------------------------------
BEGIN_DATADESC( C_NPC_Manhack )
// DEFINE_SOUNDPATCH( m_pEngineSound1 ),
// DEFINE_SOUNDPATCH( m_pEngineSound2 ),
// DEFINE_SOUNDPATCH( m_pBladeSound ),
// DEFINE_FIELD( m_nEnginePitch1, FIELD_INTEGER ),
// DEFINE_FIELD( m_nEnginePitch2, FIELD_INTEGER ),
// DEFINE_FIELD( m_flEnginePitch1Time, FIELD_FLOAT ),
// DEFINE_FIELD( m_flEnginePitch2Time, FIELD_FLOAT ),
END_DATADESC()
//-----------------------------------------------------------------------------
// Networking
//-----------------------------------------------------------------------------
IMPLEMENT_CLIENTCLASS_DT(C_NPC_Manhack, DT_NPC_Manhack, CNPC_Manhack)
RecvPropIntWithMinusOneFlag(RECVINFO(m_nEnginePitch1)),
RecvPropFloat(RECVINFO(m_flEnginePitch1Time)),
RecvPropIntWithMinusOneFlag(RECVINFO(m_nEnginePitch2)),
RecvPropFloat(RECVINFO(m_flEnginePitch2Time)),
END_RECV_TABLE()
//-----------------------------------------------------------------------------
// Purpose: Start the manhack's engine sound.
//-----------------------------------------------------------------------------
void C_NPC_Manhack::OnDataChanged( DataUpdateType_t type )
{
BaseClass::OnDataChanged( type );
if (( m_nEnginePitch1 < 0 ) || ( m_nEnginePitch2 < 0 ) )
{
SoundShutdown();
}
else
{
SoundInit();
if ( m_pEngineSound1 && m_pEngineSound2 )
{
float dt = ( m_flEnginePitch1Time >= gpGlobals->curtime ) ? m_flEnginePitch1Time - gpGlobals->curtime : 0.0f;
CSoundEnvelopeController::GetController().SoundChangePitch( m_pEngineSound1, m_nEnginePitch1, dt );
dt = ( m_flEnginePitch2Time >= gpGlobals->curtime ) ? m_flEnginePitch2Time - gpGlobals->curtime : 0.0f;
CSoundEnvelopeController::GetController().SoundChangePitch( m_pEngineSound2, m_nEnginePitch2, dt );
}
}
}
//-----------------------------------------------------------------------------
// Restore
//-----------------------------------------------------------------------------
void C_NPC_Manhack::OnRestore()
{
BaseClass::OnRestore();
SoundInit();
}
//-----------------------------------------------------------------------------
// Purpose: Start the manhack's engine sound.
//-----------------------------------------------------------------------------
void C_NPC_Manhack::UpdateOnRemove( void )
{
BaseClass::UpdateOnRemove();
SoundShutdown();
}
//-----------------------------------------------------------------------------
// Purpose: Start the manhack's engine sound.
//-----------------------------------------------------------------------------
void C_NPC_Manhack::SoundInit( void )
{
if (( m_nEnginePitch1 < 0 ) || ( m_nEnginePitch2 < 0 ) )
return;
// play an engine start sound!!
CPASAttenuationFilter filter( this );
// Bring up the engine looping sound.
if( !m_pEngineSound1 )
{
m_pEngineSound1 = CSoundEnvelopeController::GetController().SoundCreate( filter, entindex(), "NPC_Manhack.EngineSound1" );
CSoundEnvelopeController::GetController().Play( m_pEngineSound1, 0.0, m_nEnginePitch1 );
CSoundEnvelopeController::GetController().SoundChangeVolume( m_pEngineSound1, 0.7, 2.0 );
}
if( !m_pEngineSound2 )
{
m_pEngineSound2 = CSoundEnvelopeController::GetController().SoundCreate( filter, entindex(), "NPC_Manhack.EngineSound2" );
CSoundEnvelopeController::GetController().Play( m_pEngineSound2, 0.0, m_nEnginePitch2 );
CSoundEnvelopeController::GetController().SoundChangeVolume( m_pEngineSound2, 0.7, 2.0 );
}
if( !m_pBladeSound )
{
m_pBladeSound = CSoundEnvelopeController::GetController().SoundCreate( filter, entindex(), "NPC_Manhack.BladeSound" );
CSoundEnvelopeController::GetController().Play( m_pBladeSound, 0.0, m_nEnginePitch1 );
CSoundEnvelopeController::GetController().SoundChangeVolume( m_pBladeSound, 0.7, 2.0 );
}
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void C_NPC_Manhack::SoundShutdown(void)
{
// Kill the engine!
if ( m_pEngineSound1 )
{
CSoundEnvelopeController::GetController().SoundDestroy( m_pEngineSound1 );
m_pEngineSound1 = NULL;
}
// Kill the engine!
if ( m_pEngineSound2 )
{
CSoundEnvelopeController::GetController().SoundDestroy( m_pEngineSound2 );
m_pEngineSound2 = NULL;
}
// Kill the blade!
if ( m_pBladeSound )
{
CSoundEnvelopeController::GetController().SoundDestroy( m_pBladeSound );
m_pBladeSound = NULL;
}
}

View File

@@ -0,0 +1,174 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
//=============================================================================//
#include "cbase.h"
#include "c_ai_basenpc.h"
#include "iviewrender_beams.h"
#include "beam_shared.h"
#include "materialsystem/imaterial.h"
#include "model_types.h"
#include "clienteffectprecachesystem.h"
#include "beamdraw.h"
class C_RollerMine : public C_AI_BaseNPC
{
DECLARE_CLASS( C_RollerMine, C_AI_BaseNPC );
public:
DECLARE_CLIENTCLASS();
C_RollerMine( void ) {}
int DrawModel( int flags );
RenderGroup_t GetRenderGroup( void )
{
if ( m_bIsOpen )
return RENDER_GROUP_TRANSLUCENT_ENTITY;
else
return RENDER_GROUP_OPAQUE_ENTITY;
}
private:
C_RollerMine( const C_RollerMine & ) {}
bool m_bIsOpen;
float m_flActiveTime;
bool m_bHackedByAlyx;
bool m_bPowerDown;
};
IMPLEMENT_CLIENTCLASS_DT( C_RollerMine, DT_RollerMine, CNPC_RollerMine )
RecvPropInt( RECVINFO( m_bIsOpen ) ),
RecvPropFloat( RECVINFO( m_flActiveTime ) ),
RecvPropInt( RECVINFO( m_bHackedByAlyx ) ),
RecvPropInt( RECVINFO( m_bPowerDown ) ),
END_RECV_TABLE()
#define NUM_ATTACHMENTS 11
//-----------------------------------------------------------------------------
// Purpose:
// Input : flags -
// Output : int
//-----------------------------------------------------------------------------
int C_RollerMine::DrawModel( int flags )
{
if ( m_bIsOpen && m_flActiveTime <= gpGlobals->curtime )
{
float scale = random->RandomFloat( 4.0f, 6.0f );
if ( gpGlobals->frametime != 0 )
{
// Inner beams
BeamInfo_t beamInfo;
beamInfo.m_vecStart = GetAbsOrigin();
Vector offset = RandomVector( -6*scale, 2*scale );
offset += Vector(2,2,2) * scale;
beamInfo.m_vecEnd = GetAbsOrigin() + offset;
beamInfo.m_pStartEnt= cl_entitylist->GetEnt( BEAMENT_ENTITY( entindex() ) );
beamInfo.m_pEndEnt = beamInfo.m_pStartEnt;
beamInfo.m_nStartAttachment = random->RandomInt( 0, NUM_ATTACHMENTS );
beamInfo.m_nEndAttachment = random->RandomInt( 0, NUM_ATTACHMENTS );
// Ensure we're not the same point
if ( beamInfo.m_nStartAttachment == beamInfo.m_nEndAttachment )
{
int nextStep = ( random->RandomInt( 0, 1 ) ) ? 1 : -1;
beamInfo.m_nEndAttachment = ( beamInfo.m_nStartAttachment + nextStep ) % NUM_ATTACHMENTS;
}
beamInfo.m_nType = TE_BEAMTESLA;
beamInfo.m_pszModelName = "sprites/lgtning.vmt";
beamInfo.m_flHaloScale = 0.0f;
beamInfo.m_flLife = 0.1f;
beamInfo.m_flWidth = random->RandomFloat( 2.0f, 4.0f );
beamInfo.m_flEndWidth = random->RandomFloat( 0.0f, 1.0f );
beamInfo.m_flFadeLength = 0.0f;
beamInfo.m_flAmplitude = random->RandomFloat( 16, 32 );
beamInfo.m_flBrightness = 255.0;
beamInfo.m_flSpeed = 0.0;
beamInfo.m_nStartFrame = 0.0;
beamInfo.m_flFrameRate = 1.0f;
if ( m_bPowerDown )
{
beamInfo.m_flRed = 255.0f;;
beamInfo.m_flGreen = 64.0f;
beamInfo.m_flBlue = 64.0f;
}
else if ( m_bHackedByAlyx )
{
beamInfo.m_flRed = 240.0f;;
beamInfo.m_flGreen = 200.0f;
beamInfo.m_flBlue = 80.0f;
}
else
{
beamInfo.m_flRed = 255.0f;;
beamInfo.m_flGreen = 255.0f;
beamInfo.m_flBlue = 255.0f;
}
beamInfo.m_nSegments = 4;
beamInfo.m_bRenderable = true;
beamInfo.m_nFlags = 0;
beams->CreateBeamEntPoint( beamInfo );
// Draw the halo
float color[3];
if ( m_bHackedByAlyx )
{
color[0] = 0.25f;
color[1] = 0.05f;
color[2] = 0.0f;
}
else
{
color[0] = color[1] = color[2] = 0.15f;
}
IMaterial *pMaterial = materials->FindMaterial( "effects/rollerglow", NULL, false );
CMatRenderContextPtr pRenderContext( materials );
pRenderContext->Bind( pMaterial );
DrawHalo( pMaterial, GetAbsOrigin(), random->RandomFloat( 6.0f*scale, 6.5f*scale ), color );
if ( m_bPowerDown )
{
color[0] = random->RandomFloat( 0.80f, 1.00f );
color[1] = random->RandomFloat( 0.10f, 0.25f );
color[2] = 0.0f;
}
else if ( m_bHackedByAlyx )
{
color[0] = random->RandomFloat( 0.25f, 0.75f );
color[1] = random->RandomFloat( 0.10f, 0.25f );
color[2] = 0.0f;
}
else
{
color[0] = color[1] = color[2] = random->RandomFloat( 0.25f, 0.5f );
}
Vector attachOrigin;
QAngle attachAngles;
GetAttachment( beamInfo.m_nEndAttachment, attachOrigin, attachAngles );
DrawHalo( pMaterial, attachOrigin, random->RandomFloat( 1.0f*scale, 1.5f*scale ), color );
GetAttachment( beamInfo.m_nStartAttachment, attachOrigin, attachAngles );
DrawHalo( pMaterial, attachOrigin, random->RandomFloat( 1.0f*scale, 1.5f*scale ), color );
}
}
return BaseClass::DrawModel( flags );
}

View File

@@ -0,0 +1,279 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
// $NoKeywords: $
//=============================================================================//
#include "cbase.h"
#include "particles_simple.h"
#include "c_tracer.h"
#include "particle_collision.h"
#include "view.h"
#include "clienteffectprecachesystem.h"
// memdbgon must be the last include file in a .cpp file!!!
#include "tier0/memdbgon.h"
#define PLASMASPARK_LIFETIME 0.5
#define SPRAYS_PER_THINK 12
CLIENTEFFECT_REGISTER_BEGIN( PrecacheEffectPlasmaBeam )
CLIENTEFFECT_MATERIAL( "sprites/plasmaember" )
CLIENTEFFECT_REGISTER_END()
class C_PlasmaBeamNode;
//##################################################################
//
// > CPlasmaSpray
//
//##################################################################
class CPlasmaSpray : public CSimpleEmitter
{
public:
CPlasmaSpray( const char *pDebugName ) : CSimpleEmitter( pDebugName ) {}
static CSmartPtr<CPlasmaSpray> Create( const char *pDebugName );
void Think( void );
void UpdateVelocity( SimpleParticle *pParticle, float timeDelta );
virtual void RenderParticles( CParticleRenderIterator *pIterator );
virtual void SimulateParticles( CParticleSimulateIterator *pIterator );
EHANDLE m_pOwner;
CParticleCollision m_ParticleCollision;
private:
CPlasmaSpray( const CPlasmaSpray & );
};
//##################################################################
//
// PlasmaBeamNode - generates plasma spray
//
//##################################################################
class C_PlasmaBeamNode : public C_BaseEntity
{
public:
DECLARE_CLASS( C_PlasmaBeamNode, C_BaseEntity );
DECLARE_CLIENTCLASS();
C_PlasmaBeamNode();
~C_PlasmaBeamNode(void);
public:
void ClientThink(void);
void AddEntity( void );
void OnDataChanged(DataUpdateType_t updateType);
bool ShouldDraw();
bool m_bSprayOn;
CSmartPtr<CPlasmaSpray> m_pFirePlasmaSpray;
};
//##################################################################
//
// > CPlasmaSpray
//
//##################################################################
//-----------------------------------------------------------------------------
// Purpose:
// Input : *pParticle -
// timeDelta -
// Output : float
//-----------------------------------------------------------------------------
CSmartPtr<CPlasmaSpray> CPlasmaSpray::Create( const char *pDebugName )
{
CPlasmaSpray *pRet = new CPlasmaSpray( pDebugName );
return pRet;
}
//-----------------------------------------------------------------------------
// Purpose:
// Input : fTimeDelta -
// Output : Vector
//-----------------------------------------------------------------------------
void CPlasmaSpray::UpdateVelocity( SimpleParticle *pParticle, float timeDelta )
{
Vector vGravity = Vector(0,0,-1000);
float flFrametime = gpGlobals->frametime;
vGravity = flFrametime * vGravity;
pParticle->m_vecVelocity += vGravity;
}
void CPlasmaSpray::SimulateParticles( CParticleSimulateIterator *pIterator )
{
float timeDelta = pIterator->GetTimeDelta();
SimpleParticle *pParticle = (SimpleParticle*)pIterator->GetFirst();
while ( pParticle )
{
//Should this particle die?
pParticle->m_flLifetime += timeDelta;
C_PlasmaBeamNode* pNode = (C_PlasmaBeamNode*)((C_BaseEntity*)m_pOwner);
if ( pParticle->m_flLifetime >= pParticle->m_flDieTime )
{
pIterator->RemoveParticle( pParticle );
}
// If owner is gone or spray off remove me
else if (pNode == NULL || !pNode->m_bSprayOn)
{
pIterator->RemoveParticle( pParticle );
}
//Simulate the movement with collision
trace_t trace;
m_ParticleCollision.MoveParticle( pParticle->m_Pos, pParticle->m_vecVelocity, NULL, timeDelta, &trace );
pParticle = (SimpleParticle*)pIterator->GetNext();
}
}
void CPlasmaSpray::RenderParticles( CParticleRenderIterator *pIterator )
{
const SimpleParticle *pParticle = (const SimpleParticle *)pIterator->GetFirst();
while ( pParticle )
{
float scale = random->RandomFloat( 0.02, 0.08 );
// NOTE: We need to do everything in screen space
Vector delta;
Vector start;
TransformParticle(ParticleMgr()->GetModelView(), pParticle->m_Pos, start);
float sortKey = start.z;
Vector3DMultiply( CurrentWorldToViewMatrix(), pParticle->m_vecVelocity, delta );
delta[0] *= scale;
delta[1] *= scale;
delta[2] *= scale;
// See c_tracer.* for this method
Tracer_Draw( pIterator->GetParticleDraw(), start, delta, random->RandomInt( 2, 8 ), 0 );
pParticle = (const SimpleParticle *)pIterator->GetNext( sortKey );
}
}
//##################################################################
//
// PlasmaBeamNode - generates plasma spray
//
//##################################################################
//------------------------------------------------------------------------------
// Purpose :
// Input :
// Output :
//------------------------------------------------------------------------------
C_PlasmaBeamNode::C_PlasmaBeamNode(void)
{
m_bSprayOn = false;
m_pFirePlasmaSpray = CPlasmaSpray::Create( "C_PlasmaBeamNode" );
}
//------------------------------------------------------------------------------
// Purpose :
// Input :
// Output :
//------------------------------------------------------------------------------
C_PlasmaBeamNode::~C_PlasmaBeamNode(void)
{
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void C_PlasmaBeamNode::AddEntity( void )
{
m_pFirePlasmaSpray->SetSortOrigin( GetAbsOrigin() );
}
//------------------------------------------------------------------------------
// Purpose :
// Input :
// Output :
//------------------------------------------------------------------------------
void C_PlasmaBeamNode::OnDataChanged(DataUpdateType_t updateType)
{
if (updateType == DATA_UPDATE_CREATED)
{
Vector vMoveDir = GetAbsVelocity();
float flVel = VectorNormalize(vMoveDir);
m_pFirePlasmaSpray->m_ParticleCollision.Setup( GetAbsOrigin(), &vMoveDir, 0.3,
flVel-50, flVel+50, 800, 0.5 );
SetNextClientThink(gpGlobals->curtime + 0.01);
}
C_BaseEntity::OnDataChanged(updateType);
}
//------------------------------------------------------------------------------
// Purpose :
// Input :
// Output :
//------------------------------------------------------------------------------
bool C_PlasmaBeamNode::ShouldDraw()
{
return false;
}
//------------------------------------------------------------------------------
// Purpose :
// Input :
// Output :
//------------------------------------------------------------------------------
void C_PlasmaBeamNode::ClientThink(void)
{
if (!m_bSprayOn)
{
return;
}
trace_t trace;
Vector vEndTrace = GetAbsOrigin() + (0.3*GetAbsVelocity());
UTIL_TraceLine( GetAbsOrigin(), vEndTrace, MASK_SHOT, NULL, COLLISION_GROUP_NONE, &trace );
if ( trace.fraction != 1.0f || trace.startsolid)
{
m_bSprayOn = false;
return;
}
PMaterialHandle handle = m_pFirePlasmaSpray->GetPMaterial( "sprites/plasmaember" );
for (int i=0;i<SPRAYS_PER_THINK;i++)
{
SimpleParticle *sParticle;
//Make a new particle
if ( random->RandomInt( 0, 2 ) == 0 )
{
float ranx = random->RandomFloat( -28.0f, 28.0f );
float rany = random->RandomFloat( -28.0f, 28.0f );
float ranz = random->RandomFloat( -28.0f, 28.0f );
Vector vNewPos = GetAbsOrigin();
Vector vAdd = Vector(GetAbsAngles().x,GetAbsAngles().y,GetAbsAngles().z)*random->RandomFloat(-60,120);
vNewPos += vAdd;
sParticle = (SimpleParticle *) m_pFirePlasmaSpray->AddParticle( sizeof(SimpleParticle), handle, vNewPos );
sParticle->m_flLifetime = 0.0f;
sParticle->m_flDieTime = PLASMASPARK_LIFETIME;
sParticle->m_vecVelocity = GetAbsVelocity();
sParticle->m_vecVelocity.x += ranx;
sParticle->m_vecVelocity.y += rany;
sParticle->m_vecVelocity.z += ranz;
m_pFirePlasmaSpray->m_pOwner = this;
}
}
SetNextClientThink(gpGlobals->curtime + 0.05);
}
IMPLEMENT_CLIENTCLASS_DT(C_PlasmaBeamNode, DT_PlasmaBeamNode, CPlasmaBeamNode )
RecvPropVector (RECVINFO(m_vecVelocity), 0, RecvProxy_LocalVelocity),
RecvPropInt (RECVINFO(m_bSprayOn)),
END_RECV_TABLE()

View File

@@ -0,0 +1,340 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
//=============================================================================//
#include "cbase.h"
#include "c_prop_combine_ball.h"
#include "materialsystem/imaterial.h"
#include "model_types.h"
#include "c_physicsprop.h"
#include "c_te_effect_dispatch.h"
#include "fx_quad.h"
#include "fx.h"
#include "clienteffectprecachesystem.h"
#include "view.h"
#include "view_scene.h"
#include "beamdraw.h"
// Precache our effects
CLIENTEFFECT_REGISTER_BEGIN( PrecacheEffectCombineBall )
CLIENTEFFECT_MATERIAL( "effects/ar2_altfire1" )
CLIENTEFFECT_MATERIAL( "effects/ar2_altfire1b" )
CLIENTEFFECT_MATERIAL( "effects/combinemuzzle1_nocull" )
CLIENTEFFECT_MATERIAL( "effects/combinemuzzle2_nocull" )
CLIENTEFFECT_MATERIAL( "effects/combinemuzzle1" )
CLIENTEFFECT_MATERIAL( "effects/ar2_altfire1" )
CLIENTEFFECT_MATERIAL( "effects/ar2_altfire1b" )
CLIENTEFFECT_REGISTER_END()
IMPLEMENT_CLIENTCLASS_DT( C_PropCombineBall, DT_PropCombineBall, CPropCombineBall )
RecvPropBool( RECVINFO( m_bEmit ) ),
RecvPropFloat( RECVINFO( m_flRadius ) ),
RecvPropBool( RECVINFO( m_bHeld ) ),
RecvPropBool( RECVINFO( m_bLaunched ) ),
END_RECV_TABLE()
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
C_PropCombineBall::C_PropCombineBall( void )
{
m_pFlickerMaterial = NULL;
m_pBodyMaterial = NULL;
m_pBlurMaterial = NULL;
}
//-----------------------------------------------------------------------------
// Purpose:
// Input : updateType -
//-----------------------------------------------------------------------------
void C_PropCombineBall::OnDataChanged( DataUpdateType_t updateType )
{
BaseClass::OnDataChanged( updateType );
if ( updateType == DATA_UPDATE_CREATED )
{
m_vecLastOrigin = GetAbsOrigin();
InitMaterials();
}
}
//-----------------------------------------------------------------------------
// Purpose:
// Output : RenderGroup_t
//-----------------------------------------------------------------------------
RenderGroup_t C_PropCombineBall::GetRenderGroup( void )
{
return RENDER_GROUP_TRANSLUCENT_ENTITY;
}
//-----------------------------------------------------------------------------
// Purpose: Cache the material handles
// Output : Returns true on success, false on failure.
//-----------------------------------------------------------------------------
bool C_PropCombineBall::InitMaterials( void )
{
// Motion blur
if ( m_pBlurMaterial == NULL )
{
m_pBlurMaterial = materials->FindMaterial( "effects/ar2_altfire1b", NULL, false );
if ( m_pBlurMaterial == NULL )
return false;
}
// Main body of the ball
if ( m_pBodyMaterial == NULL )
{
m_pBodyMaterial = materials->FindMaterial( "effects/ar2_altfire1", NULL, false );
if ( m_pBodyMaterial == NULL )
return false;
}
// Flicker material
if ( m_pFlickerMaterial == NULL )
{
m_pFlickerMaterial = materials->FindMaterial( "effects/combinemuzzle1", NULL, false );
if ( m_pFlickerMaterial == NULL )
return false;
}
return true;
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void C_PropCombineBall::DrawMotionBlur( void )
{
float color[3];
Vector vecDir = GetAbsOrigin() - m_vecLastOrigin;
float speed = VectorNormalize( vecDir );
speed = clamp( speed, 0, 32 );
float stepSize = MIN( ( speed * 0.5f ), 4.0f );
Vector spawnPos = GetAbsOrigin();
Vector spawnStep = -vecDir * stepSize;
float base = RemapValClamped( speed, 4, 32, 0.0f, 1.0f );
CMatRenderContextPtr pRenderContext( materials );
pRenderContext->Bind( m_pBlurMaterial );
// Draw the motion blurred trail
for ( int i = 0; i < 8; i++ )
{
spawnPos += spawnStep;
color[0] = color[1] = color[2] = base * ( 1.0f - ( (float) i / 12.0f ) );
DrawHalo( m_pBlurMaterial, spawnPos, m_flRadius, color );
}
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void C_PropCombineBall::DrawFlicker( void )
{
float rand1 = random->RandomFloat( 0.2f, 0.3f );
float rand2 = random->RandomFloat( 1.5f, 2.5f );
if ( gpGlobals->frametime == 0.0f )
{
rand1 = 0.2f;
rand2 = 1.5f;
}
float color[3];
color[0] = color[1] = color[2] = rand1;
// Draw the flickering glow
CMatRenderContextPtr pRenderContext( materials );
pRenderContext->Bind( m_pFlickerMaterial );
DrawHalo( m_pFlickerMaterial, GetAbsOrigin(), m_flRadius * rand2, color );
}
//-----------------------------------------------------------------------------
// Purpose:
// Input : pMaterial -
// source -
// color -
//-----------------------------------------------------------------------------
void DrawHaloOriented( const Vector& source, float scale, float const *color, float roll )
{
Vector point, screen;
CMatRenderContextPtr pRenderContext( materials );
IMesh* pMesh = pRenderContext->GetDynamicMesh();
CMeshBuilder meshBuilder;
meshBuilder.Begin( pMesh, MATERIAL_QUADS, 1 );
// Transform source into screen space
ScreenTransform( source, screen );
Vector right, up;
float sr, cr;
SinCos( roll, &sr, &cr );
for ( int i = 0; i < 3; i++ )
{
right[i] = CurrentViewRight()[i] * cr + CurrentViewUp()[i] * sr;
up[i] = CurrentViewRight()[i] * -sr + CurrentViewUp()[i] * cr;
}
meshBuilder.Color3fv (color);
meshBuilder.TexCoord2f (0, 0, 1);
VectorMA (source, -scale, up, point);
VectorMA (point, -scale, right, point);
meshBuilder.Position3fv (point.Base());
meshBuilder.AdvanceVertex();
meshBuilder.Color3fv (color);
meshBuilder.TexCoord2f (0, 0, 0);
VectorMA (source, scale, up, point);
VectorMA (point, -scale, right, point);
meshBuilder.Position3fv (point.Base());
meshBuilder.AdvanceVertex();
meshBuilder.Color3fv (color);
meshBuilder.TexCoord2f (0, 1, 0);
VectorMA (source, scale, up, point);
VectorMA (point, scale, right, point);
meshBuilder.Position3fv (point.Base());
meshBuilder.AdvanceVertex();
meshBuilder.Color3fv (color);
meshBuilder.TexCoord2f (0, 1, 1);
VectorMA (source, -scale, up, point);
VectorMA (point, scale, right, point);
meshBuilder.Position3fv (point.Base());
meshBuilder.AdvanceVertex();
meshBuilder.End();
pMesh->Draw();
}
//-----------------------------------------------------------------------------
// Purpose:
// Input : flags -
// Output : int
//-----------------------------------------------------------------------------
int C_PropCombineBall::DrawModel( int flags )
{
if ( !m_bEmit )
return 0;
// Make sure our materials are cached
if ( !InitMaterials() )
{
//NOTENOTE: This means that a material was not found for the combine ball, so it may not render!
AssertOnce( 0 );
return 0;
}
// Draw the flickering overlay
DrawFlicker();
// Draw the motion blur from movement
if ( m_bHeld || m_bLaunched )
{
DrawMotionBlur();
}
// Draw the model if we're being held
if ( m_bHeld )
{
QAngle angles;
VectorAngles( -CurrentViewForward(), angles );
// Always orient towards the camera!
SetAbsAngles( angles );
BaseClass::DrawModel( flags );
}
else
{
float color[3];
color[0] = color[1] = color[2] = 1.0f;
float sinOffs = 1.0f * sin( gpGlobals->curtime * 25 );
float roll = SpawnTime();
// Draw the main ball body
CMatRenderContextPtr pRenderContext( materials );
pRenderContext->Bind( m_pBodyMaterial, (C_BaseEntity*) this );
DrawHaloOriented( GetAbsOrigin(), m_flRadius + sinOffs, color, roll );
}
m_vecLastOrigin = GetAbsOrigin();
return 1;
}
//-----------------------------------------------------------------------------
// Purpose:
// Input : &data -
//-----------------------------------------------------------------------------
void CombineBallImpactCallback( const CEffectData &data )
{
// Quick flash
FX_AddQuad( data.m_vOrigin,
data.m_vNormal,
data.m_flRadius * 10.0f,
0,
0.75f,
1.0f,
0.0f,
0.4f,
random->RandomInt( 0, 360 ),
0,
Vector( 1.0f, 1.0f, 1.0f ),
0.25f,
"effects/combinemuzzle1_nocull",
(FXQUAD_BIAS_SCALE|FXQUAD_BIAS_ALPHA) );
// Lingering burn
FX_AddQuad( data.m_vOrigin,
data.m_vNormal,
data.m_flRadius * 2.0f,
data.m_flRadius * 4.0f,
0.75f,
1.0f,
0.0f,
0.4f,
random->RandomInt( 0, 360 ),
0,
Vector( 1.0f, 1.0f, 1.0f ),
0.5f,
"effects/combinemuzzle2_nocull",
(FXQUAD_BIAS_SCALE|FXQUAD_BIAS_ALPHA) );
// Throw sparks
FX_ElectricSpark( data.m_vOrigin, 2, 1, &data.m_vNormal );
}
DECLARE_CLIENT_EFFECT( "cball_bounce", CombineBallImpactCallback );
//-----------------------------------------------------------------------------
// Purpose:
// Input : &data -
//-----------------------------------------------------------------------------
void CombineBallExplosionCallback( const CEffectData &data )
{
Vector normal(0,0,1);
// Throw sparks
FX_ElectricSpark( data.m_vOrigin, 4, 1, &normal );
}
DECLARE_CLIENT_EFFECT( "cball_explode", CombineBallExplosionCallback );

View File

@@ -0,0 +1,45 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
//=============================================================================//
#ifndef CPROPCOMBINEBALL_H_
#define CPROPCOMBINEBALL_H_
#ifdef _WIN32
#pragma once
#endif
class C_PropCombineBall : public C_BaseAnimating
{
DECLARE_CLASS( C_PropCombineBall, C_BaseAnimating );
DECLARE_CLIENTCLASS();
public:
C_PropCombineBall( void );
virtual RenderGroup_t GetRenderGroup( void );
virtual void OnDataChanged( DataUpdateType_t updateType );
virtual int DrawModel( int flags );
protected:
void DrawMotionBlur( void );
void DrawFlicker( void );
virtual bool InitMaterials( void );
Vector m_vecLastOrigin;
bool m_bEmit;
float m_flRadius;
bool m_bHeld;
bool m_bLaunched;
IMaterial *m_pFlickerMaterial;
IMaterial *m_pBodyMaterial;
IMaterial *m_pBlurMaterial;
};
#endif

View File

@@ -0,0 +1,306 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
// $NoKeywords: $
//=============================================================================//
#include "cbase.h"
#include "particlemgr.h"
#include "particle_prototype.h"
#include "particle_util.h"
#include "c_te_particlesystem.h"
#include "fx.h"
#include "fx_quad.h"
#include "clienteffectprecachesystem.h"
// memdbgon must be the last include file in a .cpp file!!!
#include "tier0/memdbgon.h"
// ==============================================
// Rotorwash particle emitter
// ==============================================
#ifndef _XBOX
class WashEmitter : public CSimpleEmitter
{
public:
WashEmitter( const char *pDebugName ) : CSimpleEmitter( pDebugName ) {}
static WashEmitter *Create( const char *pDebugName )
{
return new WashEmitter( pDebugName );
}
void UpdateVelocity( SimpleParticle *pParticle, float timeDelta )
{
// Float up when lifetime is half gone.
pParticle->m_vecVelocity[ 2 ] += 64 * timeDelta;
// FIXME: optimize this....
pParticle->m_vecVelocity *= ExponentialDecay( 0.8, 0.05, timeDelta );
}
virtual float UpdateRoll( SimpleParticle *pParticle, float timeDelta )
{
pParticle->m_flRoll += pParticle->m_flRollDelta * timeDelta;
pParticle->m_flRollDelta += pParticle->m_flRollDelta * ( timeDelta * -2.0f );
//Cap the minimum roll
if ( fabs( pParticle->m_flRollDelta ) < 0.5f )
{
pParticle->m_flRollDelta = ( pParticle->m_flRollDelta > 0.0f ) ? 0.5f : -0.5f;
}
return pParticle->m_flRoll;
}
virtual float UpdateAlpha( const SimpleParticle *pParticle )
{
return ( ((float)pParticle->m_uchStartAlpha/255.0f) * sin( M_PI * (pParticle->m_flLifetime / pParticle->m_flDieTime) ) );
}
private:
WashEmitter( const WashEmitter & );
};
#endif // !_XBOX
// ==============================================
// Rotorwash entity
// ==============================================
#define ROTORWASH_THINK_INTERVAL 0.1f
class C_RotorWashEmitter : public C_BaseEntity
{
public:
DECLARE_CLASS( C_RotorWashEmitter, C_BaseEntity );
DECLARE_CLIENTCLASS();
C_RotorWashEmitter( void );
virtual void OnDataChanged( DataUpdateType_t updateType );
virtual void ClientThink( void );
protected:
float m_flAltitude;
PMaterialHandle m_hWaterMaterial[2];
#ifndef _XBOX
void InitSpawner( void );
CSmartPtr<WashEmitter> m_pSimple;
#endif // !XBOX
};
IMPLEMENT_CLIENTCLASS_DT( C_RotorWashEmitter, DT_RotorWashEmitter, CRotorWashEmitter)
RecvPropFloat(RECVINFO(m_flAltitude)),
END_RECV_TABLE()
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
C_RotorWashEmitter::C_RotorWashEmitter( void )
{
#ifndef _XBOX
m_pSimple = NULL;
m_hWaterMaterial[0] = NULL;
m_hWaterMaterial[1] = NULL;
#endif // !_XBOX
}
#ifndef _XBOX
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void C_RotorWashEmitter::InitSpawner( void )
{
if ( m_pSimple.IsValid() )
return;
m_pSimple = WashEmitter::Create( "wash" );
m_pSimple->SetNearClip( 128, 256 );
}
#endif // !XBOX
//-----------------------------------------------------------------------------
// Purpose:
// Input : updateType -
//-----------------------------------------------------------------------------
void C_RotorWashEmitter::OnDataChanged( DataUpdateType_t updateType )
{
BaseClass::OnDataChanged( updateType );
if ( updateType == DATA_UPDATE_CREATED )
{
SetNextClientThink( gpGlobals->curtime + ROTORWASH_THINK_INTERVAL );
#ifndef _XBOX
InitSpawner();
#endif // !XBOX
}
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void C_RotorWashEmitter::ClientThink( void )
{
SetNextClientThink( gpGlobals->curtime + ROTORWASH_THINK_INTERVAL );
trace_t tr;
UTIL_TraceLine( GetAbsOrigin(), GetAbsOrigin()+(Vector(0, 0, -1024)), (MASK_SOLID_BRUSHONLY|CONTENTS_WATER|CONTENTS_SLIME), NULL, COLLISION_GROUP_NONE, &tr );
if ( /*!m_bIgnoreSolid && */(tr.fraction == 1.0f || tr.startsolid || tr.allsolid) )
return;
// If we hit the skybox, don't do it either
if ( tr.surface.flags & SURF_SKY )
return;
float heightScale = RemapValClamped( tr.fraction * 1024, 512, 1024, 1.0f, 0.0f );
Vector vecDustColor;
if ( tr.contents & CONTENTS_WATER )
{
vecDustColor.x = 0.8f;
vecDustColor.y = 0.8f;
vecDustColor.z = 0.75f;
}
else if ( tr.contents & CONTENTS_SLIME )
{
vecDustColor.x = 0.6f;
vecDustColor.y = 0.5f;
vecDustColor.z = 0.15f;
}
else
{
vecDustColor.x = 0.35f;
vecDustColor.y = 0.3f;
vecDustColor.z = 0.25f;
}
#ifndef _XBOX
InitSpawner();
if ( m_pSimple.IsValid() == false )
return;
m_pSimple->SetSortOrigin( GetAbsOrigin() );
PMaterialHandle *hMaterial;
// Cache and set our material based on the surface we're over (ie. water)
if ( tr.contents & (CONTENTS_WATER|CONTENTS_SLIME) )
{
if ( m_hWaterMaterial[0] == NULL )
{
m_hWaterMaterial[0] = m_pSimple->GetPMaterial("effects/splash1");
m_hWaterMaterial[1] = m_pSimple->GetPMaterial("effects/splash2");
}
hMaterial = m_hWaterMaterial;
}
else
{
hMaterial = g_Mat_DustPuff;
}
#endif // !XBOX
// If we're above water, make ripples
if ( tr.contents & (CONTENTS_WATER|CONTENTS_SLIME) )
{
float flScale = random->RandomFloat( 7.5f, 8.5f );
Vector color = Vector( 0.8f, 0.8f, 0.75f );
Vector startPos = tr.endpos + Vector(0,0,8);
Vector endPos = tr.endpos + Vector(0,0,-64);
if ( tr.fraction < 1.0f )
{
//Add a ripple quad to the surface
FX_AddQuad( tr.endpos + ( tr.plane.normal * 0.5f ),
tr.plane.normal,
64.0f * flScale,
128.0f * flScale,
0.8f,
0.75f * heightScale,
0.0f,
0.75f,
random->RandomFloat( 0, 360 ),
random->RandomFloat( -2.0f, 2.0f ),
vecDustColor,
0.2f,
"effects/splashwake3",
(FXQUAD_BIAS_SCALE|FXQUAD_BIAS_ALPHA) );
}
}
#ifndef _XBOX
int numRingSprites = 32;
float yaw = random->RandomFloat( 0, 2*M_PI ); // Randomly placed on the unit circle
float yawIncr = (2*M_PI) / numRingSprites;
Vector vecForward;
Vector offset;
SimpleParticle *pParticle;
// Draw the rings
for ( int i = 0; i < numRingSprites; i++ )
{
// Get our x,y on the unit circle
SinCos( yaw, &vecForward.y, &vecForward.x );
// Increment ahead
yaw += yawIncr;
// @NOTE toml (3-28-07): broke out following expression because vc2005 optimizer was screwing up in presence of SinCos inline assembly. Would also
// go away if offset were referenced below as in the AddLineOverlay()
//offset = ( RandomVector( -4.0f, 4.0f ) + tr.endpos ) + ( vecForward * 128.0f );
offset = vecForward * 128.0f;
offset += tr.endpos + RandomVector( -4.0f, 4.0f );
pParticle = (SimpleParticle *) m_pSimple->AddParticle( sizeof(SimpleParticle), hMaterial[random->RandomInt(0,1)], offset );
if ( pParticle != NULL )
{
pParticle->m_flLifetime = 0.0f;
pParticle->m_flDieTime = random->RandomFloat( 0.25f, 1.0f );
pParticle->m_vecVelocity = vecForward * random->RandomFloat( 1000, 1500 );
#if __EXPLOSION_DEBUG
debugoverlay->AddLineOverlay( m_vecOrigin, m_vecOrigin + pParticle->m_vecVelocity, 255, 0, 0, false, 3 );
#endif
if ( tr.contents & CONTENTS_SLIME )
{
vecDustColor.x = random->RandomFloat( 0.4f, 0.6f );
vecDustColor.y = random->RandomFloat( 0.3f, 0.5f );
vecDustColor.z = random->RandomFloat( 0.1f, 0.2f );
}
pParticle->m_uchColor[0] = vecDustColor.x * 255.0f;
pParticle->m_uchColor[1] = vecDustColor.y * 255.0f;
pParticle->m_uchColor[2] = vecDustColor.z * 255.0f;
pParticle->m_uchStartSize = random->RandomInt( 16, 64 );
pParticle->m_uchEndSize = pParticle->m_uchStartSize * 4;
pParticle->m_uchStartAlpha = random->RandomFloat( 16, 32 ) * heightScale;
pParticle->m_uchEndAlpha = 0;
pParticle->m_flRoll = random->RandomInt( 0, 360 );
pParticle->m_flRollDelta = random->RandomFloat( -16.0f, 16.0f );
}
}
#endif // !XBOX
}

View File

@@ -0,0 +1,502 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
//=============================================================================//
#include "cbase.h"
#include "shareddefs.h"
#include "materialsystem/imesh.h"
#include "view.h"
#include "iviewrender.h"
#include "view_shared.h"
#include "viewrender.h"
#ifdef MAPBASE
#include "c_point_camera.h"
#endif
// memdbgon must be the last include file in a .cpp file!!!
#include "tier0/memdbgon.h"
extern IntroData_t *g_pIntroData;
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
class C_ScriptIntro : public C_BaseEntity
{
DECLARE_CLASS( C_ScriptIntro, C_BaseEntity );
public:
DECLARE_CLIENTCLASS();
C_ScriptIntro( void );
~C_ScriptIntro( void );
void PostDataUpdate( DataUpdateType_t updateType );
void ClientThink( void );
void CalculateFOV( void );
void CalculateAlpha( void );
public:
int m_iNextFOV;
int m_iFOV;
int m_iPrevFOV;
int m_iStartFOV;
float m_flNextFOVBlendTime;
float m_flFOVBlendStartTime;
bool m_bAlternateFOV;
// Our intro data block
IntroData_t m_IntroData;
private:
Vector m_vecCameraView;
QAngle m_vecCameraViewAngles;
int m_iBlendMode;
int m_iNextBlendMode;
float m_flNextBlendTime;
float m_flBlendStartTime;
bool m_bActive;
EHANDLE m_hCameraEntity;
#ifdef MAPBASE
bool m_bDrawSky;
bool m_bDrawSky2;
bool m_bUseEyePosition;
#endif
// Fades
float m_flFadeColor[3]; // Server's desired fade color
float m_flFadeAlpha; // Server's desired fade alpha
float m_flPrevServerFadeAlpha; // Previous server's desired fade alpha
float m_flFadeDuration; // Time it should take to reach the server's new fade alpha
float m_flFadeTimeStartedAt; // Time at which we last recieved a new desired fade alpha
float m_flFadeAlphaStartedAt; // Alpha at which we last received a new desired fade alpha
};
IMPLEMENT_CLIENTCLASS_DT( C_ScriptIntro, DT_ScriptIntro, CScriptIntro )
RecvPropVector( RECVINFO( m_vecCameraView ) ),
RecvPropVector( RECVINFO( m_vecCameraViewAngles ) ),
RecvPropInt( RECVINFO( m_iBlendMode ) ),
RecvPropInt( RECVINFO( m_iNextBlendMode ) ),
RecvPropFloat( RECVINFO( m_flNextBlendTime ) ),
RecvPropFloat( RECVINFO( m_flBlendStartTime ) ),
RecvPropBool( RECVINFO( m_bActive ) ),
#ifdef MAPBASE
RecvPropBool( RECVINFO( m_bDrawSky ) ),
RecvPropBool( RECVINFO( m_bDrawSky2 ) ),
RecvPropBool( RECVINFO( m_bUseEyePosition ) ),
#endif
// Fov & fov blends
RecvPropInt( RECVINFO( m_iFOV ) ),
RecvPropInt( RECVINFO( m_iNextFOV ) ),
RecvPropInt( RECVINFO( m_iStartFOV ) ),
RecvPropFloat( RECVINFO( m_flNextFOVBlendTime ) ),
RecvPropFloat( RECVINFO( m_flFOVBlendStartTime ) ),
RecvPropBool( RECVINFO( m_bAlternateFOV ) ),
// Fades
RecvPropFloat( RECVINFO( m_flFadeAlpha ) ),
RecvPropArray( RecvPropFloat( RECVINFO( m_flFadeColor[0] ) ), m_flFadeColor ),
RecvPropFloat( RECVINFO( m_flFadeDuration ) ),
RecvPropEHandle(RECVINFO(m_hCameraEntity)),
END_RECV_TABLE()
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
C_ScriptIntro::C_ScriptIntro( void )
{
m_bActive = false;
m_vecCameraView = vec3_origin;
m_vecCameraViewAngles = vec3_angle;
m_iBlendMode = 0;
m_iNextBlendMode = 0;
m_flNextBlendTime = 0;
m_flBlendStartTime = 0;
m_IntroData.m_playerViewFOV = 0;
m_flFadeAlpha = 0;
m_flPrevServerFadeAlpha = 0;
m_flFadeDuration = 0;
m_flFadeTimeStartedAt = 0;
m_flFadeAlphaStartedAt = 0;
m_hCameraEntity = NULL;
m_iPrevFOV = 0;
m_iStartFOV = 0;
g_pIntroData = NULL;
// Setup fade colors
m_IntroData.m_flCurrentFadeColor[0] = m_flFadeColor[0];
m_IntroData.m_flCurrentFadeColor[1] = m_flFadeColor[1];
m_IntroData.m_flCurrentFadeColor[2] = m_flFadeColor[2];
m_IntroData.m_flCurrentFadeColor[3] = m_flFadeAlpha;
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
C_ScriptIntro::~C_ScriptIntro( void )
{
g_pIntroData = NULL;
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void C_ScriptIntro::PostDataUpdate( DataUpdateType_t updateType )
{
BaseClass::PostDataUpdate( updateType );
SetNextClientThink( CLIENT_THINK_ALWAYS );
// Fill out the intro data
m_IntroData.m_vecCameraView = m_vecCameraView;
m_IntroData.m_vecCameraViewAngles = m_vecCameraViewAngles;
m_IntroData.m_Passes.SetCount( 0 );
#ifdef MAPBASE
m_IntroData.m_bDrawSky = m_bDrawSky;
#endif
// Find/Create our first pass
IntroDataBlendPass_t *pass1;
if ( m_IntroData.m_Passes.Count() == 0 )
{
pass1 = &m_IntroData.m_Passes[m_IntroData.m_Passes.AddToTail()];
}
else
{
pass1 = &m_IntroData.m_Passes[0];
}
Assert(pass1);
pass1->m_BlendMode = m_iBlendMode;
pass1->m_Alpha = 1.0f;
if ( m_vecCameraView == vec3_origin )
{
m_IntroData.m_bDrawPrimary = false;
}
else
{
m_IntroData.m_bDrawPrimary = true;
#ifdef MAPBASE
m_IntroData.m_bDrawSky2 = m_bDrawSky2;
// If it's a point_camera and it's ortho, send it to the intro data
// Change this code if the purpose of m_hCameraEntity in intro data ever goes beyond ortho
if ( m_hCameraEntity && Q_strncmp(m_hCameraEntity->GetClassname(), "point_camera", 12) == 0 )
{
C_PointCamera *pCamera = dynamic_cast<C_PointCamera*>(m_hCameraEntity.Get());
if (pCamera && pCamera->IsOrtho())
{
m_IntroData.m_hCameraEntity = m_hCameraEntity;
}
}
#endif
}
// If we're currently blending to a new mode, set the second pass
if ( m_flNextBlendTime > gpGlobals->curtime )
{
IntroDataBlendPass_t *pass2;
if ( m_IntroData.m_Passes.Count() < 2 )
{
pass2 = &m_IntroData.m_Passes[m_IntroData.m_Passes.AddToTail()];
//Msg("STARTED BLEND: Mode %d to %d.\n", m_IntroData.m_Passes[0].m_BlendMode, m_iNextBlendMode );
}
else
{
pass2 = &m_IntroData.m_Passes[1];
Assert( pass2->m_BlendMode == m_iNextBlendMode );
}
Assert(pass2);
pass2->m_BlendMode = m_iNextBlendMode;
pass2->m_Alpha = 0.0f;
}
else if ( m_IntroData.m_Passes.Count() == 2 )
{
C_BasePlayer *player = C_BasePlayer::GetLocalPlayer();
if ( !player )
return;
//Msg("FINISHED BLEND.\n");
m_IntroData.m_Passes.Remove(1);
}
// Set the introdata our data chunk
if ( m_bActive )
{
g_pIntroData = &m_IntroData;
}
else if ( g_pIntroData == &m_IntroData )
{
g_pIntroData = NULL;
}
// Update the fade color
m_IntroData.m_flCurrentFadeColor[0] = m_flFadeColor[0];
m_IntroData.m_flCurrentFadeColor[1] = m_flFadeColor[1];
m_IntroData.m_flCurrentFadeColor[2] = m_flFadeColor[2];
// Started fading?
if ( m_flFadeAlpha != m_flPrevServerFadeAlpha )
{
m_flFadeTimeStartedAt = gpGlobals->curtime;
m_flFadeAlphaStartedAt = m_IntroData.m_flCurrentFadeColor[3];
m_flPrevServerFadeAlpha = m_flFadeAlpha;
if ( !m_flFadeDuration )
{
m_flFadeDuration = 0.01;
}
//Msg("STARTING NEW FADE: alpha %.2f, duration %.2f.\n", m_flFadeAlpha, m_flFadeDuration );
}
if ( m_iPrevFOV != m_iFOV )
{
m_IntroData.m_playerViewFOV = m_iFOV;
m_iPrevFOV = m_iFOV;
}
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void C_ScriptIntro::ClientThink( void )
{
Assert( m_IntroData.m_Passes.Count() <= 2 );
if ( m_hCameraEntity )
{
#ifdef MAPBASE
if ( m_bUseEyePosition )
{
m_hCameraEntity->GetEyePosition( m_IntroData.m_vecCameraView, m_IntroData.m_vecCameraViewAngles );
}
else
{
m_IntroData.m_vecCameraView = m_hCameraEntity->GetAbsOrigin();
m_IntroData.m_vecCameraViewAngles = m_hCameraEntity->GetAbsAngles();
}
#else
m_IntroData.m_vecCameraView = m_hCameraEntity->GetAbsOrigin();
m_IntroData.m_vecCameraViewAngles = m_hCameraEntity->GetAbsAngles();
#endif
}
CalculateFOV();
CalculateAlpha();
// Calculate the blend levels of each pass
float flPerc = 1.0;
if ( (m_flNextBlendTime - m_flBlendStartTime) != 0 )
{
flPerc = clamp( (gpGlobals->curtime - m_flBlendStartTime) / (m_flNextBlendTime - m_flBlendStartTime), 0, 1 );
}
// Detect when we're finished blending
if ( flPerc >= 1.0 )
{
if ( m_IntroData.m_Passes.Count() == 2 )
{
// We're done blending
m_IntroData.m_Passes[0].m_BlendMode = m_IntroData.m_Passes[1].m_BlendMode;
m_IntroData.m_Passes[0].m_Alpha = 1.0;
m_IntroData.m_Passes.Remove(1);
//Msg("FINISHED BLEND.\n");
}
else
{
m_IntroData.m_Passes[0].m_Alpha = 1.0f;
}
return;
}
/*
if ( m_flNextBlendTime >= gpGlobals->curtime )
{
Msg("INTRO BLENDING: Blending from mode %d to %d.\n", m_IntroData.m_Passes[0].m_BlendMode, m_IntroData.m_Passes[1].m_BlendMode );
Msg(" curtime %.2f StartedAt %.2f FinishAt: %.2f\n", gpGlobals->curtime, m_flBlendStartTime, m_flNextBlendTime );
Msg(" Perc: %.2f\n", flPerc );
}
*/
if ( m_IntroData.m_Passes.Count() == 2 )
{
m_IntroData.m_Passes[0].m_Alpha = 1.0 - flPerc;
m_IntroData.m_Passes[1].m_Alpha = flPerc;
}
else
{
m_IntroData.m_Passes[0].m_Alpha = 1.0 - flPerc;
}
}
extern float ScriptInfo_CalculateFOV( float flFOVBlendStartTime, float flNextFOVBlendTime, int nFOV, int nNextFOV, bool bSplineRamp );
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void C_ScriptIntro::CalculateFOV( void )
{
// We're past our blending time so we're at our target
if ( m_flNextFOVBlendTime >= gpGlobals->curtime )
{
// Calculate where we're at
m_IntroData.m_playerViewFOV = ScriptInfo_CalculateFOV( m_flFOVBlendStartTime, m_flNextFOVBlendTime, m_iStartFOV, m_iNextFOV, m_bAlternateFOV );
}
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void C_ScriptIntro::CalculateAlpha( void )
{
// Fill out the fade alpha
float flNewAlpha = RemapValClamped( gpGlobals->curtime, m_flFadeTimeStartedAt, m_flFadeTimeStartedAt + m_flFadeDuration, m_flFadeAlphaStartedAt, m_flFadeAlpha );
/*
if ( m_IntroData.m_flCurrentFadeColor[3] != flNewAlpha )
{
Msg("INTRO FADING: curtime %.2f StartedAt %.2f Duration: %.2f\n", gpGlobals->curtime, m_flFadeTimeStartedAt, m_flFadeDuration );
Msg(" TimePassed %.2f Alpha: %.2f\n", RemapValClamped( gpGlobals->curtime, m_flFadeTimeStartedAt, m_flFadeTimeStartedAt + m_flFadeDuration, 0.0, 1.0 ), m_IntroData.m_flCurrentFadeColor[3] );
}
*/
m_IntroData.m_flCurrentFadeColor[3] = flNewAlpha;
}
#ifdef MAPBASE
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
class C_PlayerViewProxy : public C_BaseEntity
{
DECLARE_CLASS( C_PlayerViewProxy, C_BaseEntity );
public:
DECLARE_CLIENTCLASS();
Vector EyePosition( void ); // position of eyes
const QAngle &EyeAngles( void ); // Direction of eyes in world space
void GetEyePosition( Vector &vecOrigin, QAngle &angAngles );
const QAngle &LocalEyeAngles( void ); // Direction of eyes
Vector EarPosition( void ); // position of ears
#ifdef MAPBASE_MP
C_BasePlayer *GetPlayer() { return m_bEnabled ? (m_hPlayer.Get() ? m_hPlayer.Get() : C_BasePlayer::GetLocalPlayer()) : NULL; }
#else
C_BasePlayer *GetPlayer() { return m_bEnabled ? C_BasePlayer::GetLocalPlayer() : NULL; }
#endif
public:
#ifdef MAPBASE_MP
CHandle<C_BasePlayer> m_hPlayer;
#endif
bool m_bEnabled;
};
IMPLEMENT_CLIENTCLASS_DT( C_PlayerViewProxy, DT_PlayerViewProxy, CPlayerViewProxy )
#ifdef MAPBASE_MP
RecvPropEHandle( RECVINFO( m_hPlayer ) ),
#endif
RecvPropBool( RECVINFO( m_bEnabled ) ),
END_RECV_TABLE()
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
Vector C_PlayerViewProxy::EyePosition( void )
{
C_BasePlayer *pPlayer = GetPlayer();
if (pPlayer)
{
//Vector vecPlayerOffset = m_hPlayer.Get()->EyePosition() - m_hPlayer.Get()->GetAbsOrigin();
//return GetAbsOrigin() + vecPlayerOffset;
Vector vecOrigin;
QAngle angAngles;
float fldummy;
pPlayer->CalcView( vecOrigin, angAngles, fldummy, fldummy, fldummy );
return GetAbsOrigin() + (vecOrigin - pPlayer->GetAbsOrigin());
}
else
return BaseClass::EyePosition();
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
const QAngle &C_PlayerViewProxy::EyeAngles( void )
{
C_BasePlayer *pPlayer = GetPlayer();
if (pPlayer)
{
Vector vecOrigin;
static QAngle angAngles;
float fldummy;
pPlayer->CalcView( vecOrigin, angAngles, fldummy, fldummy, fldummy );
angAngles = GetAbsAngles() + (angAngles - pPlayer->GetAbsAngles());
return angAngles;
//return m_hPlayer.Get()->EyeAngles();
}
else
return BaseClass::EyeAngles();
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void C_PlayerViewProxy::GetEyePosition( Vector &vecOrigin, QAngle &angAngles )
{
C_BasePlayer *pPlayer = GetPlayer();
if (pPlayer)
{
float fldummy;
pPlayer->CalcView( vecOrigin, angAngles, fldummy, fldummy, fldummy );
vecOrigin = GetAbsOrigin() + (vecOrigin - pPlayer->GetAbsOrigin());
angAngles = GetAbsAngles() + (angAngles - pPlayer->GetAbsAngles());
}
else
{
BaseClass::GetEyePosition( vecOrigin, angAngles );
}
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
const QAngle &C_PlayerViewProxy::LocalEyeAngles( void )
{
C_BasePlayer *pPlayer = GetPlayer();
if (pPlayer) {
static QAngle angAngles;
angAngles = GetAbsAngles() + (pPlayer->LocalEyeAngles() - pPlayer->GetAbsAngles());
return angAngles;
}
else
return BaseClass::LocalEyeAngles();
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
Vector C_PlayerViewProxy::EarPosition( void )
{
C_BasePlayer *pPlayer = GetPlayer();
if (pPlayer)
{
Vector vecPlayerOffset = pPlayer->GetAbsOrigin() - pPlayer->EarPosition();
return GetAbsOrigin() + vecPlayerOffset;
}
else
return BaseClass::EarPosition();
}
#endif

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,110 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
// $NoKeywords: $
//===========================================================================//
#include "cbase.h"
#include "c_te_particlesystem.h"
#include "fx.h"
#include "ragdollexplosionenumerator.h"
#include "tier1/KeyValues.h"
#include "toolframework_client.h"
// memdbgon must be the last include file in a .cpp file!!!
#include "tier0/memdbgon.h"
//-----------------------------------------------------------------------------
// Purpose: Concussive explosion entity
//-----------------------------------------------------------------------------
class C_TEConcussiveExplosion : public C_TEParticleSystem
{
public:
DECLARE_CLASS( C_TEConcussiveExplosion, C_TEParticleSystem );
DECLARE_CLIENTCLASS();
virtual void PostDataUpdate( DataUpdateType_t updateType );
void AffectRagdolls( void );
Vector m_vecNormal;
float m_flScale;
int m_nRadius;
int m_nMagnitude;
};
//-----------------------------------------------------------------------------
// Networking
//-----------------------------------------------------------------------------
IMPLEMENT_CLIENTCLASS_EVENT_DT( C_TEConcussiveExplosion, DT_TEConcussiveExplosion, CTEConcussiveExplosion )
RecvPropVector( RECVINFO(m_vecNormal)),
RecvPropFloat( RECVINFO(m_flScale)),
RecvPropInt( RECVINFO(m_nRadius)),
RecvPropInt( RECVINFO(m_nMagnitude)),
END_RECV_TABLE()
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void C_TEConcussiveExplosion::AffectRagdolls( void )
{
if ( ( m_nRadius == 0 ) || ( m_nMagnitude == 0 ) )
return;
CRagdollExplosionEnumerator ragdollEnum( m_vecOrigin, m_nRadius, m_nMagnitude );
partition->EnumerateElementsInSphere( PARTITION_CLIENT_RESPONSIVE_EDICTS, m_vecOrigin, m_nRadius, false, &ragdollEnum );
}
//-----------------------------------------------------------------------------
// Recording
//-----------------------------------------------------------------------------
static inline void RecordConcussiveExplosion( const Vector& start, const Vector &vecDirection )
{
if ( !ToolsEnabled() )
return;
if ( clienttools->IsInRecordingMode() )
{
KeyValues *msg = new KeyValues( "TempEntity" );
msg->SetInt( "te", TE_CONCUSSIVE_EXPLOSION );
msg->SetString( "name", "TE_ConcussiveExplosion" );
msg->SetFloat( "time", gpGlobals->curtime );
msg->SetFloat( "originx", start.x );
msg->SetFloat( "originy", start.y );
msg->SetFloat( "originz", start.z );
msg->SetFloat( "directionx", vecDirection.x );
msg->SetFloat( "directiony", vecDirection.y );
msg->SetFloat( "directionz", vecDirection.z );
ToolFramework_PostToolMessage( HTOOLHANDLE_INVALID, msg );
msg->deleteThis();
}
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void C_TEConcussiveExplosion::PostDataUpdate( DataUpdateType_t updateType )
{
AffectRagdolls();
FX_ConcussiveExplosion( m_vecOrigin, m_vecNormal );
RecordConcussiveExplosion( m_vecOrigin, m_vecNormal );
}
void TE_ConcussiveExplosion( IRecipientFilter& filter, float delay, KeyValues *pKeyValues )
{
Vector vecOrigin, vecDirection;
vecOrigin.x = pKeyValues->GetFloat( "originx" );
vecOrigin.y = pKeyValues->GetFloat( "originy" );
vecOrigin.z = pKeyValues->GetFloat( "originz" );
vecDirection.x = pKeyValues->GetFloat( "directionx" );
vecDirection.y = pKeyValues->GetFloat( "directiony" );
vecDirection.z = pKeyValues->GetFloat( "directionz" );
FX_ConcussiveExplosion( vecOrigin, vecDirection );
}

View File

@@ -0,0 +1,414 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose: Flare effects
//
// $NoKeywords: $
//=============================================================================//
#include "cbase.h"
#include "clienteffectprecachesystem.h"
#include "particles_simple.h"
#include "iefx.h"
#include "dlight.h"
#include "view.h"
#include "fx.h"
#include "clientsideeffects.h"
#include "c_pixel_visibility.h"
// memdbgon must be the last include file in a .cpp file!!!
#include "tier0/memdbgon.h"
//Precahce the effects
CLIENTEFFECT_REGISTER_BEGIN( PrecacheEffectFlares )
CLIENTEFFECT_MATERIAL( "effects/redflare" )
CLIENTEFFECT_MATERIAL( "effects/yellowflare" )
CLIENTEFFECT_MATERIAL( "effects/yellowflare_noz" )
CLIENTEFFECT_REGISTER_END()
class C_Flare : public C_BaseCombatCharacter, CSimpleEmitter
{
public:
DECLARE_CLASS( C_Flare, C_BaseCombatCharacter );
DECLARE_CLIENTCLASS();
C_Flare();
void OnDataChanged( DataUpdateType_t updateType );
void Update( float timeDelta );
void NotifyDestroyParticle( Particle* pParticle );
void NotifyShouldTransmit( ShouldTransmitState_t state );
void RestoreResources( void );
float m_flTimeBurnOut;
float m_flScale;
bool m_bLight;
bool m_bSmoke;
bool m_bPropFlare;
pixelvis_handle_t m_queryHandle;
private:
C_Flare( const C_Flare & );
TimedEvent m_teSmokeSpawn;
int m_iAttachment;
SimpleParticle *m_pParticle[2];
};
IMPLEMENT_CLIENTCLASS_DT( C_Flare, DT_Flare, CFlare )
RecvPropFloat( RECVINFO( m_flTimeBurnOut ) ),
RecvPropFloat( RECVINFO( m_flScale ) ),
RecvPropInt( RECVINFO( m_bLight ) ),
RecvPropInt( RECVINFO( m_bSmoke ) ),
RecvPropInt( RECVINFO( m_bPropFlare ) ),
END_RECV_TABLE()
//-----------------------------------------------------------------------------
// Constructor
//-----------------------------------------------------------------------------
C_Flare::C_Flare() : CSimpleEmitter( "C_Flare" )
{
m_pParticle[0] = NULL;
m_pParticle[1] = NULL;
m_flTimeBurnOut = 0.0f;
m_bLight = true;
m_bSmoke = true;
m_bPropFlare = false;
SetDynamicallyAllocated( false );
m_queryHandle = 0;
m_iAttachment = -1;
}
//-----------------------------------------------------------------------------
// Purpose:
// Input : state -
//-----------------------------------------------------------------------------
void C_Flare::NotifyShouldTransmit( ShouldTransmitState_t state )
{
if ( state == SHOULDTRANSMIT_END )
{
AddEffects( EF_NODRAW );
}
else if ( state == SHOULDTRANSMIT_START )
{
RemoveEffects( EF_NODRAW );
}
BaseClass::NotifyShouldTransmit( state );
}
//-----------------------------------------------------------------------------
// Purpose:
// Input : bool -
//-----------------------------------------------------------------------------
void C_Flare::OnDataChanged( DataUpdateType_t updateType )
{
if ( updateType == DATA_UPDATE_CREATED )
{
SetSortOrigin( GetAbsOrigin() );
if ( m_bSmoke )
{
m_teSmokeSpawn.Init( 8 );
}
}
BaseClass::OnDataChanged( updateType );
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void C_Flare::RestoreResources( void )
{
if ( m_pParticle[0] == NULL )
{
m_pParticle[0] = (SimpleParticle *) AddParticle( sizeof( SimpleParticle ), GetPMaterial( "effects/redflare" ), GetAbsOrigin() );
if ( m_pParticle[0] != NULL )
{
m_pParticle[0]->m_uchColor[0] = m_pParticle[0]->m_uchColor[1] = m_pParticle[0]->m_uchColor[2] = 0;
m_pParticle[0]->m_flRoll = random->RandomInt( 0, 360 );
m_pParticle[0]->m_flRollDelta = random->RandomFloat( 1.0f, 4.0f );
m_pParticle[0]->m_flLifetime = 0.0f;
m_pParticle[0]->m_flDieTime = 10.0f;
}
else
{
Assert(0);
}
}
if ( m_pParticle[1] == NULL )
{
m_pParticle[1] = (SimpleParticle *) AddParticle( sizeof( SimpleParticle ), GetPMaterial( "effects/yellowflare_noz" ), GetAbsOrigin() );
if ( m_pParticle[1] != NULL )
{
m_pParticle[1]->m_uchColor[0] = m_pParticle[1]->m_uchColor[1] = m_pParticle[1]->m_uchColor[2] = 0;
m_pParticle[1]->m_flRoll = random->RandomInt( 0, 360 );
m_pParticle[1]->m_flRollDelta = random->RandomFloat( 1.0f, 4.0f );
m_pParticle[1]->m_flLifetime = 0.0f;
m_pParticle[1]->m_flDieTime = 10.0f;
}
else
{
Assert(0);
}
}
}
//-----------------------------------------------------------------------------
// Purpose:
// Input : pParticle -
//-----------------------------------------------------------------------------
void C_Flare::NotifyDestroyParticle( Particle* pParticle )
{
if ( pParticle == m_pParticle[0] )
{
m_pParticle[0] = NULL;
}
if ( pParticle == m_pParticle[1] )
{
m_pParticle[1] = NULL;
}
CSimpleEmitter::NotifyDestroyParticle( pParticle );
}
//-----------------------------------------------------------------------------
// Purpose:
// Input : timeDelta -
//-----------------------------------------------------------------------------
void C_Flare::Update( float timeDelta )
{
if ( !IsVisible() )
return;
CSimpleEmitter::Update( timeDelta );
//Make sure our stored resources are up to date
RestoreResources();
//Don't do this if the console is down
if ( timeDelta <= 0.0f )
return;
//Check for LOS
pixelvis_queryparams_t params;
params.Init(GetAbsOrigin());
params.proxySize = 8.0f; // Inches
float visible = PixelVisibility_FractionVisible( params, &m_queryHandle );
float fColor;
#ifdef HL2_CLIENT_DLL
float baseScale = m_flScale;
#else
// NOTE!!! This is bigger by a factor of 1.2 to deal with fixing a bug from HL2. See dlight_t.h
float baseScale = m_flScale * 1.2f;
#endif
//Account for fading out
if ( ( m_flTimeBurnOut != -1.0f ) && ( ( m_flTimeBurnOut - gpGlobals->curtime ) <= 10.0f ) )
{
baseScale *= ( ( m_flTimeBurnOut - gpGlobals->curtime ) / 10.0f );
}
bool bVisible = (baseScale < 0.01f || visible == 0.0f) ? false : true;
//Clamp the scale if vanished
if ( !bVisible )
{
if ( m_pParticle[0] != NULL )
{
m_pParticle[0]->m_flDieTime = gpGlobals->curtime;
m_pParticle[0]->m_uchStartSize = m_pParticle[0]->m_uchEndSize = 0;
m_pParticle[0]->m_uchColor[0] = 0;
m_pParticle[0]->m_uchColor[1] = 0;
m_pParticle[0]->m_uchColor[2] = 0;
}
if ( m_pParticle[1] != NULL )
{
m_pParticle[1]->m_flDieTime = gpGlobals->curtime;
m_pParticle[1]->m_uchStartSize = m_pParticle[1]->m_uchEndSize = 0;
m_pParticle[1]->m_uchColor[0] = 0;
m_pParticle[1]->m_uchColor[1] = 0;
m_pParticle[1]->m_uchColor[2] = 0;
}
}
if ( baseScale < 0.01f )
return;
//
// Dynamic light
//
if ( m_bLight )
{
dlight_t *dl= effects->CL_AllocDlight( index );
if ( m_bPropFlare == false )
{
dl->origin = GetAbsOrigin();
dl->color.r = 255;
dl->die = gpGlobals->curtime + 0.1f;
dl->radius = baseScale * random->RandomFloat( 110.0f, 128.0f );
dl->color.g = dl->color.b = random->RandomInt( 32, 64 );
}
else
{
if ( m_iAttachment == -1 )
{
m_iAttachment = LookupAttachment( "fuse" );
}
if ( m_iAttachment != -1 )
{
Vector effect_origin;
QAngle effect_angles;
GetAttachment( m_iAttachment, effect_origin, effect_angles );
//Raise the light a little bit away from the flare so it lights it up better.
dl->origin = effect_origin + Vector( 0, 0, 4 );
dl->color.r = 255;
dl->die = gpGlobals->curtime + 0.1f;
dl->radius = baseScale * random->RandomFloat( 245.0f, 256.0f );
dl->color.g = dl->color.b = random->RandomInt( 95, 128 );
dlight_t *el= effects->CL_AllocElight( index );
el->origin = effect_origin;
el->color.r = 255;
el->color.g = dl->color.b = random->RandomInt( 95, 128 );
el->radius = baseScale * random->RandomFloat( 260.0f, 290.0f );
el->die = gpGlobals->curtime + 0.1f;
}
}
}
//
// Smoke
//
float dt = timeDelta;
if ( m_bSmoke )
{
while ( m_teSmokeSpawn.NextEvent( dt ) )
{
Vector smokeOrg = GetAbsOrigin();
Vector flareScreenDir = ( smokeOrg - MainViewOrigin() );
VectorNormalize( flareScreenDir );
smokeOrg = smokeOrg + ( flareScreenDir * 2.0f );
smokeOrg[2] += baseScale * 4.0f;
SimpleParticle *sParticle = (SimpleParticle *) AddParticle( sizeof( SimpleParticle ), g_Mat_DustPuff[1], smokeOrg );
if ( sParticle == NULL )
return;
sParticle->m_flLifetime = 0.0f;
sParticle->m_flDieTime = 1.0f;
sParticle->m_vecVelocity = Vector( random->RandomFloat( -16.0f, 16.0f ), random->RandomFloat( -16.0f, 16.0f ), random->RandomFloat( 8.0f, 16.0f ) + 32.0f );
if ( m_bPropFlare )
{
sParticle->m_uchColor[0] = 255;
sParticle->m_uchColor[1] = 100;
sParticle->m_uchColor[2] = 100;
}
else
{
sParticle->m_uchColor[0] = 255;
sParticle->m_uchColor[1] = 48;
sParticle->m_uchColor[2] = 48;
}
sParticle->m_uchStartAlpha = random->RandomInt( 64, 90 );
sParticle->m_uchEndAlpha = 0;
sParticle->m_uchStartSize = random->RandomInt( 2, 4 );
sParticle->m_uchEndSize = sParticle->m_uchStartSize * 8.0f;
sParticle->m_flRoll = random->RandomInt( 0, 2*M_PI );
sParticle->m_flRollDelta = random->RandomFloat( -(M_PI/6.0f), M_PI/6.0f );
}
}
if ( !bVisible )
return;
//
// Outer glow
//
Vector offset;
//Cause the base of the effect to shake
offset.Random( -0.5f * baseScale, 0.5f * baseScale );
offset += GetAbsOrigin();
if ( m_pParticle[0] != NULL )
{
m_pParticle[0]->m_Pos = offset;
m_pParticle[0]->m_flLifetime = 0.0f;
m_pParticle[0]->m_flDieTime = 2.0f;
m_pParticle[0]->m_vecVelocity.Init();
fColor = random->RandomInt( 100.0f, 128.0f ) * visible;
m_pParticle[0]->m_uchColor[0] = fColor;
m_pParticle[0]->m_uchColor[1] = fColor;
m_pParticle[0]->m_uchColor[2] = fColor;
m_pParticle[0]->m_uchStartAlpha = fColor;
m_pParticle[0]->m_uchEndAlpha = fColor;
m_pParticle[0]->m_uchStartSize = baseScale * (float) random->RandomInt( 32, 48 );
m_pParticle[0]->m_uchEndSize = m_pParticle[0]->m_uchStartSize;
m_pParticle[0]->m_flRollDelta = 0.0f;
if ( random->RandomInt( 0, 4 ) == 3 )
{
m_pParticle[0]->m_flRoll += random->RandomInt( 2, 8 );
}
}
//
// Inner core
//
//Cause the base of the effect to shake
offset.Random( -1.0f * baseScale, 1.0f * baseScale );
offset += GetAbsOrigin();
if ( m_pParticle[1] != NULL )
{
m_pParticle[1]->m_Pos = offset;
m_pParticle[1]->m_flLifetime = 0.0f;
m_pParticle[1]->m_flDieTime = 2.0f;
m_pParticle[1]->m_vecVelocity.Init();
fColor = 255 * visible;
m_pParticle[1]->m_uchColor[0] = fColor;
m_pParticle[1]->m_uchColor[1] = fColor;
m_pParticle[1]->m_uchColor[2] = fColor;
m_pParticle[1]->m_uchStartAlpha = fColor;
m_pParticle[1]->m_uchEndAlpha = fColor;
m_pParticle[1]->m_uchStartSize = baseScale * (float) random->RandomInt( 2, 4 );
m_pParticle[1]->m_uchEndSize = m_pParticle[0]->m_uchStartSize;
m_pParticle[1]->m_flRoll = random->RandomInt( 0, 360 );
}
}

View File

@@ -0,0 +1,170 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
// $NoKeywords: $
//=============================================================================//
#include "cbase.h"
#include "particlemgr.h"
#include "particle_prototype.h"
#include "particle_util.h"
#include "c_te_particlesystem.h"
#include "fx.h"
#include "fx_quad.h"
#include "c_te_effect_dispatch.h"
#include "view.h"
// memdbgon must be the last include file in a .cpp file!!!
#include "tier0/memdbgon.h"
#define THUMPER_DUST_LIFETIME 2.0f
#define THUMPER_MAX_PARTICLES 24
extern IPhysicsSurfaceProps *physprops;
class ThumperDustEmitter : public CSimpleEmitter
{
public:
ThumperDustEmitter( const char *pDebugName ) : CSimpleEmitter( pDebugName ) {}
static ThumperDustEmitter *Create( const char *pDebugName )
{
return new ThumperDustEmitter( pDebugName );
}
void UpdateVelocity( SimpleParticle *pParticle, float timeDelta )
{
// Float up when lifetime is half gone.
pParticle->m_vecVelocity[2] -= ( 8.0f * timeDelta );
// FIXME: optimize this....
pParticle->m_vecVelocity *= ExponentialDecay( 0.9, 0.03, timeDelta );
}
virtual float UpdateRoll( SimpleParticle *pParticle, float timeDelta )
{
pParticle->m_flRoll += pParticle->m_flRollDelta * timeDelta;
pParticle->m_flRollDelta += pParticle->m_flRollDelta * ( timeDelta * -4.0f );
//Cap the minimum roll
if ( fabs( pParticle->m_flRollDelta ) < 0.25f )
{
pParticle->m_flRollDelta = ( pParticle->m_flRollDelta > 0.0f ) ? 0.25f : -0.25f;
}
return pParticle->m_flRoll;
}
virtual float UpdateAlpha( const SimpleParticle *pParticle )
{
return (pParticle->m_uchStartAlpha/255.0f) + ( (float)(pParticle->m_uchEndAlpha/255.0f) - (float)(pParticle->m_uchStartAlpha/255.0f) ) * (pParticle->m_flLifetime / pParticle->m_flDieTime);
}
private:
ThumperDustEmitter( const ThumperDustEmitter & );
};
//-----------------------------------------------------------------------------
// Purpose:
// Input : bNewEntity - whether or not to start a new entity
//-----------------------------------------------------------------------------
void FX_ThumperDust( const CEffectData &data )
{
Vector vecDustColor;
vecDustColor.x = 0.85f;
vecDustColor.y = 0.75f;
vecDustColor.z = 0.52f;
CSmartPtr<ThumperDustEmitter> pSimple = ThumperDustEmitter::Create( "thumperdust" );
C_BaseEntity *pEnt = C_BaseEntity::Instance( data.m_hEntity );
if ( pEnt )
{
Vector vWorldMins, vWorldMaxs;
float scale = pEnt->CollisionProp()->BoundingRadius();
vWorldMins[0] = data.m_vOrigin[0] - scale;
vWorldMins[1] = data.m_vOrigin[1] - scale;
vWorldMins[2] = data.m_vOrigin[2] - scale;
vWorldMaxs[0] = data.m_vOrigin[0] + scale;
vWorldMaxs[1] = data.m_vOrigin[1] + scale;
vWorldMaxs[2] = data.m_vOrigin[2] + scale;
pSimple->GetBinding().SetBBox( vWorldMins, vWorldMaxs, true );
}
pSimple->SetSortOrigin( data.m_vOrigin );
pSimple->SetNearClip( 32, 64 );
SimpleParticle *pParticle = NULL;
Vector offset;
//int numPuffs = IsXbox() ? THUMPER_MAX_PARTICLES/2 : THUMPER_MAX_PARTICLES;
int numPuffs = THUMPER_MAX_PARTICLES;
float flYaw = 0;
float flIncr = (2*M_PI) / (float) numPuffs; // Radians
Vector forward;
Vector vecColor;
int i = 0;
float flScale = MIN( data.m_flScale, 255 );
// Setup the color for these particles
engine->ComputeLighting( data.m_vOrigin, NULL, true, vecColor );
VectorLerp( vecColor, vecDustColor, 0.5, vecColor );
vecColor *= 255;
for ( i = 0; i < numPuffs; i++ )
{
flYaw += flIncr;
SinCos( flYaw, &forward.y, &forward.x );
forward.z = 0.0f;
offset = ( RandomVector( -4.0f, 4.0f ) + data.m_vOrigin ) + ( forward * 128.0f );
pParticle = (SimpleParticle *) pSimple->AddParticle( sizeof(SimpleParticle), g_Mat_DustPuff[random->RandomInt(0,1)], offset );
if ( pParticle != NULL )
{
pParticle->m_flLifetime = 0.0f;
pParticle->m_flDieTime = 1.5f;
Vector dir = (offset - data.m_vOrigin);
float length = dir.Length();
VectorNormalize( dir );
pParticle->m_vecVelocity = dir * ( length * 2.0f );
pParticle->m_vecVelocity[2] = data.m_flScale / 3;
pParticle->m_uchColor[0] = vecColor[0];
pParticle->m_uchColor[1] = vecColor[1];
pParticle->m_uchColor[2] = vecColor[2];
pParticle->m_uchStartAlpha = random->RandomInt( 64, 96 );
pParticle->m_uchEndAlpha = 0;
pParticle->m_uchStartSize = flScale * 0.25f;
pParticle->m_uchEndSize = flScale * 0.5f;
pParticle->m_flRoll = random->RandomInt( 0, 360 );
pParticle->m_flRollDelta = random->RandomFloat( -6.0f, 6.0f );
}
}
}
//-----------------------------------------------------------------------------
// Purpose:
// Input : &data -
//-----------------------------------------------------------------------------
void ThumperDustCallback( const CEffectData &data )
{
FX_ThumperDust( data );
}
DECLARE_CLIENT_EFFECT( "ThumperDust", ThumperDustCallback );

View File

@@ -0,0 +1,931 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose: Client side implementation of the airboat.
//
// - Dampens motion of driver's view to reduce nausea.
// - Autocenters driver's view after a period of inactivity.
// - Controls headlights.
// - Controls curve parameters for pitch/roll blending.
//
//=============================================================================//
#include "cbase.h"
#include "c_prop_vehicle.h"
#include "datacache/imdlcache.h"
#include "flashlighteffect.h"
#include "movevars_shared.h"
#include "ammodef.h"
#include "SpriteTrail.h"
#include "beamdraw.h"
#include "enginesprite.h"
#include "fx_quad.h"
#include "fx.h"
#include "fx_water.h"
#include "engine/ivdebugoverlay.h"
#include "view.h"
#include "clienteffectprecachesystem.h"
#include "c_basehlplayer.h"
#include "vgui_controls/Controls.h"
#include "vgui/ISurface.h"
// memdbgon must be the last include file in a .cpp file!!!
#include "tier0/memdbgon.h"
ConVar r_AirboatViewBlendTo( "r_AirboatViewBlendTo", "1", FCVAR_CHEAT );
ConVar r_AirboatViewBlendToScale( "r_AirboatViewBlendToScale", "0.03", FCVAR_CHEAT );
ConVar r_AirboatViewBlendToTime( "r_AirboatViewBlendToTime", "1.5", FCVAR_CHEAT );
ConVar cl_draw_airboat_wake( "cl_draw_airboat_wake", "1", FCVAR_CHEAT );
// Curve parameters for pitch/roll blending.
// NOTE: Must restart (or create a new airboat) after changing these cvars!
ConVar r_AirboatRollCurveZero( "r_AirboatRollCurveZero", "90.0", FCVAR_CHEAT ); // Roll less than this is clamped to zero.
ConVar r_AirboatRollCurveLinear( "r_AirboatRollCurveLinear", "120.0", FCVAR_CHEAT ); // Roll greater than this is mapped directly.
// Spline in between.
ConVar r_AirboatPitchCurveZero( "r_AirboatPitchCurveZero", "25.0", FCVAR_CHEAT ); // Pitch less than this is clamped to zero.
ConVar r_AirboatPitchCurveLinear( "r_AirboatPitchCurveLinear", "60.0", FCVAR_CHEAT ); // Pitch greater than this is mapped directly.
// Spline in between.
ConVar airboat_joy_response_move( "airboat_joy_response_move", "1" ); // Quadratic steering response
#define AIRBOAT_DELTA_LENGTH_MAX 12.0f // 1 foot
#define AIRBOAT_FRAMETIME_MIN 1e-6
#define HEADLIGHT_DISTANCE 1000
#define MAX_WAKE_POINTS 16
#define WAKE_POINT_MASK (MAX_WAKE_POINTS-1)
#define WAKE_LIFETIME 0.5f
//=============================================================================
//
// Client-side Airboat Class
//
class C_PropAirboat : public C_PropVehicleDriveable
{
DECLARE_CLASS( C_PropAirboat, C_PropVehicleDriveable );
public:
DECLARE_CLIENTCLASS();
DECLARE_INTERPOLATION();
DECLARE_DATADESC();
C_PropAirboat();
~C_PropAirboat();
public:
// C_BaseEntity
virtual void Simulate();
// IClientVehicle
virtual void UpdateViewAngles( C_BasePlayer *pLocalPlayer, CUserCmd *pCmd );
virtual void OnEnteredVehicle( C_BasePlayer *pPlayer );
virtual int GetPrimaryAmmoType() const;
virtual int GetPrimaryAmmoClip() const;
virtual bool PrimaryAmmoUsesClips() const;
virtual int GetPrimaryAmmoCount() const;
virtual int GetJoystickResponseCurve() const;
int DrawModel( int flags );
// Draws crosshair in the forward direction of the boat
void DrawHudElements( );
private:
void DrawPropWake( Vector origin, float speed );
void DrawPontoonSplash( Vector position, Vector direction, float speed );
void DrawPontoonWake( Vector startPos, Vector wakeDir, float wakeLength, float speed);
void DampenEyePosition( Vector &vecVehicleEyePos, QAngle &vecVehicleEyeAngles );
void DampenForwardMotion( Vector &vecVehicleEyePos, QAngle &vecVehicleEyeAngles, float flFrameTime );
void DampenUpMotion( Vector &vecVehicleEyePos, QAngle &vecVehicleEyeAngles, float flFrameTime );
void ComputePDControllerCoefficients( float *pCoefficientsOut, float flFrequency, float flDampening, float flDeltaTime );
void UpdateHeadlight( void );
void UpdateWake( void );
int DrawWake( void );
void DrawSegment( const BeamSeg_t &beamSeg, const Vector &vNormal );
TrailPoint_t *GetTrailPoint( int n )
{
int nIndex = (n + m_nFirstStep) & WAKE_POINT_MASK;
return &m_vecSteps[nIndex];
}
private:
Vector m_vecLastEyePos;
Vector m_vecLastEyeTarget;
Vector m_vecEyeSpeed;
Vector m_vecTargetSpeed;
float m_flViewAngleDeltaTime;
bool m_bHeadlightIsOn;
int m_nAmmoCount;
CHeadlightEffect *m_pHeadlight;
int m_nExactWaterLevel;
TrailPoint_t m_vecSteps[MAX_WAKE_POINTS];
int m_nFirstStep;
int m_nStepCount;
float m_flUpdateTime;
TimedEvent m_SplashTime;
CMeshBuilder m_Mesh;
Vector m_vecPhysVelocity;
};
IMPLEMENT_CLIENTCLASS_DT( C_PropAirboat, DT_PropAirboat, CPropAirboat )
RecvPropBool( RECVINFO( m_bHeadlightIsOn ) ),
RecvPropInt( RECVINFO( m_nAmmoCount ) ),
RecvPropInt( RECVINFO( m_nExactWaterLevel ) ),
RecvPropInt( RECVINFO( m_nWaterLevel ) ),
RecvPropVector( RECVINFO( m_vecPhysVelocity ) ),
END_RECV_TABLE()
BEGIN_DATADESC( C_PropAirboat )
DEFINE_FIELD( m_vecLastEyePos, FIELD_POSITION_VECTOR ),
DEFINE_FIELD( m_vecLastEyeTarget, FIELD_POSITION_VECTOR ),
DEFINE_FIELD( m_vecEyeSpeed, FIELD_VECTOR ),
DEFINE_FIELD( m_vecTargetSpeed, FIELD_VECTOR ),
//DEFINE_FIELD( m_flViewAngleDeltaTime, FIELD_FLOAT ),
END_DATADESC()
//-----------------------------------------------------------------------------
// Purpose: Constructor
//-----------------------------------------------------------------------------
C_PropAirboat::C_PropAirboat()
{
m_vecEyeSpeed.Init();
m_flViewAngleDeltaTime = 0.0f;
m_pHeadlight = NULL;
m_ViewSmoothingData.flPitchCurveZero = r_AirboatPitchCurveZero.GetFloat();
m_ViewSmoothingData.flPitchCurveLinear = r_AirboatPitchCurveLinear.GetFloat();
m_ViewSmoothingData.flRollCurveZero = r_AirboatRollCurveZero.GetFloat();
m_ViewSmoothingData.flRollCurveLinear = r_AirboatRollCurveLinear.GetFloat();
m_ViewSmoothingData.rollLockData.flLockInterval = 1.5;
m_ViewSmoothingData.rollLockData.flUnlockBlendInterval = 1.0;
m_ViewSmoothingData.pitchLockData.flLockInterval = 1.5;
m_ViewSmoothingData.pitchLockData.flUnlockBlendInterval = 1.0;
m_nFirstStep = 0;
m_nStepCount = 0;
m_SplashTime.Init( 60 );
}
//-----------------------------------------------------------------------------
// Purpose: Deconstructor
//-----------------------------------------------------------------------------
C_PropAirboat::~C_PropAirboat()
{
if (m_pHeadlight)
{
delete m_pHeadlight;
}
}
//-----------------------------------------------------------------------------
// Draws the ammo for the airboat
//-----------------------------------------------------------------------------
int C_PropAirboat::GetPrimaryAmmoType() const
{
if ( m_nAmmoCount < 0 )
return -1;
int nAmmoType = GetAmmoDef()->Index( "AirboatGun" );
return nAmmoType;
}
int C_PropAirboat::GetPrimaryAmmoCount() const
{
return m_nAmmoCount;
}
bool C_PropAirboat::PrimaryAmmoUsesClips() const
{
return false;
}
int C_PropAirboat::GetPrimaryAmmoClip() const
{
return -1;
}
//-----------------------------------------------------------------------------
// The airboat prefers a more peppy response curve for joystick control.
//-----------------------------------------------------------------------------
int C_PropAirboat::GetJoystickResponseCurve() const
{
return airboat_joy_response_move.GetInt();
}
//-----------------------------------------------------------------------------
// Draws crosshair in the forward direction of the boat
//-----------------------------------------------------------------------------
void C_PropAirboat::DrawHudElements( )
{
BaseClass::DrawHudElements();
MDLCACHE_CRITICAL_SECTION();
CHudTexture *pIcon = gHUD.GetIcon( IsX360() ? "crosshair_default" : "plushair" );
if ( pIcon != NULL )
{
float x, y;
Vector screen;
int vx, vy, vw, vh;
vgui::surface()->GetFullscreenViewport( vx, vy, vw, vh );
float screenWidth = vw;
float screenHeight = vh;
x = screenWidth/2;
y = screenHeight/2;
int eyeAttachmentIndex = LookupAttachment( "vehicle_driver_eyes" );
Vector vehicleEyeOrigin;
QAngle vehicleEyeAngles;
GetAttachment( eyeAttachmentIndex, vehicleEyeOrigin, vehicleEyeAngles );
// Only worry about yaw.
vehicleEyeAngles.x = vehicleEyeAngles.z = 0.0f;
Vector vecForward;
AngleVectors( vehicleEyeAngles, &vecForward );
VectorMA( vehicleEyeOrigin, 100.0f, vecForward, vehicleEyeOrigin );
ScreenTransform( vehicleEyeOrigin, screen );
x += 0.5 * screen[0] * screenWidth + 0.5;
y -= 0.5 * screen[1] * screenHeight + 0.5;
x -= pIcon->Width() / 2;
y -= pIcon->Height() / 2;
pIcon->DrawSelf( x, y, gHUD.m_clrNormal );
}
}
//-----------------------------------------------------------------------------
// Purpose: Blend view angles.
//-----------------------------------------------------------------------------
void C_PropAirboat::UpdateViewAngles( C_BasePlayer *pLocalPlayer, CUserCmd *pCmd )
{
if ( r_AirboatViewBlendTo.GetInt() )
{
//
// Autocenter the view after a period of no mouse movement while throttling.
//
bool bResetViewAngleTime = false;
if ( ( pCmd->mousedx != 0 || pCmd->mousedy != 0 ) || ( fabsf( m_flThrottle ) < 0.01f ) )
{
if ( IsX360() )
{
// Only reset this if there isn't an autoaim target!
C_BaseHLPlayer *pLocalHLPlayer = (C_BaseHLPlayer *)pLocalPlayer;
if ( pLocalHLPlayer )
{
// Get the autoaim target.
CBaseEntity *pTarget = pLocalHLPlayer->m_HL2Local.m_hAutoAimTarget.Get();
if( !pTarget )
{
bResetViewAngleTime = true;
}
}
}
else
{
bResetViewAngleTime = true;
}
}
if( bResetViewAngleTime )
{
m_flViewAngleDeltaTime = 0.0f;
}
else
{
m_flViewAngleDeltaTime += gpGlobals->frametime;
}
if ( m_flViewAngleDeltaTime > r_AirboatViewBlendToTime.GetFloat() )
{
// Blend the view angles.
int eyeAttachmentIndex = LookupAttachment( "vehicle_driver_eyes" );
Vector vehicleEyeOrigin;
QAngle vehicleEyeAngles;
GetAttachmentLocal( eyeAttachmentIndex, vehicleEyeOrigin, vehicleEyeAngles );
QAngle outAngles;
InterpolateAngles( pCmd->viewangles, vehicleEyeAngles, outAngles, r_AirboatViewBlendToScale.GetFloat() );
pCmd->viewangles = outAngles;
}
}
BaseClass::UpdateViewAngles( pLocalPlayer, pCmd );
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void C_PropAirboat::DampenEyePosition( Vector &vecVehicleEyePos, QAngle &vecVehicleEyeAngles )
{
// Get the frametime. (Check to see if enough time has passed to warrent dampening).
float flFrameTime = gpGlobals->frametime;
if ( flFrameTime < AIRBOAT_FRAMETIME_MIN )
{
vecVehicleEyePos = m_vecLastEyePos;
DampenUpMotion( vecVehicleEyePos, vecVehicleEyeAngles, 0.0f );
return;
}
// Keep static the sideways motion.
// Dampen forward/backward motion.
DampenForwardMotion( vecVehicleEyePos, vecVehicleEyeAngles, flFrameTime );
// Blend up/down motion.
DampenUpMotion( vecVehicleEyePos, vecVehicleEyeAngles, flFrameTime );
}
//-----------------------------------------------------------------------------
// Use the controller as follows:
// speed += ( pCoefficientsOut[0] * ( targetPos - currentPos ) + pCoefficientsOut[1] * ( targetSpeed - currentSpeed ) ) * flDeltaTime;
//-----------------------------------------------------------------------------
void C_PropAirboat::ComputePDControllerCoefficients( float *pCoefficientsOut,
float flFrequency, float flDampening,
float flDeltaTime )
{
float flKs = 9.0f * flFrequency * flFrequency;
float flKd = 4.5f * flFrequency * flDampening;
float flScale = 1.0f / ( 1.0f + flKd * flDeltaTime + flKs * flDeltaTime * flDeltaTime );
pCoefficientsOut[0] = flKs * flScale;
pCoefficientsOut[1] = ( flKd + flKs * flDeltaTime ) * flScale;
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void C_PropAirboat::DampenForwardMotion( Vector &vecVehicleEyePos, QAngle &vecVehicleEyeAngles, float flFrameTime )
{
// vecVehicleEyePos = real eye position this frame
// m_vecLastEyePos = eye position last frame
// m_vecEyeSpeed = eye speed last frame
// vecPredEyePos = predicted eye position this frame (assuming no acceleration - it will get that from the pd controller).
// vecPredEyeSpeed = predicted eye speed
Vector vecPredEyePos = m_vecLastEyePos + m_vecEyeSpeed * flFrameTime;
Vector vecPredEyeSpeed = m_vecEyeSpeed;
// m_vecLastEyeTarget = real eye position last frame (used for speed calculation).
// Calculate the approximate speed based on the current vehicle eye position and the eye position last frame.
Vector vecVehicleEyeSpeed = ( vecVehicleEyePos - m_vecLastEyeTarget ) / flFrameTime;
m_vecLastEyeTarget = vecVehicleEyePos;
if (vecVehicleEyeSpeed.Length() == 0.0)
{
return;
}
// Calculate the delta between the predicted eye position and speed and the current eye position and speed.
Vector vecDeltaSpeed = vecVehicleEyeSpeed - vecPredEyeSpeed;
Vector vecDeltaPos = vecVehicleEyePos - vecPredEyePos;
// Forward vector.
Vector vecForward;
AngleVectors( vecVehicleEyeAngles, &vecForward );
float flDeltaLength = vecDeltaPos.Length();
if ( flDeltaLength > AIRBOAT_DELTA_LENGTH_MAX )
{
// Clamp.
float flDelta = flDeltaLength - AIRBOAT_DELTA_LENGTH_MAX;
if ( flDelta > 40.0f )
{
// This part is a bit of a hack to get rid of large deltas (at level load, etc.).
m_vecLastEyePos = vecVehicleEyePos;
m_vecEyeSpeed = vecVehicleEyeSpeed;
}
else
{
// Position clamp.
float flRatio = AIRBOAT_DELTA_LENGTH_MAX / flDeltaLength;
vecDeltaPos *= flRatio;
Vector vecForwardOffset = vecForward * ( vecForward.Dot( vecDeltaPos ) );
vecVehicleEyePos -= vecForwardOffset;
m_vecLastEyePos = vecVehicleEyePos;
// Speed clamp.
vecDeltaSpeed *= flRatio;
float flCoefficients[2];
ComputePDControllerCoefficients( flCoefficients, r_AirboatViewDampenFreq.GetFloat(), r_AirboatViewDampenDamp.GetFloat(), flFrameTime );
m_vecEyeSpeed += ( ( flCoefficients[0] * vecDeltaPos + flCoefficients[1] * vecDeltaSpeed ) * flFrameTime );
}
}
else
{
// Generate an updated (dampening) speed for use in next frames position prediction.
float flCoefficients[2];
ComputePDControllerCoefficients( flCoefficients, r_AirboatViewDampenFreq.GetFloat(), r_AirboatViewDampenDamp.GetFloat(), flFrameTime );
m_vecEyeSpeed += ( ( flCoefficients[0] * vecDeltaPos + flCoefficients[1] * vecDeltaSpeed ) * flFrameTime );
// Save off data for next frame.
m_vecLastEyePos = vecPredEyePos;
// Move eye forward/backward.
Vector vecForwardOffset = vecForward * ( vecForward.Dot( vecDeltaPos ) );
vecVehicleEyePos -= vecForwardOffset;
}
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void C_PropAirboat::DampenUpMotion( Vector &vecVehicleEyePos, QAngle &vecVehicleEyeAngles, float flFrameTime )
{
// Get up vector.
Vector vecUp;
AngleVectors( vecVehicleEyeAngles, NULL, NULL, &vecUp );
vecUp.z = clamp( vecUp.z, 0.0f, vecUp.z );
vecVehicleEyePos.z += r_AirboatViewZHeight.GetFloat() * vecUp.z;
// NOTE: Should probably use some damped equation here.
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void C_PropAirboat::OnEnteredVehicle( C_BasePlayer *pPlayer )
{
int eyeAttachmentIndex = LookupAttachment( "vehicle_driver_eyes" );
Vector vehicleEyeOrigin;
QAngle vehicleEyeAngles;
GetAttachment( eyeAttachmentIndex, vehicleEyeOrigin, vehicleEyeAngles );
m_vecLastEyeTarget = vehicleEyeOrigin;
m_vecLastEyePos = vehicleEyeOrigin;
m_vecEyeSpeed = vec3_origin;
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void C_PropAirboat::Simulate()
{
UpdateHeadlight();
UpdateWake();
BaseClass::Simulate();
}
//-----------------------------------------------------------------------------
// Purpose: Creates, destroys, and updates the headlight effect as needed.
//-----------------------------------------------------------------------------
void C_PropAirboat::UpdateHeadlight()
{
if (m_bHeadlightIsOn)
{
if (!m_pHeadlight)
{
// Turned on the headlight; create it.
m_pHeadlight = new CHeadlightEffect();
if (!m_pHeadlight)
return;
m_pHeadlight->TurnOn();
}
// The headlight is emitted from an attachment point so that it can move
// as we turn the handlebars.
int nHeadlightIndex = LookupAttachment( "vehicle_headlight" );
Vector vecLightPos;
QAngle angLightDir;
GetAttachment(nHeadlightIndex, vecLightPos, angLightDir);
Vector vecLightDir, vecLightRight, vecLightUp;
AngleVectors( angLightDir, &vecLightDir, &vecLightRight, &vecLightUp );
// Update the light with the new position and direction.
m_pHeadlight->UpdateLight( vecLightPos, vecLightDir, vecLightRight, vecLightUp, HEADLIGHT_DISTANCE );
}
else if (m_pHeadlight)
{
// Turned off the headlight; delete it.
delete m_pHeadlight;
m_pHeadlight = NULL;
}
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void C_PropAirboat::UpdateWake( void )
{
if ( gpGlobals->frametime <= 0.0f )
return;
// Can't update too quickly
if ( m_flUpdateTime > gpGlobals->curtime )
return;
Vector screenPos = GetRenderOrigin();
screenPos.z = m_nExactWaterLevel;
TrailPoint_t *pLast = m_nStepCount ? GetTrailPoint( m_nStepCount-1 ) : NULL;
if ( ( pLast == NULL ) || ( pLast->m_vecScreenPos.DistToSqr( screenPos ) > 4.0f ) )
{
// If we're over our limit, steal the last point and put it up front
if ( m_nStepCount >= MAX_WAKE_POINTS )
{
--m_nStepCount;
++m_nFirstStep;
}
// Save off its screen position, not its world position
TrailPoint_t *pNewPoint = GetTrailPoint( m_nStepCount );
pNewPoint->m_vecScreenPos = screenPos + Vector( 0, 0, 2 );
pNewPoint->m_flDieTime = gpGlobals->curtime + WAKE_LIFETIME;
pNewPoint->m_flWidthVariance = random->RandomFloat( -16, 16 );
if ( pLast )
{
pNewPoint->m_flTexCoord = pLast->m_flTexCoord + pLast->m_vecScreenPos.DistTo( screenPos );
pNewPoint->m_flTexCoord = fmod( pNewPoint->m_flTexCoord, 1 );
}
else
{
pNewPoint->m_flTexCoord = 0.0f;
}
++m_nStepCount;
}
// Don't update again for a bit
m_flUpdateTime = gpGlobals->curtime + ( 0.5f / (float) MAX_WAKE_POINTS );
}
//-----------------------------------------------------------------------------
// Purpose:
// Input : &beamSeg -
//-----------------------------------------------------------------------------
void C_PropAirboat::DrawSegment( const BeamSeg_t &beamSeg, const Vector &vNormal )
{
// Build the endpoints.
Vector vPoint1, vPoint2;
VectorMA( beamSeg.m_vPos, beamSeg.m_flWidth*0.5f, vNormal, vPoint1 );
VectorMA( beamSeg.m_vPos, -beamSeg.m_flWidth*0.5f, vNormal, vPoint2 );
// Specify the points.
m_Mesh.Position3fv( vPoint1.Base() );
m_Mesh.Color4f( VectorExpand( beamSeg.m_vColor ), beamSeg.m_flAlpha );
m_Mesh.TexCoord2f( 0, 0, beamSeg.m_flTexCoord );
m_Mesh.TexCoord2f( 1, 0, beamSeg.m_flTexCoord );
m_Mesh.AdvanceVertex();
m_Mesh.Position3fv( vPoint2.Base() );
m_Mesh.Color4f( VectorExpand( beamSeg.m_vColor ), beamSeg.m_flAlpha );
m_Mesh.TexCoord2f( 0, 1, beamSeg.m_flTexCoord );
m_Mesh.TexCoord2f( 1, 1, beamSeg.m_flTexCoord );
m_Mesh.AdvanceVertex();
}
//-----------------------------------------------------------------------------
// Purpose:
// Input : position -
//-----------------------------------------------------------------------------
void C_PropAirboat::DrawPontoonSplash( Vector origin, Vector direction, float speed )
{
Vector offset;
CSmartPtr<CSplashParticle> pSimple = CSplashParticle::Create( "splish" );
pSimple->SetSortOrigin( origin );
SimpleParticle *pParticle;
Vector color = Vector( 0.8f, 0.8f, 0.75f );
float colorRamp;
float flScale = RemapVal( speed, 64, 256, 0.75f, 1.0f );
PMaterialHandle hMaterial;
float tempDelta = gpGlobals->frametime;
while( m_SplashTime.NextEvent( tempDelta ) )
{
if ( random->RandomInt( 0, 1 ) )
{
hMaterial = ParticleMgr()->GetPMaterial( "effects/splash1" );
}
else
{
hMaterial = ParticleMgr()->GetPMaterial( "effects/splash2" );
}
offset = RandomVector( -8.0f * flScale, 8.0f * flScale );
offset[2] = 0.0f;
offset += origin;
pParticle = (SimpleParticle *) pSimple->AddParticle( sizeof( SimpleParticle ), hMaterial, offset );
if ( pParticle == NULL )
continue;
pParticle->m_flLifetime = 0.0f;
pParticle->m_flDieTime = 0.25f;
pParticle->m_vecVelocity.Random( -0.4f, 0.4f );
pParticle->m_vecVelocity += (direction*5.0f+Vector(0,0,1));
VectorNormalize( pParticle->m_vecVelocity );
pParticle->m_vecVelocity *= speed + random->RandomFloat( -128.0f, 128.0f );
colorRamp = random->RandomFloat( 0.75f, 1.25f );
pParticle->m_uchColor[0] = MIN( 1.0f, color[0] * colorRamp ) * 255.0f;
pParticle->m_uchColor[1] = MIN( 1.0f, color[1] * colorRamp ) * 255.0f;
pParticle->m_uchColor[2] = MIN( 1.0f, color[2] * colorRamp ) * 255.0f;
pParticle->m_uchStartSize = random->RandomFloat( 8, 16 ) * flScale;
pParticle->m_uchEndSize = pParticle->m_uchStartSize * 2;
pParticle->m_uchStartAlpha = 255;
pParticle->m_uchEndAlpha = 0;
pParticle->m_flRoll = random->RandomInt( 0, 360 );
pParticle->m_flRollDelta = random->RandomFloat( -4.0f, 4.0f );
}
}
//-----------------------------------------------------------------------------
// Purpose:
// Input : Vector startPos -
// wakeDir -
// wakeLength -
//-----------------------------------------------------------------------------
void C_PropAirboat::DrawPontoonWake( Vector startPos, Vector wakeDir, float wakeLength, float speed )
{
#define WAKE_STEPS 6
Vector wakeStep = wakeDir * ( wakeLength / (float) WAKE_STEPS );
Vector origin;
float scale;
IMaterial *pMaterial = materials->FindMaterial( "effects/splashwake1", NULL, false );
CMatRenderContextPtr pRenderContext( materials );
IMesh* pMesh = pRenderContext->GetDynamicMesh( 0, 0, 0, pMaterial );
CMeshBuilder meshBuilder;
meshBuilder.Begin( pMesh, MATERIAL_QUADS, WAKE_STEPS );
for ( int i = 0; i < WAKE_STEPS; i++ )
{
origin = startPos + ( wakeStep * i );
origin[0] += random->RandomFloat( -4.0f, 4.0f );
origin[1] += random->RandomFloat( -4.0f, 4.0f );
origin[2] = m_nExactWaterLevel + 2.0f;
float scaleRange = RemapVal( i, 0, WAKE_STEPS-1, 32, 64 );
scale = scaleRange + ( 8.0f * sin( gpGlobals->curtime * 5 * i ) );
float alpha = RemapValClamped( speed, 128, 600, 0.05f, 0.25f );
float color[4] = { 1.0f, 1.0f, 1.0f, alpha };
// Needs to be time based so it'll freeze when the game is frozen
float yaw = random->RandomFloat( 0, 360 );
Vector rRight = ( Vector(1,0,0) * cos( DEG2RAD( yaw ) ) ) - ( Vector(0,1,0) * sin( DEG2RAD( yaw ) ) );
Vector rUp = ( Vector(1,0,0) * cos( DEG2RAD( yaw+90.0f ) ) ) - ( Vector(0,1,0) * sin( DEG2RAD( yaw+90.0f ) ) );
Vector point;
meshBuilder.Color4fv (color);
meshBuilder.TexCoord2f (0, 0, 1);
VectorMA (origin, -scale, rRight, point);
VectorMA (point, -scale, rUp, point);
meshBuilder.Position3fv (point.Base());
meshBuilder.AdvanceVertex();
meshBuilder.Color4fv (color);
meshBuilder.TexCoord2f (0, 0, 0);
VectorMA (origin, scale, rRight, point);
VectorMA (point, -scale, rUp, point);
meshBuilder.Position3fv (point.Base());
meshBuilder.AdvanceVertex();
meshBuilder.Color4fv (color);
meshBuilder.TexCoord2f (0, 1, 0);
VectorMA (origin, scale, rRight, point);
VectorMA (point, scale, rUp, point);
meshBuilder.Position3fv (point.Base());
meshBuilder.AdvanceVertex();
meshBuilder.Color4fv (color);
meshBuilder.TexCoord2f (0, 1, 1);
VectorMA (origin, -scale, rRight, point);
VectorMA (point, scale, rUp, point);
meshBuilder.Position3fv (point.Base());
meshBuilder.AdvanceVertex();
}
meshBuilder.End();
pMesh->Draw();
}
//-----------------------------------------------------------------------------
// Purpose:
// Output : int
//-----------------------------------------------------------------------------
int C_PropAirboat::DrawWake( void )
{
if ( cl_draw_airboat_wake.GetBool() == false )
return 0;
// Make sure we're in water...
if ( GetWaterLevel() == 0 )
return 0;
//FIXME: For now, we don't draw slime this way
if ( GetWaterLevel() == 2 )
return 0;
bool bDriven = ( GetPassenger( VEHICLE_ROLE_DRIVER ) != NULL );
Vector vehicleDir = m_vecPhysVelocity;
float vehicleSpeed = VectorNormalize( vehicleDir );
Vector vecPontoonFrontLeft;
Vector vecPontoonFrontRight;
Vector vecPontoonRearLeft;
Vector vecPontoonRearRight;
Vector vecSplashPoint;
QAngle fooAngles;
//FIXME: This lookup should be cached off
// Get all attachments
GetAttachment( LookupAttachment( "raytrace_fl" ), vecPontoonFrontLeft, fooAngles );
GetAttachment( LookupAttachment( "raytrace_fr" ), vecPontoonFrontRight, fooAngles );
GetAttachment( LookupAttachment( "raytrace_rl" ), vecPontoonRearLeft, fooAngles );
GetAttachment( LookupAttachment( "raytrace_rr" ), vecPontoonRearRight, fooAngles );
GetAttachment( LookupAttachment( "splash_pt" ), vecSplashPoint, fooAngles );
// Find the direction of the pontoons
Vector vecLeftWakeDir = ( vecPontoonRearLeft - vecPontoonFrontLeft );
Vector vecRightWakeDir = ( vecPontoonRearRight - vecPontoonFrontRight );
// Find the pontoon's size
float flWakeLeftLength = VectorNormalize( vecLeftWakeDir );
float flWakeRightLength = VectorNormalize( vecRightWakeDir );
vecPontoonFrontLeft.z = m_nExactWaterLevel;
vecPontoonFrontRight.z = m_nExactWaterLevel;
if ( bDriven && vehicleSpeed > 128.0f )
{
DrawPontoonWake( vecPontoonFrontLeft, vecLeftWakeDir, flWakeLeftLength, vehicleSpeed );
DrawPontoonWake( vecPontoonFrontRight, vecRightWakeDir, flWakeRightLength, vehicleSpeed );
Vector vecSplashDir;
Vector vForward;
GetVectors( &vForward, NULL, NULL );
if ( m_vecPhysVelocity.x < -64.0f )
{
vecSplashDir = vecLeftWakeDir - vForward;
VectorNormalize( vecSplashDir );
// Don't do this if we're going backwards
if ( m_vecPhysVelocity.y > 0.0f )
{
DrawPontoonSplash( vecPontoonFrontLeft + ( vecLeftWakeDir * 1.0f ), vecSplashDir, m_vecPhysVelocity.y );
}
}
else if ( m_vecPhysVelocity.x > 64.0f )
{
vecSplashDir = vecRightWakeDir + vForward;
VectorNormalize( vecSplashDir );
// Don't do this if we're going backwards
if ( m_vecPhysVelocity.y > 0.0f )
{
DrawPontoonSplash( vecPontoonFrontRight + ( vecRightWakeDir * 1.0f ), vecSplashDir, m_vecPhysVelocity.y );
}
}
}
// Must have at least one point
if ( m_nStepCount <= 1 )
return 1;
IMaterial *pMaterial = materials->FindMaterial( "effects/splashwake4", 0);
//Bind the material
CMatRenderContextPtr pRenderContext( materials );
IMesh *pMesh = pRenderContext->GetDynamicMesh( true, NULL, NULL, pMaterial );
m_Mesh.Begin( pMesh, MATERIAL_TRIANGLE_STRIP, (m_nStepCount-1) * 2 );
TrailPoint_t *pLast = GetTrailPoint( m_nStepCount - 1 );
TrailPoint_t currentPoint;
currentPoint.m_flDieTime = gpGlobals->curtime + 0.5f;
currentPoint.m_vecScreenPos = GetAbsOrigin();
currentPoint.m_vecScreenPos[2] = m_nExactWaterLevel + 16;
currentPoint.m_flTexCoord = pLast->m_flTexCoord + currentPoint.m_vecScreenPos.DistTo(pLast->m_vecScreenPos);
currentPoint.m_flTexCoord = fmod( currentPoint.m_flTexCoord, 1 );
currentPoint.m_flWidthVariance = 0.0f;
TrailPoint_t *pPrevPoint = NULL;
Vector segDir, normal;
for ( int i = 0; i <= m_nStepCount; ++i )
{
// This makes it so that we're always drawing to the current location
TrailPoint_t *pPoint = (i != m_nStepCount) ? GetTrailPoint(i) : &currentPoint;
float flLifePerc = RemapValClamped( ( pPoint->m_flDieTime - gpGlobals->curtime ), 0, WAKE_LIFETIME, 0.0f, 1.0f );
BeamSeg_t curSeg;
curSeg.m_vColor.x = curSeg.m_vColor.y = curSeg.m_vColor.z = 1.0f;
float flAlphaFade = flLifePerc;
float alpha = RemapValClamped( fabs( m_vecPhysVelocity.y ), 128, 600, 0.0f, 1.0f );
curSeg.m_flAlpha = 0.25f;
curSeg.m_flAlpha *= flAlphaFade * alpha;
curSeg.m_vPos = pPoint->m_vecScreenPos;
float widthBase = SimpleSplineRemapVal( fabs( m_vecPhysVelocity.y ), 128, 600, 32, 48 );
curSeg.m_flWidth = Lerp( flLifePerc, widthBase*6, widthBase );
curSeg.m_flWidth += pPoint->m_flWidthVariance;
if ( curSeg.m_flWidth < 0.0f )
{
curSeg.m_flWidth = 0.0f;
}
curSeg.m_flTexCoord = pPoint->m_flTexCoord;
if ( pPrevPoint != NULL )
{
segDir = ( pPrevPoint->m_vecScreenPos - pPoint->m_vecScreenPos );
VectorNormalize( segDir );
normal = CrossProduct( segDir, Vector( 0, 0, -1 ) );
DrawSegment( curSeg, normal );
}
pPrevPoint = pPoint;
}
m_Mesh.End();
pMesh->Draw();
return 1;
}
//-----------------------------------------------------------------------------
// Purpose:
// Input : flags -
// Output : int
//-----------------------------------------------------------------------------
int C_PropAirboat::DrawModel( int flags )
{
if ( BaseClass::DrawModel( flags ) == false )
return 0;
if ( !m_bReadyToDraw )
return 0;
return DrawWake();
}

View File

@@ -0,0 +1,187 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
// $NoKeywords: $
//=============================================================================//
#include "cbase.h"
#include "hud.h"
#include <vgui_controls/Controls.h>
#include <Color.h>
#include "c_vehicle_crane.h"
#include "view.h"
#include "vehicle_viewblend_shared.h"
// memdbgon must be the last include file in a .cpp file!!!
#include "tier0/memdbgon.h"
int ScreenTransform( const Vector& point, Vector& screen );
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
class C_PropCannon : public C_BaseAnimating, public IClientVehicle
{
DECLARE_CLASS( C_PropCannon, C_BaseAnimating );
public:
DECLARE_CLIENTCLASS();
DECLARE_DATADESC();
C_PropCannon();
void PreDataUpdate( DataUpdateType_t updateType );
public:
// IClientVehicle overrides.
virtual void GetVehicleViewPosition( int nRole, Vector *pOrigin, QAngle *pAngles, float *pFOV = NULL );
virtual void GetVehicleFOV( float &flFOV ) { flFOV = 0.0f; }
virtual void DrawHudElements();
virtual bool IsPassengerUsingStandardWeapons( int nRole = VEHICLE_ROLE_DRIVER ) { return false; }
virtual void UpdateViewAngles( C_BasePlayer *pLocalPlayer, CUserCmd *pCmd ) {}
virtual C_BaseCombatCharacter *GetPassenger( int nRole );
virtual int GetPassengerRole( C_BaseCombatCharacter *pPassenger );
virtual void GetVehicleClipPlanes( float &flZNear, float &flZFar ) const;
virtual int GetPrimaryAmmoType() const { return -1; }
virtual int GetPrimaryAmmoCount() const { return -1; }
virtual int GetPrimaryAmmoClip() const { return -1; }
virtual bool PrimaryAmmoUsesClips() const { return false; }
virtual int GetJoystickResponseCurve() const { return 0; }
public:
// C_BaseEntity overrides.
virtual IClientVehicle* GetClientVehicle() { return this; }
virtual C_BaseEntity *GetVehicleEnt() { return this; }
virtual void SetupMove( C_BasePlayer *player, CUserCmd *ucmd, IMoveHelper *pHelper, CMoveData *move ) {}
virtual void ProcessMovement( C_BasePlayer *pPlayer, CMoveData *pMoveData ) {}
virtual void FinishMove( C_BasePlayer *player, CUserCmd *ucmd, CMoveData *move ) {}
virtual bool IsPredicted() const { return false; }
virtual void ItemPostFrame( C_BasePlayer *pPlayer ) {}
virtual bool IsSelfAnimating() { return false; };
virtual void GetRenderBounds( Vector& theMins, Vector& theMaxs );
private:
CHandle<C_BasePlayer> m_hPlayer;
CHandle<C_BasePlayer> m_hPrevPlayer;
bool m_bEnterAnimOn;
bool m_bExitAnimOn;
Vector m_vecEyeExitEndpoint;
Vector m_vecOldShadowDir;
ViewSmoothingData_t m_ViewSmoothingData;
};
IMPLEMENT_CLIENTCLASS_DT(C_PropCannon, DT_PropCannon, CPropCannon)
RecvPropEHandle( RECVINFO(m_hPlayer) ),
RecvPropBool( RECVINFO( m_bEnterAnimOn ) ),
RecvPropBool( RECVINFO( m_bExitAnimOn ) ),
RecvPropVector( RECVINFO( m_vecEyeExitEndpoint ) ),
END_RECV_TABLE()
BEGIN_DATADESC( C_PropCannon )
DEFINE_EMBEDDED( m_ViewSmoothingData ),
END_DATADESC()
#define ROLL_CURVE_ZERO 5 // roll less than this is clamped to zero
#define ROLL_CURVE_LINEAR 45 // roll greater than this is copied out
#define PITCH_CURVE_ZERO 10 // pitch less than this is clamped to zero
#define PITCH_CURVE_LINEAR 45 // pitch greater than this is copied out
// spline in between
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
C_PropCannon::C_PropCannon( void )
{
memset( &m_ViewSmoothingData, 0, sizeof( m_ViewSmoothingData ) );
m_ViewSmoothingData.pVehicle = this;
}
//-----------------------------------------------------------------------------
// Purpose:
// Input : updateType -
//-----------------------------------------------------------------------------
void C_PropCannon::PreDataUpdate( DataUpdateType_t updateType )
{
BaseClass::PreDataUpdate( updateType );
m_hPrevPlayer = m_hPlayer;
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
C_BaseCombatCharacter *C_PropCannon::GetPassenger( int nRole )
{
if ( nRole == VEHICLE_ROLE_DRIVER )
return m_hPlayer.Get();
return NULL;
}
//-----------------------------------------------------------------------------
// Returns the role of the passenger
//-----------------------------------------------------------------------------
int C_PropCannon::GetPassengerRole( C_BaseCombatCharacter *pPassenger )
{
if ( m_hPlayer.Get() == pPassenger )
return VEHICLE_ROLE_DRIVER;
return VEHICLE_ROLE_NONE;
}
//-----------------------------------------------------------------------------
// Purpose: Modify the player view/camera while in a vehicle
//-----------------------------------------------------------------------------
void C_PropCannon::GetVehicleViewPosition( int nRole, Vector *pAbsOrigin, QAngle *pAbsAngles, float *pFOV /*=NULL*/ )
{
SharedVehicleViewSmoothing( m_hPlayer,
pAbsOrigin, pAbsAngles,
m_bEnterAnimOn, m_bExitAnimOn,
m_vecEyeExitEndpoint,
&m_ViewSmoothingData,
pFOV );
}
//-----------------------------------------------------------------------------
// Futzes with the clip planes
//-----------------------------------------------------------------------------
void C_PropCannon::GetVehicleClipPlanes( float &flZNear, float &flZFar ) const
{
// FIXME: Need something a better long-term, this fixes the buggy.
flZNear = 6;
}
//-----------------------------------------------------------------------------
// Renders hud elements
//-----------------------------------------------------------------------------
void C_PropCannon::DrawHudElements( )
{
}
//-----------------------------------------------------------------------------
// Purpose:
// Input : theMins -
// theMaxs -
//-----------------------------------------------------------------------------
void C_PropCannon::GetRenderBounds( Vector &theMins, Vector &theMaxs )
{
// This is kind of hacky:( Add 660.0 to the y coordinate of the bounding box to
// allow for the full extension of the crane arm.
BaseClass::GetRenderBounds( theMins, theMaxs );
theMaxs.y += 660.0f;
}

View File

@@ -0,0 +1,151 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
// $NoKeywords: $
//=============================================================================//
#include "cbase.h"
#include "hud.h"
#include <vgui_controls/Controls.h>
#include <Color.h>
#include "c_vehicle_crane.h"
#include "view.h"
// memdbgon must be the last include file in a .cpp file!!!
#include "tier0/memdbgon.h"
int ScreenTransform( const Vector& point, Vector& screen );
IMPLEMENT_CLIENTCLASS_DT(C_PropCrane, DT_PropCrane, CPropCrane)
RecvPropEHandle( RECVINFO(m_hPlayer) ),
RecvPropBool( RECVINFO(m_bMagnetOn) ),
RecvPropBool( RECVINFO( m_bEnterAnimOn ) ),
RecvPropBool( RECVINFO( m_bExitAnimOn ) ),
RecvPropVector( RECVINFO( m_vecEyeExitEndpoint ) ),
END_RECV_TABLE()
BEGIN_DATADESC( C_PropCrane )
DEFINE_EMBEDDED( m_ViewSmoothingData ),
END_DATADESC()
#define ROLL_CURVE_ZERO 5 // roll less than this is clamped to zero
#define ROLL_CURVE_LINEAR 45 // roll greater than this is copied out
#define PITCH_CURVE_ZERO 10 // pitch less than this is clamped to zero
#define PITCH_CURVE_LINEAR 45 // pitch greater than this is copied out
// spline in between
#define CRANE_FOV 75
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
C_PropCrane::C_PropCrane( void )
{
memset( &m_ViewSmoothingData, 0, sizeof( m_ViewSmoothingData ) );
m_ViewSmoothingData.pVehicle = this;
m_ViewSmoothingData.flFOV = CRANE_FOV;
}
//-----------------------------------------------------------------------------
// Purpose:
// Input : updateType -
//-----------------------------------------------------------------------------
void C_PropCrane::PreDataUpdate( DataUpdateType_t updateType )
{
BaseClass::PreDataUpdate( updateType );
m_hPrevPlayer = m_hPlayer;
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void C_PropCrane::PostDataUpdate( DataUpdateType_t updateType )
{
BaseClass::PostDataUpdate( updateType );
// Store off the old shadow direction
if ( m_hPlayer && !m_hPrevPlayer )
{
m_vecOldShadowDir = g_pClientShadowMgr->GetShadowDirection();
//Vector vecDown = m_vecOldShadowDir - Vector(0,0,0.5);
//VectorNormalize( vecDown );
Vector vecDown = Vector(0,0,-1);
g_pClientShadowMgr->SetShadowDirection( vecDown );
}
else if ( !m_hPlayer && m_hPrevPlayer )
{
g_pClientShadowMgr->SetShadowDirection( m_vecOldShadowDir );
}
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
C_BaseCombatCharacter *C_PropCrane::GetPassenger( int nRole )
{
if ( nRole == VEHICLE_ROLE_DRIVER )
return m_hPlayer.Get();
return NULL;
}
//-----------------------------------------------------------------------------
// Returns the role of the passenger
//-----------------------------------------------------------------------------
int C_PropCrane::GetPassengerRole( C_BaseCombatCharacter *pPassenger )
{
if ( m_hPlayer.Get() == pPassenger )
return VEHICLE_ROLE_DRIVER;
return VEHICLE_ROLE_NONE;
}
//-----------------------------------------------------------------------------
// Purpose: Modify the player view/camera while in a vehicle
//-----------------------------------------------------------------------------
void C_PropCrane::GetVehicleViewPosition( int nRole, Vector *pAbsOrigin, QAngle *pAbsAngles, float *pFOV /*=NULL*/ )
{
SharedVehicleViewSmoothing( m_hPlayer,
pAbsOrigin, pAbsAngles,
m_bEnterAnimOn, m_bExitAnimOn,
m_vecEyeExitEndpoint,
&m_ViewSmoothingData,
pFOV );
}
//-----------------------------------------------------------------------------
// Futzes with the clip planes
//-----------------------------------------------------------------------------
void C_PropCrane::GetVehicleClipPlanes( float &flZNear, float &flZFar ) const
{
// FIXME: Need something a better long-term, this fixes the buggy.
flZNear = 6;
}
//-----------------------------------------------------------------------------
// Renders hud elements
//-----------------------------------------------------------------------------
void C_PropCrane::DrawHudElements( )
{
}
//-----------------------------------------------------------------------------
// Purpose:
// Input : theMins -
// theMaxs -
//-----------------------------------------------------------------------------
void C_PropCrane::GetRenderBounds( Vector &theMins, Vector &theMaxs )
{
// This is kind of hacky:( Add 660.0 to the y coordinate of the bounding box to
// allow for the full extension of the crane arm.
BaseClass::GetRenderBounds( theMins, theMaxs );
theMaxs.y += 660.0f;
}

View File

@@ -0,0 +1,80 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
//=============================================================================//
#include "iclientvehicle.h"
#include "vehicle_viewblend_shared.h"
#ifndef C_VEHICLE_CRANE_H
#define C_VEHICLE_CRANE_H
#pragma once
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
class C_PropCrane : public C_BaseAnimating, public IClientVehicle
{
DECLARE_CLASS( C_PropCrane, C_BaseAnimating );
public:
DECLARE_CLIENTCLASS();
DECLARE_DATADESC();
C_PropCrane();
void PreDataUpdate( DataUpdateType_t updateType );
void PostDataUpdate( DataUpdateType_t updateType );
bool IsMagnetOn( void ) { return m_bMagnetOn; }
public:
// IClientVehicle overrides.
virtual void GetVehicleViewPosition( int nRole, Vector *pOrigin, QAngle *pAngles, float *pFOV =NULL );
virtual void GetVehicleFOV( float &flFOV ) { flFOV = 0.0f; }
virtual void DrawHudElements();
virtual bool IsPassengerUsingStandardWeapons( int nRole = VEHICLE_ROLE_DRIVER ) { return false; }
virtual void UpdateViewAngles( C_BasePlayer *pLocalPlayer, CUserCmd *pCmd ) {}
virtual C_BaseCombatCharacter* GetPassenger( int nRole );
virtual int GetPassengerRole( C_BaseCombatCharacter *pPassenger );
virtual void GetVehicleClipPlanes( float &flZNear, float &flZFar ) const;
virtual int GetPrimaryAmmoType() const { return -1; }
virtual int GetPrimaryAmmoCount() const { return -1; }
virtual int GetPrimaryAmmoClip() const { return -1; }
virtual bool PrimaryAmmoUsesClips() const { return false; }
virtual int GetJoystickResponseCurve() const { return 0; }
public:
// C_BaseEntity overrides.
virtual IClientVehicle* GetClientVehicle() { return this; }
virtual C_BaseEntity *GetVehicleEnt() { return this; }
virtual void SetupMove( C_BasePlayer *player, CUserCmd *ucmd, IMoveHelper *pHelper, CMoveData *move ) {}
virtual void ProcessMovement( C_BasePlayer *pPlayer, CMoveData *pMoveData ) {}
virtual void FinishMove( C_BasePlayer *player, CUserCmd *ucmd, CMoveData *move ) {}
virtual bool IsPredicted() const { return false; }
virtual void ItemPostFrame( C_BasePlayer *pPlayer ) {}
virtual bool IsSelfAnimating() { return false; };
virtual void GetRenderBounds( Vector& theMins, Vector& theMaxs );
private:
CHandle<C_BasePlayer> m_hPlayer;
CHandle<C_BasePlayer> m_hPrevPlayer;
bool m_bEnterAnimOn;
bool m_bExitAnimOn;
Vector m_vecEyeExitEndpoint;
bool m_bMagnetOn;
Vector m_vecOldShadowDir;
ViewSmoothingData_t m_ViewSmoothingData;
};
#endif // C_VEHICLE_CRANE_H

View File

@@ -0,0 +1,237 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
//=============================================================================//
#include "cbase.h"
#include "hud.h"
#include "c_physicsprop.h"
#include "iclientvehicle.h"
#include <vgui_controls/Controls.h>
#include <Color.h>
#include "vehicle_viewblend_shared.h"
// memdbgon must be the last include file in a .cpp file!!!
#include "tier0/memdbgon.h"
extern float RemapAngleRange( float startInterval, float endInterval, float value );
#define ROLL_CURVE_ZERO 5 // roll less than this is clamped to zero
#define ROLL_CURVE_LINEAR 45 // roll greater than this is copied out
#define PITCH_CURVE_ZERO 10 // pitch less than this is clamped to zero
#define PITCH_CURVE_LINEAR 45 // pitch greater than this is copied out
// spline in between
#define POD_VIEW_FOV 90
#define POD_VIEW_YAW_MIN -60
#define POD_VIEW_YAW_MAX 60
#define POD_VIEW_PITCH_MIN -90
#define POD_VIEW_PITCH_MAX 38 // Don't let players look down and see that the pod is empty
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
class C_PropVehiclePrisonerPod : public C_PhysicsProp, public IClientVehicle
{
DECLARE_CLASS( C_PropVehiclePrisonerPod, C_PhysicsProp );
public:
DECLARE_CLIENTCLASS();
DECLARE_DATADESC();
C_PropVehiclePrisonerPod();
void PreDataUpdate( DataUpdateType_t updateType );
void PostDataUpdate( DataUpdateType_t updateType );
public:
// IClientVehicle overrides.
virtual void GetVehicleViewPosition( int nRole, Vector *pOrigin, QAngle *pAngles, float *pFOV = NULL );
virtual void GetVehicleFOV( float &flFOV )
{
flFOV = m_flFOV;
}
virtual void DrawHudElements();
virtual bool IsPassengerUsingStandardWeapons( int nRole = VEHICLE_ROLE_DRIVER ) { return false; }
virtual void UpdateViewAngles( C_BasePlayer *pLocalPlayer, CUserCmd *pCmd );
virtual C_BaseCombatCharacter* GetPassenger( int nRole );
virtual int GetPassengerRole( C_BaseCombatCharacter *pEnt );
virtual void GetVehicleClipPlanes( float &flZNear, float &flZFar ) const;
virtual int GetPrimaryAmmoType() const { return -1; }
virtual int GetPrimaryAmmoCount() const { return -1; }
virtual int GetPrimaryAmmoClip() const { return -1; }
virtual bool PrimaryAmmoUsesClips() const { return false; }
virtual int GetJoystickResponseCurve() const { return 0; }
public:
// C_BaseEntity overrides.
virtual IClientVehicle* GetClientVehicle() { return this; }
virtual C_BaseEntity *GetVehicleEnt() { return this; }
virtual void SetupMove( C_BasePlayer *player, CUserCmd *ucmd, IMoveHelper *pHelper, CMoveData *move ) {}
virtual void ProcessMovement( C_BasePlayer *pPlayer, CMoveData *pMoveData ) {}
virtual void FinishMove( C_BasePlayer *player, CUserCmd *ucmd, CMoveData *move ) {}
virtual bool IsPredicted() const { return false; }
virtual void ItemPostFrame( C_BasePlayer *pPlayer ) {}
virtual bool IsSelfAnimating() { return false; };
private:
CHandle<C_BasePlayer> m_hPlayer;
CHandle<C_BasePlayer> m_hPrevPlayer;
bool m_bEnterAnimOn;
bool m_bExitAnimOn;
Vector m_vecEyeExitEndpoint;
float m_flFOV; // The current FOV (changes during entry/exit anims).
ViewSmoothingData_t m_ViewSmoothingData;
};
IMPLEMENT_CLIENTCLASS_DT(C_PropVehiclePrisonerPod, DT_PropVehiclePrisonerPod, CPropVehiclePrisonerPod)
RecvPropEHandle( RECVINFO(m_hPlayer) ),
RecvPropBool( RECVINFO( m_bEnterAnimOn ) ),
RecvPropBool( RECVINFO( m_bExitAnimOn ) ),
RecvPropVector( RECVINFO( m_vecEyeExitEndpoint ) ),
END_RECV_TABLE()
BEGIN_DATADESC( C_PropVehiclePrisonerPod )
DEFINE_EMBEDDED( m_ViewSmoothingData ),
END_DATADESC()
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
C_PropVehiclePrisonerPod::C_PropVehiclePrisonerPod( void )
{
memset( &m_ViewSmoothingData, 0, sizeof( m_ViewSmoothingData ) );
m_ViewSmoothingData.pVehicle = this;
m_ViewSmoothingData.bClampEyeAngles = true;
m_ViewSmoothingData.flPitchCurveZero = PITCH_CURVE_ZERO;
m_ViewSmoothingData.flPitchCurveLinear = PITCH_CURVE_LINEAR;
m_ViewSmoothingData.flRollCurveZero = ROLL_CURVE_ZERO;
m_ViewSmoothingData.flRollCurveLinear = ROLL_CURVE_LINEAR;
m_ViewSmoothingData.flFOV = POD_VIEW_FOV;
m_flFOV = 0;
}
//-----------------------------------------------------------------------------
// Purpose:
// Input : updateType -
//-----------------------------------------------------------------------------
void C_PropVehiclePrisonerPod::PreDataUpdate( DataUpdateType_t updateType )
{
BaseClass::PreDataUpdate( updateType );
m_hPrevPlayer = m_hPlayer;
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void C_PropVehiclePrisonerPod::PostDataUpdate( DataUpdateType_t updateType )
{
BaseClass::PostDataUpdate( updateType );
if ( !m_hPlayer && m_hPrevPlayer )
{
// They have just exited the vehicle.
// Sometimes we never reach the end of our exit anim, such as if the
// animation doesn't have fadeout 0 specified in the QC, so we fail to
// catch it in VehicleViewSmoothing. Catch it here instead.
m_ViewSmoothingData.bWasRunningAnim = false;
}
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
C_BaseCombatCharacter *C_PropVehiclePrisonerPod::GetPassenger( int nRole )
{
if ( nRole == VEHICLE_ROLE_DRIVER )
return m_hPlayer.Get();
return NULL;
}
//-----------------------------------------------------------------------------
// Returns the role of the passenger
//-----------------------------------------------------------------------------
int C_PropVehiclePrisonerPod::GetPassengerRole( C_BaseCombatCharacter *pPassenger )
{
if ( m_hPlayer.Get() == pPassenger )
return VEHICLE_ROLE_DRIVER;
return VEHICLE_ROLE_NONE;
}
//-----------------------------------------------------------------------------
// Purpose: Modify the player view/camera while in a vehicle
//-----------------------------------------------------------------------------
void C_PropVehiclePrisonerPod::GetVehicleViewPosition( int nRole, Vector *pAbsOrigin, QAngle *pAbsAngles, float *pFOV /*=NULL*/ )
{
SharedVehicleViewSmoothing( m_hPlayer,
pAbsOrigin, pAbsAngles,
m_bEnterAnimOn, m_bExitAnimOn,
m_vecEyeExitEndpoint,
&m_ViewSmoothingData,
pFOV );
}
//-----------------------------------------------------------------------------
// Purpose:
// Input : pLocalPlayer -
// pCmd -
//-----------------------------------------------------------------------------
void C_PropVehiclePrisonerPod::UpdateViewAngles( C_BasePlayer *pLocalPlayer, CUserCmd *pCmd )
{
int eyeAttachmentIndex = LookupAttachment( "vehicle_driver_eyes" );
Vector vehicleEyeOrigin;
QAngle vehicleEyeAngles;
GetAttachmentLocal( eyeAttachmentIndex, vehicleEyeOrigin, vehicleEyeAngles );
// Limit the yaw.
float flAngleDiff = AngleDiff( pCmd->viewangles.y, vehicleEyeAngles.y );
flAngleDiff = clamp( flAngleDiff, POD_VIEW_YAW_MIN, POD_VIEW_YAW_MAX );
pCmd->viewangles.y = vehicleEyeAngles.y + flAngleDiff;
// Limit the pitch -- don't let them look down into the empty pod!
flAngleDiff = AngleDiff( pCmd->viewangles.x, vehicleEyeAngles.x );
flAngleDiff = clamp( flAngleDiff, POD_VIEW_PITCH_MIN, POD_VIEW_PITCH_MAX );
pCmd->viewangles.x = vehicleEyeAngles.x + flAngleDiff;
}
//-----------------------------------------------------------------------------
// Futzes with the clip planes
//-----------------------------------------------------------------------------
void C_PropVehiclePrisonerPod::GetVehicleClipPlanes( float &flZNear, float &flZFar ) const
{
// Pod doesn't need to adjust the clip planes.
//flZNear = 6;
}
//-----------------------------------------------------------------------------
// Renders hud elements
//-----------------------------------------------------------------------------
void C_PropVehiclePrisonerPod::DrawHudElements( )
{
}

View File

@@ -0,0 +1,121 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
//=============================================================================//
#include "cbase.h"
#include "particles_simple.h"
// memdbgon must be the last include file in a .cpp file!!!
#include "tier0/memdbgon.h"
class C_WaterBullet : public C_BaseAnimating
{
public:
DECLARE_CLIENTCLASS();
DECLARE_CLASS( C_WaterBullet, C_BaseAnimating );
C_WaterBullet( void ) {};
~C_WaterBullet( void ) {};
void OnDataChanged( DataUpdateType_t updateType )
{
BaseClass::OnDataChanged( updateType );
if ( updateType == DATA_UPDATE_CREATED )
{
m_pEmitter = CSimpleEmitter::Create( "FX_Bubble" );
m_pEmitter->SetSortOrigin( GetAbsOrigin() );
m_vecLastOrigin = GetAbsOrigin();
}
}
#define BUBBLES_PER_INCH 0.2
void AddEntity( void )
{
Vector direction = GetAbsOrigin() - m_vecLastOrigin;
float flDist = VectorNormalize( direction );
int numBubbles = (int) ( flDist * BUBBLES_PER_INCH );
if ( numBubbles < 1 )
numBubbles = 1;
// Make bubbles
SimpleParticle *sParticle;
Vector offset;
for ( int i = 0; i < numBubbles; i++ )
{
offset = m_vecLastOrigin + ( direction * ( flDist / numBubbles ) * i ) + RandomVector( -2.5f, 2.5f );
sParticle = (SimpleParticle *) m_pEmitter->AddParticle( sizeof(SimpleParticle), m_pEmitter->GetPMaterial( "effects/bubble" ), offset );
if ( sParticle )
{
sParticle->m_flLifetime = 0.0f;
sParticle->m_flDieTime = random->RandomFloat( 0.75f, 1.25f );
sParticle->m_flRoll = 0;
sParticle->m_flRollDelta = 0;
unsigned char color = random->RandomInt( 128, 255 );
sParticle->m_uchColor[0] = color;
sParticle->m_uchColor[1] = color;
sParticle->m_uchColor[2] = color;
sParticle->m_uchStartAlpha = 255;
sParticle->m_uchEndAlpha = 0;
sParticle->m_uchStartSize = random->RandomInt( 1, 2 );
sParticle->m_uchEndSize = sParticle->m_uchStartSize;
sParticle->m_vecVelocity = ( direction * 64.0f ) + Vector( 0, 0, 32 );
}
sParticle = (SimpleParticle *) m_pEmitter->AddParticle( sizeof(SimpleParticle), m_pEmitter->GetPMaterial( "effects/splash2" ), offset );
if ( sParticle )
{
sParticle->m_flLifetime = 0.0f;
sParticle->m_flDieTime = 0.2f;
sParticle->m_flRoll = random->RandomInt( 0, 360 );
sParticle->m_flRollDelta = random->RandomInt( -4, 4 );;
unsigned char color = random->RandomInt( 200, 255 );
sParticle->m_uchColor[0] = color;
sParticle->m_uchColor[1] = color;
sParticle->m_uchColor[2] = color;
sParticle->m_uchStartAlpha = 128;
sParticle->m_uchEndAlpha = 0;
sParticle->m_uchStartSize = 2;
sParticle->m_uchEndSize = sParticle->m_uchStartSize * 4;
sParticle->m_vecVelocity = ( direction * 64.0f ) + Vector( 0, 0, 32 );
}
}
// Save our last position
m_vecLastOrigin = GetAbsOrigin();
BaseClass::AddEntity();
}
bool ShouldDraw( void ) { return true; }
private:
C_WaterBullet( const C_WaterBullet & );
CSmartPtr<CSimpleEmitter> m_pEmitter;
Vector m_vecLastOrigin;
};
IMPLEMENT_CLIENTCLASS_DT( C_WaterBullet, DT_WaterBullet, CWaterBullet )
END_RECV_TABLE()

View File

@@ -0,0 +1,49 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
//=============================================================================//
#include "cbase.h"
#include "c_weapon__stubs.h"
#include "basehlcombatweapon_shared.h"
#include "c_basehlcombatweapon.h"
// memdbgon must be the last include file in a .cpp file!!!
#include "tier0/memdbgon.h"
STUB_WEAPON_CLASS( cycler_weapon, WeaponCycler, C_BaseCombatWeapon );
STUB_WEAPON_CLASS( weapon_binoculars, WeaponBinoculars, C_BaseHLCombatWeapon );
STUB_WEAPON_CLASS( weapon_bugbait, WeaponBugBait, C_BaseHLCombatWeapon );
STUB_WEAPON_CLASS( weapon_flaregun, Flaregun, C_BaseHLCombatWeapon );
STUB_WEAPON_CLASS( weapon_annabelle, WeaponAnnabelle, C_BaseHLCombatWeapon );
STUB_WEAPON_CLASS( weapon_gauss, WeaponGaussGun, C_BaseHLCombatWeapon );
STUB_WEAPON_CLASS( weapon_cubemap, WeaponCubemap, C_BaseCombatWeapon );
STUB_WEAPON_CLASS( weapon_alyxgun, WeaponAlyxGun, C_HLSelectFireMachineGun );
STUB_WEAPON_CLASS( weapon_citizenpackage, WeaponCitizenPackage, C_BaseHLCombatWeapon );
STUB_WEAPON_CLASS( weapon_citizensuitcase, WeaponCitizenSuitcase, C_WeaponCitizenPackage );
#ifndef HL2MP
STUB_WEAPON_CLASS( weapon_ar2, WeaponAR2, C_HLMachineGun );
STUB_WEAPON_CLASS( weapon_frag, WeaponFrag, C_BaseHLCombatWeapon );
STUB_WEAPON_CLASS( weapon_rpg, WeaponRPG, C_BaseHLCombatWeapon );
STUB_WEAPON_CLASS( weapon_pistol, WeaponPistol, C_BaseHLCombatWeapon );
STUB_WEAPON_CLASS( weapon_shotgun, WeaponShotgun, C_BaseHLCombatWeapon );
STUB_WEAPON_CLASS( weapon_smg1, WeaponSMG1, C_HLSelectFireMachineGun );
STUB_WEAPON_CLASS( weapon_357, Weapon357, C_BaseHLCombatWeapon );
STUB_WEAPON_CLASS( weapon_crossbow, WeaponCrossbow, C_BaseHLCombatWeapon );
#ifndef MAPBASE
STUB_WEAPON_CLASS( weapon_slam, Weapon_SLAM, C_BaseHLCombatWeapon );
#endif
STUB_WEAPON_CLASS( weapon_crowbar, WeaponCrowbar, C_BaseHLBludgeonWeapon );
#ifdef HL2_EPISODIC
STUB_WEAPON_CLASS( weapon_hopwire, WeaponHopwire, C_BaseHLCombatWeapon );
//STUB_WEAPON_CLASS( weapon_proto1, WeaponProto1, C_BaseHLCombatWeapon );
#endif
#ifdef HL2_LOSTCOAST
STUB_WEAPON_CLASS( weapon_oldmanharpoon, WeaponOldManHarpoon, C_WeaponCitizenPackage );
#endif
#endif

View File

@@ -0,0 +1,159 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
//=============================================================================//
#include "cbase.h"
#include "model_types.h"
#include "clienteffectprecachesystem.h"
#include "fx.h"
#include "c_te_effect_dispatch.h"
#include "beamdraw.h"
CLIENTEFFECT_REGISTER_BEGIN( PrecacheEffectCrossbow )
CLIENTEFFECT_MATERIAL( "effects/muzzleflash1" )
CLIENTEFFECT_REGISTER_END()
//
// Crossbow bolt
//
class C_CrossbowBolt : public C_BaseCombatCharacter
{
DECLARE_CLASS( C_CrossbowBolt, C_BaseCombatCharacter );
DECLARE_CLIENTCLASS();
public:
C_CrossbowBolt( void );
virtual RenderGroup_t GetRenderGroup( void )
{
// We want to draw translucent bits as well as our main model
return RENDER_GROUP_TWOPASS;
}
virtual void ClientThink( void );
virtual void OnDataChanged( DataUpdateType_t updateType );
virtual int DrawModel( int flags );
private:
C_CrossbowBolt( const C_CrossbowBolt & ); // not defined, not accessible
Vector m_vecLastOrigin;
bool m_bUpdated;
};
IMPLEMENT_CLIENTCLASS_DT( C_CrossbowBolt, DT_CrossbowBolt, CCrossbowBolt )
END_RECV_TABLE()
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
C_CrossbowBolt::C_CrossbowBolt( void )
{
}
//-----------------------------------------------------------------------------
// Purpose:
// Input : updateType -
//-----------------------------------------------------------------------------
void C_CrossbowBolt::OnDataChanged( DataUpdateType_t updateType )
{
BaseClass::OnDataChanged( updateType );
if ( updateType == DATA_UPDATE_CREATED )
{
m_bUpdated = false;
m_vecLastOrigin = GetAbsOrigin();
SetNextClientThink( CLIENT_THINK_ALWAYS );
}
}
//-----------------------------------------------------------------------------
// Purpose:
// Input : flags -
// Output : int
//-----------------------------------------------------------------------------
int C_CrossbowBolt::DrawModel( int flags )
{
// See if we're drawing the motion blur
if ( flags & STUDIO_TRANSPARENCY )
{
float color[3];
IMaterial *pBlurMaterial = materials->FindMaterial( "effects/muzzleflash1", NULL, false );
Vector vecDir = GetAbsOrigin() - m_vecLastOrigin;
float speed = VectorNormalize( vecDir );
speed = clamp( speed, 0, 32 );
if ( speed > 0 )
{
float stepSize = MIN( ( speed * 0.5f ), 4.0f );
Vector spawnPos = GetAbsOrigin() + ( vecDir * 24.0f );
Vector spawnStep = -vecDir * stepSize;
CMatRenderContextPtr pRenderContext( materials );
pRenderContext->Bind( pBlurMaterial );
float alpha;
// Draw the motion blurred trail
for ( int i = 0; i < 20; i++ )
{
spawnPos += spawnStep;
alpha = RemapValClamped( i, 5, 11, 0.25f, 0.05f );
color[0] = color[1] = color[2] = alpha;
DrawHalo( pBlurMaterial, spawnPos, 3.0f, color );
}
}
if ( gpGlobals->frametime > 0.0f && !m_bUpdated)
{
m_bUpdated = true;
m_vecLastOrigin = GetAbsOrigin();
}
return 1;
}
// Draw the normal portion
return BaseClass::DrawModel( flags );
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void C_CrossbowBolt::ClientThink( void )
{
m_bUpdated = false;
}
//-----------------------------------------------------------------------------
// Purpose:
// Input : &data -
//-----------------------------------------------------------------------------
void CrosshairLoadCallback( const CEffectData &data )
{
IClientRenderable *pRenderable = data.GetRenderable( );
if ( !pRenderable )
return;
Vector position;
QAngle angles;
// If we found the attachment, emit sparks there
if ( pRenderable->GetAttachment( data.m_nAttachmentIndex, position, angles ) )
{
FX_ElectricSpark( position, 1.0f, 1.0f, NULL );
}
}
DECLARE_CLIENT_EFFECT( "CrossbowLoad", CrosshairLoadCallback );

View File

@@ -0,0 +1,166 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
// $NoKeywords: $
//===========================================================================//
#include "cbase.h"
#include "hud.h"
#include "in_buttons.h"
#include "beamdraw.h"
#include "c_weapon__stubs.h"
#include "clienteffectprecachesystem.h"
// memdbgon must be the last include file in a .cpp file!!!
#include "tier0/memdbgon.h"
CLIENTEFFECT_REGISTER_BEGIN( PrecacheEffectGravityGun )
CLIENTEFFECT_MATERIAL( "sprites/physbeam" )
CLIENTEFFECT_REGISTER_END()
class C_BeamQuadratic : public CDefaultClientRenderable
{
public:
C_BeamQuadratic();
void Update( C_BaseEntity *pOwner );
// IClientRenderable
virtual const Vector& GetRenderOrigin( void ) { return m_worldPosition; }
virtual const QAngle& GetRenderAngles( void ) { return vec3_angle; }
virtual bool ShouldDraw( void ) { return true; }
virtual bool IsTransparent( void ) { return true; }
virtual bool ShouldReceiveProjectedTextures( int flags ) { return false; }
virtual int DrawModel( int flags );
// Returns the bounds relative to the origin (render bounds)
virtual void GetRenderBounds( Vector& mins, Vector& maxs )
{
// bogus. But it should draw if you can see the end point
mins.Init(-32,-32,-32);
maxs.Init(32,32,32);
}
C_BaseEntity *m_pOwner;
Vector m_targetPosition;
Vector m_worldPosition;
int m_active;
int m_glueTouching;
int m_viewModelIndex;
};
class C_WeaponGravityGun : public C_BaseCombatWeapon
{
DECLARE_CLASS( C_WeaponGravityGun, C_BaseCombatWeapon );
public:
C_WeaponGravityGun() {}
DECLARE_CLIENTCLASS();
DECLARE_PREDICTABLE();
int KeyInput( int down, ButtonCode_t keynum, const char *pszCurrentBinding )
{
if ( gHUD.m_iKeyBits & IN_ATTACK )
{
switch ( keynum )
{
case MOUSE_WHEEL_UP:
gHUD.m_iKeyBits |= IN_WEAPON1;
return 0;
case MOUSE_WHEEL_DOWN:
gHUD.m_iKeyBits |= IN_WEAPON2;
return 0;
}
}
// Allow engine to process
return BaseClass::KeyInput( down, keynum, pszCurrentBinding );
}
void OnDataChanged( DataUpdateType_t updateType )
{
BaseClass::OnDataChanged( updateType );
m_beam.Update( this );
}
private:
C_WeaponGravityGun( const C_WeaponGravityGun & );
C_BeamQuadratic m_beam;
};
STUB_WEAPON_CLASS_IMPLEMENT( weapon_physgun, C_WeaponGravityGun );
IMPLEMENT_CLIENTCLASS_DT( C_WeaponGravityGun, DT_WeaponGravityGun, CWeaponGravityGun )
RecvPropVector( RECVINFO_NAME(m_beam.m_targetPosition,m_targetPosition) ),
RecvPropVector( RECVINFO_NAME(m_beam.m_worldPosition, m_worldPosition) ),
RecvPropInt( RECVINFO_NAME(m_beam.m_active, m_active) ),
RecvPropInt( RECVINFO_NAME(m_beam.m_glueTouching, m_glueTouching) ),
RecvPropInt( RECVINFO_NAME(m_beam.m_viewModelIndex, m_viewModelIndex) ),
END_RECV_TABLE()
C_BeamQuadratic::C_BeamQuadratic()
{
m_pOwner = NULL;
}
void C_BeamQuadratic::Update( C_BaseEntity *pOwner )
{
m_pOwner = pOwner;
if ( m_active )
{
if ( m_hRenderHandle == INVALID_CLIENT_RENDER_HANDLE )
{
ClientLeafSystem()->AddRenderable( this, RENDER_GROUP_TRANSLUCENT_ENTITY );
}
else
{
ClientLeafSystem()->RenderableChanged( m_hRenderHandle );
}
}
else if ( !m_active && m_hRenderHandle != INVALID_CLIENT_RENDER_HANDLE )
{
ClientLeafSystem()->RemoveRenderable( m_hRenderHandle );
}
}
int C_BeamQuadratic::DrawModel( int )
{
Vector points[3];
QAngle tmpAngle;
if ( !m_active )
return 0;
C_BaseEntity *pEnt = cl_entitylist->GetEnt( m_viewModelIndex );
if ( !pEnt )
return 0;
pEnt->GetAttachment( 1, points[0], tmpAngle );
points[1] = 0.5 * (m_targetPosition + points[0]);
// a little noise 11t & 13t should be somewhat non-periodic looking
//points[1].z += 4*sin( gpGlobals->curtime*11 ) + 5*cos( gpGlobals->curtime*13 );
points[2] = m_worldPosition;
IMaterial *pMat = materials->FindMaterial( "sprites/physbeam", TEXTURE_GROUP_CLIENT_EFFECTS );
Vector color;
if ( m_glueTouching )
{
color.Init(1,0,0);
}
else
{
color.Init(1,1,1);
}
float scrollOffset = gpGlobals->curtime - (int)gpGlobals->curtime;
materials->Bind( pMat );
DrawBeamQuadratic( points[0], points[1], points[2], 13, color, scrollOffset );
return 1;
}

View File

@@ -0,0 +1,442 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
//=============================================================================//
#include "cbase.h"
#include "c_weapon__stubs.h"
#include "c_basehlcombatweapon.h"
#include "fx.h"
#include "particles_localspace.h"
#include "view.h"
#include "particles_attractor.h"
class C_WeaponPhysCannon: public C_BaseHLCombatWeapon
{
DECLARE_CLASS( C_WeaponPhysCannon, C_BaseHLCombatWeapon );
public:
C_WeaponPhysCannon( void );
DECLARE_CLIENTCLASS();
DECLARE_PREDICTABLE();
virtual void OnDataChanged( DataUpdateType_t updateType );
virtual int DrawModel( int flags );
virtual void ClientThink( void );
virtual bool ShouldUseLargeViewModelVROverride() OVERRIDE { return true; }
private:
bool SetupEmitter( void );
bool m_bIsCurrentlyUpgrading;
float m_flTimeForceView;
float m_flTimeIgnoreForceView;
bool m_bWasUpgraded;
CSmartPtr<CLocalSpaceEmitter> m_pLocalEmitter;
CSmartPtr<CSimpleEmitter> m_pEmitter;
CSmartPtr<CParticleAttractor> m_pAttractor;
};
STUB_WEAPON_CLASS_IMPLEMENT( weapon_physcannon, C_WeaponPhysCannon );
IMPLEMENT_CLIENTCLASS_DT( C_WeaponPhysCannon, DT_WeaponPhysCannon, CWeaponPhysCannon )
RecvPropBool( RECVINFO( m_bIsCurrentlyUpgrading ) ),
RecvPropFloat( RECVINFO( m_flTimeForceView) ),
END_RECV_TABLE()
//-----------------------------------------------------------------------------
// Constructor
//-----------------------------------------------------------------------------
C_WeaponPhysCannon::C_WeaponPhysCannon( void )
{
m_bWasUpgraded = false;
m_flTimeIgnoreForceView = -1;
}
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
void C_WeaponPhysCannon::OnDataChanged( DataUpdateType_t updateType )
{
BaseClass::OnDataChanged( updateType );
SetNextClientThink( CLIENT_THINK_ALWAYS );
}
//-----------------------------------------------------------------------------
// Purpose:
// Output : Returns true on success, false on failure.
//-----------------------------------------------------------------------------
bool C_WeaponPhysCannon::SetupEmitter( void )
{
if ( !m_pLocalEmitter.IsValid() )
{
m_pLocalEmitter = CLocalSpaceEmitter::Create( "physpowerup", GetRefEHandle(), LookupAttachment( "core" ) );
if ( m_pLocalEmitter.IsValid() == false )
return false;
}
if ( !m_pAttractor.IsValid() )
{
m_pAttractor = CParticleAttractor::Create( vec3_origin, "physpowerup_att" );
if ( m_pAttractor.IsValid() == false )
return false;
}
if ( !m_pEmitter.IsValid() )
{
m_pEmitter = CSimpleEmitter::Create( "physpowerup_glow" );
if ( m_pEmitter.IsValid() == false )
return false;
}
return true;
}
//-----------------------------------------------------------------------------
// Sorts the components of a vector
//-----------------------------------------------------------------------------
static inline void SortAbsVectorComponents( const Vector& src, int* pVecIdx )
{
Vector absVec( fabs(src[0]), fabs(src[1]), fabs(src[2]) );
int maxIdx = (absVec[0] > absVec[1]) ? 0 : 1;
if (absVec[2] > absVec[maxIdx])
{
maxIdx = 2;
}
// always choose something right-handed....
switch( maxIdx )
{
case 0:
pVecIdx[0] = 1;
pVecIdx[1] = 2;
pVecIdx[2] = 0;
break;
case 1:
pVecIdx[0] = 2;
pVecIdx[1] = 0;
pVecIdx[2] = 1;
break;
case 2:
pVecIdx[0] = 0;
pVecIdx[1] = 1;
pVecIdx[2] = 2;
break;
}
}
//-----------------------------------------------------------------------------
// Compute the bounding box's center, size, and basis
//-----------------------------------------------------------------------------
void ComputeRenderInfo( mstudiobbox_t *pHitBox, const matrix3x4_t &hitboxToWorld,
Vector *pVecAbsOrigin, Vector *pXVec, Vector *pYVec )
{
// Compute the center of the hitbox in worldspace
Vector vecHitboxCenter;
VectorAdd( pHitBox->bbmin, pHitBox->bbmax, vecHitboxCenter );
vecHitboxCenter *= 0.5f;
VectorTransform( vecHitboxCenter, hitboxToWorld, *pVecAbsOrigin );
// Get the object's basis
Vector vec[3];
MatrixGetColumn( hitboxToWorld, 0, vec[0] );
MatrixGetColumn( hitboxToWorld, 1, vec[1] );
MatrixGetColumn( hitboxToWorld, 2, vec[2] );
// vec[1] *= -1.0f;
Vector vecViewDir;
VectorSubtract( CurrentViewOrigin(), *pVecAbsOrigin, vecViewDir );
VectorNormalize( vecViewDir );
// Project the shadow casting direction into the space of the hitbox
Vector localViewDir;
localViewDir[0] = DotProduct( vec[0], vecViewDir );
localViewDir[1] = DotProduct( vec[1], vecViewDir );
localViewDir[2] = DotProduct( vec[2], vecViewDir );
// Figure out which vector has the largest component perpendicular
// to the view direction...
// Sort by how perpendicular it is
int vecIdx[3];
SortAbsVectorComponents( localViewDir, vecIdx );
// Here's our hitbox basis vectors; namely the ones that are
// most perpendicular to the view direction
*pXVec = vec[vecIdx[0]];
*pYVec = vec[vecIdx[1]];
// Project them into a plane perpendicular to the view direction
*pXVec -= vecViewDir * DotProduct( vecViewDir, *pXVec );
*pYVec -= vecViewDir * DotProduct( vecViewDir, *pYVec );
VectorNormalize( *pXVec );
VectorNormalize( *pYVec );
// Compute the hitbox size
Vector boxSize;
VectorSubtract( pHitBox->bbmax, pHitBox->bbmin, boxSize );
// We project the two longest sides into the vectors perpendicular
// to the projection direction, then add in the projection of the perp direction
Vector2D size( boxSize[vecIdx[0]], boxSize[vecIdx[1]] );
size.x *= fabs( DotProduct( vec[vecIdx[0]], *pXVec ) );
size.y *= fabs( DotProduct( vec[vecIdx[1]], *pYVec ) );
// Add the third component into x and y
size.x += boxSize[vecIdx[2]] * fabs( DotProduct( vec[vecIdx[2]], *pXVec ) );
size.y += boxSize[vecIdx[2]] * fabs( DotProduct( vec[vecIdx[2]], *pYVec ) );
// Bloat a bit, since the shadow wants to extend outside the model a bit
size *= 2.0f;
// Clamp the minimum size
Vector2DMax( size, Vector2D(10.0f, 10.0f), size );
// Factor the size into the xvec + yvec
(*pXVec) *= size.x * 0.5f;
(*pYVec) *= size.y * 0.5f;
}
//-----------------------------------------------------------------------------
// Purpose:
// Input : flags -
// Output : int
//-----------------------------------------------------------------------------
int C_WeaponPhysCannon::DrawModel( int flags )
{
// If we're not ugrading, don't do anything special
if ( m_bIsCurrentlyUpgrading == false && m_bWasUpgraded == false )
return BaseClass::DrawModel( flags );
if ( gpGlobals->frametime == 0 )
return BaseClass::DrawModel( flags );
if ( !m_bReadyToDraw )
return 0;
m_bWasUpgraded = true;
// Create the particle emitter if it's not already
if ( SetupEmitter() )
{
// Add the power-up particles
// See if we should draw
if ( m_bReadyToDraw == false )
return 0;
C_BaseAnimating *pAnimating = GetBaseAnimating();
if (!pAnimating)
return 0;
matrix3x4_t *hitboxbones[MAXSTUDIOBONES];
if ( !pAnimating->HitboxToWorldTransforms( hitboxbones ) )
return 0;
studiohdr_t *pStudioHdr = modelinfo->GetStudiomodel( pAnimating->GetModel() );
if (!pStudioHdr)
return false;
mstudiohitboxset_t *set = pStudioHdr->pHitboxSet( pAnimating->GetHitboxSet() );
if ( !set )
return false;
int i;
float fadePerc = 1.0f;
if ( m_bIsCurrentlyUpgrading )
{
Vector vecSkew = vec3_origin;
// Skew the particles in front or in back of their targets
vecSkew = CurrentViewForward() * 4.0f;
float spriteScale = 1.0f;
spriteScale = clamp( spriteScale, 0.75f, 1.0f );
SimpleParticle *sParticle;
for ( i = 0; i < set->numhitboxes; ++i )
{
Vector vecAbsOrigin, xvec, yvec;
mstudiobbox_t *pBox = set->pHitbox(i);
ComputeRenderInfo( pBox, *hitboxbones[pBox->bone], &vecAbsOrigin, &xvec, &yvec );
Vector offset;
Vector xDir, yDir;
xDir = xvec;
float xScale = VectorNormalize( xDir ) * 0.75f;
yDir = yvec;
float yScale = VectorNormalize( yDir ) * 0.75f;
int numParticles = clamp( 4.0f * fadePerc, 1, 3 );
for ( int j = 0; j < numParticles; j++ )
{
offset = xDir * Helper_RandomFloat( -xScale*0.5f, xScale*0.5f ) + yDir * Helper_RandomFloat( -yScale*0.5f, yScale*0.5f );
offset += vecSkew;
sParticle = (SimpleParticle *) m_pEmitter->AddParticle( sizeof(SimpleParticle), m_pEmitter->GetPMaterial( "effects/combinemuzzle1" ), vecAbsOrigin + offset );
if ( sParticle == NULL )
return 1;
sParticle->m_vecVelocity = vec3_origin;
sParticle->m_uchStartSize = 16.0f * spriteScale;
sParticle->m_flDieTime = 0.2f;
sParticle->m_flLifetime = 0.0f;
sParticle->m_flRoll = Helper_RandomInt( 0, 360 );
sParticle->m_flRollDelta = Helper_RandomFloat( -2.0f, 2.0f );
float alpha = 40;
sParticle->m_uchColor[0] = alpha;
sParticle->m_uchColor[1] = alpha;
sParticle->m_uchColor[2] = alpha;
sParticle->m_uchStartAlpha = alpha;
sParticle->m_uchEndAlpha = 0;
sParticle->m_uchEndSize = sParticle->m_uchStartSize * 2;
}
}
}
}
int attachment = LookupAttachment( "core" );
Vector coreOrigin;
QAngle coreAngles;
GetAttachment( attachment, coreOrigin, coreAngles );
SimpleParticle *sParticle;
// Do the core effects
for ( int i = 0; i < 4; i++ )
{
sParticle = (SimpleParticle *) m_pLocalEmitter->AddParticle( sizeof(SimpleParticle), m_pLocalEmitter->GetPMaterial( "effects/strider_muzzle" ), vec3_origin );
if ( sParticle == NULL )
return 1;
sParticle->m_vecVelocity = vec3_origin;
sParticle->m_flDieTime = 0.1f;
sParticle->m_flLifetime = 0.0f;
sParticle->m_flRoll = Helper_RandomInt( 0, 360 );
sParticle->m_flRollDelta = 0.0f;
float alpha = 255;
sParticle->m_uchColor[0] = alpha;
sParticle->m_uchColor[1] = alpha;
sParticle->m_uchColor[2] = alpha;
sParticle->m_uchStartAlpha = alpha;
sParticle->m_uchEndAlpha = 0;
if ( i < 2 )
{
sParticle->m_uchStartSize = random->RandomFloat( 1, 2 ) * (i+1);
sParticle->m_uchEndSize = sParticle->m_uchStartSize * 2.0f;
}
else
{
if ( random->RandomInt( 0, 20 ) == 0 )
{
sParticle->m_uchStartSize = random->RandomFloat( 1, 2 ) * (i+1);
sParticle->m_uchEndSize = sParticle->m_uchStartSize * 4.0f;
sParticle->m_flDieTime = 0.25f;
}
else
{
sParticle->m_uchStartSize = random->RandomFloat( 1, 2 ) * (i+1);
sParticle->m_uchEndSize = sParticle->m_uchStartSize * 2.0f;
}
}
}
if ( m_bWasUpgraded && m_bIsCurrentlyUpgrading )
{
// Update our attractor point
m_pAttractor->SetAttractorOrigin( coreOrigin );
Vector offset;
for ( int i = 0; i < 4; i++ )
{
offset = coreOrigin + RandomVector( -32.0f, 32.0f );
sParticle = (SimpleParticle *) m_pAttractor->AddParticle( sizeof(SimpleParticle), m_pAttractor->GetPMaterial( "effects/strider_muzzle" ), offset );
if ( sParticle == NULL )
return 1;
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 = 0.0f;
float alpha = 255;
sParticle->m_uchColor[0] = alpha;
sParticle->m_uchColor[1] = alpha;
sParticle->m_uchColor[2] = alpha;
sParticle->m_uchStartAlpha = alpha;
sParticle->m_uchEndAlpha = 0;
sParticle->m_uchStartSize = random->RandomFloat( 1, 2 );
sParticle->m_uchEndSize = 0;
}
}
return BaseClass::DrawModel( flags );
}
//---------------------------------------------------------
// On 360, raise up the player's view if the server has
// asked us to.
//---------------------------------------------------------
#define PHYSCANNON_RAISE_VIEW_GOAL 0.0f
void C_WeaponPhysCannon::ClientThink( void )
{
if( m_flTimeIgnoreForceView > gpGlobals->curtime )
return;
float flTime = (m_flTimeForceView - gpGlobals->curtime);
if( flTime < 0.0f )
return;
float flDT = 1.0f - flTime;
if( flDT > 0.0f )
{
QAngle viewangles;
engine->GetViewAngles( viewangles );
if( viewangles.x > PHYSCANNON_RAISE_VIEW_GOAL + 1.0f )
{
float flDelta = PHYSCANNON_RAISE_VIEW_GOAL - viewangles.x;
viewangles.x += (flDelta * flDT);
engine->SetViewAngles(viewangles);
}
else
{
// We've reached our goal. Ignore the forced view angles for now.
m_flTimeIgnoreForceView = m_flTimeForceView + 0.1f;
}
}
return BaseClass::ClientThink();
}

View File

@@ -0,0 +1,187 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
//=============================================================================//
#include "cbase.h"
#include "c_basehlcombatweapon.h"
#include "iviewrender_beams.h"
#include "beam_shared.h"
#include "c_weapon__stubs.h"
#include "materialsystem/imaterial.h"
#include "clienteffectprecachesystem.h"
#include "beamdraw.h"
// memdbgon must be the last include file in a .cpp file!!!
#include "tier0/memdbgon.h"
CLIENTEFFECT_REGISTER_BEGIN( PrecacheEffectStunstick )
CLIENTEFFECT_MATERIAL( "effects/stunstick" )
CLIENTEFFECT_REGISTER_END()
class C_WeaponStunStick : public C_BaseHLBludgeonWeapon
{
DECLARE_CLASS( C_WeaponStunStick, C_BaseHLBludgeonWeapon );
public:
DECLARE_CLIENTCLASS();
DECLARE_PREDICTABLE();
int DrawModel( int flags )
{
//FIXME: This sucks, but I can't easily create temp ents...
if ( m_bActive )
{
Vector vecOrigin;
QAngle vecAngles;
float color[3];
color[0] = color[1] = color[2] = random->RandomFloat( 0.1f, 0.2f );
GetAttachment( 1, vecOrigin, vecAngles );
Vector vForward;
AngleVectors( vecAngles, &vForward );
Vector vEnd = vecOrigin - vForward * 1.0f;
IMaterial *pMaterial = materials->FindMaterial( "effects/stunstick", NULL, false );
CMatRenderContextPtr pRenderContext( materials );
pRenderContext->Bind( pMaterial );
DrawHalo( pMaterial, vEnd, random->RandomFloat( 4.0f, 6.0f ), color );
color[0] = color[1] = color[2] = random->RandomFloat( 0.9f, 1.0f );
DrawHalo( pMaterial, vEnd, random->RandomFloat( 2.0f, 3.0f ), color );
}
return BaseClass::DrawModel( flags );
}
// Do part of our effect
void ClientThink( void )
{
// Update our effects
if ( m_bActive &&
gpGlobals->frametime != 0.0f &&
( random->RandomInt( 0, 5 ) == 0 ) )
{
Vector vecOrigin;
QAngle vecAngles;
GetAttachment( 1, vecOrigin, vecAngles );
Vector vForward;
AngleVectors( vecAngles, &vForward );
Vector vEnd = vecOrigin - vForward * 1.0f;
// Inner beams
BeamInfo_t beamInfo;
beamInfo.m_vecStart = vEnd;
Vector offset = RandomVector( -6, 2 );
offset += Vector(2,2,2);
beamInfo.m_vecEnd = vecOrigin + offset;
beamInfo.m_pStartEnt= cl_entitylist->GetEnt( BEAMENT_ENTITY( entindex() ) );
beamInfo.m_pEndEnt = cl_entitylist->GetEnt( BEAMENT_ENTITY( entindex() ) );
beamInfo.m_nStartAttachment = 1;
beamInfo.m_nEndAttachment = 2;
beamInfo.m_nType = TE_BEAMTESLA;
beamInfo.m_pszModelName = "sprites/physbeam.vmt";
beamInfo.m_flHaloScale = 0.0f;
beamInfo.m_flLife = 0.01f;
beamInfo.m_flWidth = random->RandomFloat( 0.5f, 2.0f );
beamInfo.m_flEndWidth = 0;
beamInfo.m_flFadeLength = 0.0f;
beamInfo.m_flAmplitude = random->RandomFloat( 1, 2 );
beamInfo.m_flBrightness = 255.0;
beamInfo.m_flSpeed = 0.0;
beamInfo.m_nStartFrame = 0.0;
beamInfo.m_flFrameRate = 1.0f;
beamInfo.m_flRed = 255.0f;;
beamInfo.m_flGreen = 255.0f;
beamInfo.m_flBlue = 255.0f;
beamInfo.m_nSegments = 8;
beamInfo.m_bRenderable = true;
beamInfo.m_nFlags = (FBEAM_ONLYNOISEONCE|FBEAM_SHADEOUT);
beams->CreateBeamPoints( beamInfo );
}
}
void OnDataChanged( DataUpdateType_t updateType )
{
BaseClass::OnDataChanged( updateType );
if ( updateType == DATA_UPDATE_CREATED )
{
SetNextClientThink( CLIENT_THINK_ALWAYS );
}
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void StartStunEffect( void )
{
//TODO: Play startup sound
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void StopStunEffect( void )
{
//TODO: Play shutdown sound
}
//-----------------------------------------------------------------------------
// Purpose:
// Output : RenderGroup_t
//-----------------------------------------------------------------------------
RenderGroup_t GetRenderGroup( void )
{
return RENDER_GROUP_TRANSLUCENT_ENTITY;
}
private:
CNetworkVar( bool, m_bActive );
};
//-----------------------------------------------------------------------------
// Purpose:
// Input : *pData -
// *pStruct -
// *pOut -
//-----------------------------------------------------------------------------
void RecvProxy_StunActive( const CRecvProxyData *pData, void *pStruct, void *pOut )
{
bool state = *((bool *)&pData->m_Value.m_Int);
C_WeaponStunStick *pWeapon = (C_WeaponStunStick *) pStruct;
if ( state )
{
// Turn on the effect
pWeapon->StartStunEffect();
}
else
{
// Turn off the effect
pWeapon->StopStunEffect();
}
*(bool *)pOut = state;
}
STUB_WEAPON_CLASS_IMPLEMENT( weapon_stunstick, C_WeaponStunStick );
IMPLEMENT_CLIENTCLASS_DT( C_WeaponStunStick, DT_WeaponStunStick, CWeaponStunStick )
RecvPropInt( RECVINFO(m_bActive), 0, RecvProxy_StunActive ),
END_RECV_TABLE()

View File

@@ -0,0 +1,99 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose: Draws the normal TF2 or HL2 HUD.
//
//=============================================================================
#include "cbase.h"
#include "clientmode_hlnormal.h"
#include "vgui_int.h"
#include "hud.h"
#include <vgui/IInput.h>
#include <vgui/IPanel.h>
#include <vgui/ISurface.h>
#include <vgui_controls/AnimationController.h>
#include "iinput.h"
#include "ienginevgui.h"
// memdbgon must be the last include file in a .cpp file!!!
#include "tier0/memdbgon.h"
extern bool g_bRollingCredits;
ConVar fov_desired( "fov_desired", "75", FCVAR_ARCHIVE | FCVAR_USERINFO, "Sets the base field-of-view.", true, 75.0, true, 90.0 );
//-----------------------------------------------------------------------------
// Globals
//-----------------------------------------------------------------------------
vgui::HScheme g_hVGuiCombineScheme = 0;
// Instance the singleton and expose the interface to it.
IClientMode *GetClientModeNormal()
{
static ClientModeHLNormal g_ClientModeNormal;
return &g_ClientModeNormal;
}
//-----------------------------------------------------------------------------
// Purpose: this is the viewport that contains all the hud elements
//-----------------------------------------------------------------------------
class CHudViewport : public CBaseViewport
{
private:
DECLARE_CLASS_SIMPLE( CHudViewport, CBaseViewport );
protected:
virtual void ApplySchemeSettings( vgui::IScheme *pScheme )
{
BaseClass::ApplySchemeSettings( pScheme );
gHUD.InitColors( pScheme );
SetPaintBackgroundEnabled( false );
}
virtual void CreateDefaultPanels( void ) { /* don't create any panels yet*/ };
};
//-----------------------------------------------------------------------------
// ClientModeHLNormal implementation
//-----------------------------------------------------------------------------
ClientModeHLNormal::ClientModeHLNormal()
{
m_pViewport = new CHudViewport();
m_pViewport->Start( gameuifuncs, gameeventmanager );
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
ClientModeHLNormal::~ClientModeHLNormal()
{
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void ClientModeHLNormal::Init()
{
BaseClass::Init();
// Load up the combine control panel scheme
g_hVGuiCombineScheme = vgui::scheme()->LoadSchemeFromFileEx( enginevgui->GetPanel( PANEL_CLIENTDLL ), IsXbox() ? "resource/ClientScheme.res" : "resource/CombinePanelScheme.res", "CombineScheme" );
if (!g_hVGuiCombineScheme)
{
Warning( "Couldn't load combine panel scheme!\n" );
}
}
bool ClientModeHLNormal::ShouldDrawCrosshair( void )
{
return ( g_bRollingCredits == false );
}

View File

@@ -0,0 +1,45 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
// $Workfile: $
// $Date: $
// $NoKeywords: $
//=============================================================================//
#if !defined( CLIENTMODE_HLNORMAL_H )
#define CLIENTMODE_HLNORMAL_H
#ifdef _WIN32
#pragma once
#endif
#include "clientmode_shared.h"
#include <vgui_controls/EditablePanel.h>
#include <vgui/Cursor.h>
class CHudViewport;
namespace vgui
{
typedef unsigned long HScheme;
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
class ClientModeHLNormal : public ClientModeShared
{
public:
DECLARE_CLASS( ClientModeHLNormal, ClientModeShared );
ClientModeHLNormal();
~ClientModeHLNormal();
virtual void Init();
virtual bool ShouldDrawCrosshair( void );
};
extern IClientMode *GetClientModeNormal();
extern vgui::HScheme g_hVGuiCombineScheme;
#endif // CLIENTMODE_HLNORMAL_H

View File

@@ -0,0 +1,334 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
//=============================================================================//
#include "cbase.h"
#include "fx.h"
#include "c_gib.h"
#include "c_te_effect_dispatch.h"
#include "iefx.h"
#include "decals.h"
// memdbgon must be the last include file in a .cpp file!!!
#include "tier0/memdbgon.h"
PMaterialHandle g_Material_Blood[2] = { NULL, NULL };
#ifdef _XBOX
// XBox only uses a few gibs
#define NUM_ANTLION_GIBS 3
const char *pszAntlionGibs[NUM_ANTLION_GIBS] = {
"models/gibs/antlion_gib_large_2.mdl", // Head
"models/gibs/antlion_gib_medium_1.mdl", // Pincher
"models/gibs/antlion_gib_medium_2.mdl", // Leg
};
#else
// Use all the gibs
#define NUM_ANTLION_GIBS_UNIQUE 3
const char *pszAntlionGibs_Unique[NUM_ANTLION_GIBS_UNIQUE] = {
"models/gibs/antlion_gib_large_1.mdl",
"models/gibs/antlion_gib_large_2.mdl",
"models/gibs/antlion_gib_large_3.mdl"
};
#define NUM_ANTLION_GIBS_MEDIUM 3
const char *pszAntlionGibs_Medium[NUM_ANTLION_GIBS_MEDIUM] = {
"models/gibs/antlion_gib_medium_1.mdl",
"models/gibs/antlion_gib_medium_2.mdl",
"models/gibs/antlion_gib_medium_3.mdl"
};
// XBox doesn't use the smaller gibs, so don't cache them
#define NUM_ANTLION_GIBS_SMALL 3
const char *pszAntlionGibs_Small[NUM_ANTLION_GIBS_SMALL] = {
"models/gibs/antlion_gib_small_1.mdl",
"models/gibs/antlion_gib_small_2.mdl",
"models/gibs/antlion_gib_small_3.mdl"
};
#endif
ConVar g_antlion_maxgibs( "g_antlion_maxgibs", "16", FCVAR_ARCHIVE );
void CAntlionGibManager::LevelInitPreEntity( void )
{
m_LRU.Purge();
}
CAntlionGibManager s_AntlionGibManager( "CAntlionGibManager" );
void CAntlionGibManager::AddGib( C_BaseEntity *pEntity )
{
m_LRU.AddToTail( pEntity );
}
void CAntlionGibManager::RemoveGib( C_BaseEntity *pEntity )
{
m_LRU.FindAndRemove( pEntity );
}
//-----------------------------------------------------------------------------
// Methods of IGameSystem
//-----------------------------------------------------------------------------
void CAntlionGibManager::Update( float frametime )
{
if ( m_LRU.Count() < g_antlion_maxgibs.GetInt() )
return;
int i = 0;
i = m_LRU.Head();
if ( m_LRU[ i ].Get() )
{
m_LRU[ i ].Get()->SetNextClientThink( gpGlobals->curtime );
}
m_LRU.Remove(i);
}
// Antlion gib - marks surfaces when it bounces
class C_AntlionGib : public C_Gib
{
typedef C_Gib BaseClass;
public:
static C_AntlionGib *CreateClientsideGib( const char *pszModelName, Vector vecOrigin, Vector vecForceDir, AngularImpulse vecAngularImp, float m_flLifetime = DEFAULT_GIB_LIFETIME )
{
C_AntlionGib *pGib = new C_AntlionGib;
if ( pGib == NULL )
return NULL;
if ( pGib->InitializeGib( pszModelName, vecOrigin, vecForceDir, vecAngularImp, m_flLifetime ) == false )
return NULL;
s_AntlionGibManager.AddGib( pGib );
return pGib;
}
// Decal the surface
virtual void HitSurface( C_BaseEntity *pOther )
{
//JDW: Removed for the time being
/*
int index = decalsystem->GetDecalIndexForName( "YellowBlood" );
if (index >= 0 )
{
effects->DecalShoot( index, pOther->entindex(), pOther->GetModel(), pOther->GetAbsOrigin(), pOther->GetAbsAngles(), GetAbsOrigin(), 0, 0 );
}
*/
}
};
//-----------------------------------------------------------------------------
// Purpose:
// Input : &origin -
//-----------------------------------------------------------------------------
void FX_AntlionGib( const Vector &origin, const Vector &direction, float scale )
{
Vector offset;
#ifdef _XBOX
// Throw less gibs for XBox
for ( int i = 0; i < NUM_ANTLION_GIBS; i++ )
{
offset = RandomVector( -32, 32 ) + origin;
C_AntlionGib::CreateClientsideGib( pszAntlionGibs[i], offset, ( direction + RandomVector( -0.8f, 0.8f ) ) * ( 250 * scale ), RandomAngularImpulse( -32, 32 ), 1.0f );
}
#else
int numGibs = random->RandomInt( 1, NUM_ANTLION_GIBS_UNIQUE );
// Spawn all the unique gibs
for ( int i = 0; i < numGibs; i++ )
{
offset = RandomVector( -16, 16 ) + origin;
C_AntlionGib::CreateClientsideGib( pszAntlionGibs_Unique[i], offset, ( direction + RandomVector( -0.8f, 0.8f ) ) * ( 150 * scale ), RandomAngularImpulse( -32, 32 ), 2.0f);
}
numGibs = random->RandomInt( 1, NUM_ANTLION_GIBS_MEDIUM );
// Spawn all the medium gibs
for ( int i = 0; i < numGibs; i++ )
{
offset = RandomVector( -16, 16 ) + origin;
C_AntlionGib::CreateClientsideGib( pszAntlionGibs_Medium[i], offset, ( direction + RandomVector( -0.8f, 0.8f ) ) * ( 250 * scale ), RandomAngularImpulse( -200, 200 ), 1.0f );
}
numGibs = random->RandomInt( 1, NUM_ANTLION_GIBS_SMALL );
// Spawn all the small gibs
for ( int i = 0; i < NUM_ANTLION_GIBS_SMALL; i++ )
{
offset = RandomVector( -16, 16 ) + origin;
C_AntlionGib::CreateClientsideGib( pszAntlionGibs_Small[i], offset, ( direction + RandomVector( -0.8f, 0.8f ) ) * ( 400 * scale ), RandomAngularImpulse( -300, 300 ), 0.5f );
}
#endif
#ifdef _XBOX
//
// Throw some blood
//
CSmartPtr<CSimpleEmitter> pSimple = CSimpleEmitter::Create( "FX_AntlionGib" );
pSimple->SetSortOrigin( origin );
pSimple->GetBinding().SetBBox( origin - Vector(64,64,64), origin + Vector(64,64,64) );
// Cache this if we're not already
if ( g_Material_Blood[0] == NULL )
{
g_Material_Blood[0] = g_Mat_BloodPuff[0];
}
if ( g_Material_Blood[1] == NULL )
{
g_Material_Blood[1] = g_Mat_BloodPuff[1];
}
Vector vDir;
vDir.Random( -1.0f, 1.0f );
// Gore bits
for ( int i = 0; i < 4; i++ )
{
SimpleParticle *sParticle = (SimpleParticle *) pSimple->AddParticle( sizeof( SimpleParticle ), g_Material_Blood[0], origin + RandomVector(-16,16));
if ( sParticle == NULL )
return;
sParticle->m_flLifetime = 0.0f;
sParticle->m_flDieTime = random->RandomFloat( 0.25f, 0.5f );
float speed = random->RandomFloat( 16.0f, 64.0f );
sParticle->m_vecVelocity.Init();
sParticle->m_uchColor[0] = 255;
sParticle->m_uchColor[1] = 200;
sParticle->m_uchColor[2] = 32;
sParticle->m_uchStartAlpha = 255;
sParticle->m_uchEndAlpha = 0;
sParticle->m_uchStartSize = random->RandomInt( 4, 16 );
sParticle->m_uchEndSize = sParticle->m_uchStartSize * 4;
sParticle->m_flRoll = random->RandomInt( 0, 360 );
sParticle->m_flRollDelta = 0.0f;
}
// Middle core
SimpleParticle *sParticle = (SimpleParticle *) pSimple->AddParticle( sizeof( SimpleParticle ), g_Material_Blood[1], origin );
if ( sParticle == NULL )
return;
sParticle->m_flLifetime = 0.0f;
sParticle->m_flDieTime = random->RandomFloat( 0.5f, 0.75f );
float speed = random->RandomFloat( 16.0f, 64.0f );
sParticle->m_vecVelocity = vDir * -speed;
sParticle->m_vecVelocity[2] += 16.0f;
sParticle->m_uchColor[0] = 255;
sParticle->m_uchColor[1] = 200;
sParticle->m_uchColor[2] = 32;
sParticle->m_uchStartAlpha = random->RandomInt( 64, 128 );
sParticle->m_uchEndAlpha = 0;
sParticle->m_uchStartSize = random->RandomInt( 16, 32 );
sParticle->m_uchEndSize = sParticle->m_uchStartSize * 3;
sParticle->m_flRoll = random->RandomInt( 0, 360 );
sParticle->m_flRollDelta = random->RandomFloat( -0.2f, 0.2f );
#else
//
// Non-XBox blood
//
CSmartPtr<CSimpleEmitter> pSimple = CSimpleEmitter::Create( "FX_AntlionGib" );
pSimple->SetSortOrigin( origin );
Vector vDir;
vDir.Random( -1.0f, 1.0f );
for ( int i = 0; i < 4; i++ )
{
SimpleParticle *sParticle = (SimpleParticle *) pSimple->AddParticle( sizeof( SimpleParticle ), g_Mat_BloodPuff[0], origin );
if ( sParticle == NULL )
return;
sParticle->m_flLifetime = 0.0f;
sParticle->m_flDieTime = random->RandomFloat( 0.5f, 0.75f );
float speed = random->RandomFloat( 16.0f, 64.0f );
sParticle->m_vecVelocity = vDir * -speed;
sParticle->m_vecVelocity[2] += 16.0f;
sParticle->m_uchColor[0] = 255;
sParticle->m_uchColor[1] = 200;
sParticle->m_uchColor[2] = 32;
sParticle->m_uchStartAlpha = 255;
sParticle->m_uchEndAlpha = 0;
sParticle->m_uchStartSize = random->RandomInt( 16, 32 );
sParticle->m_uchEndSize = sParticle->m_uchStartSize * 2;
sParticle->m_flRoll = random->RandomInt( 0, 360 );
sParticle->m_flRollDelta = random->RandomFloat( -1.0f, 1.0f );
}
for ( int i = 0; i < 4; i++ )
{
SimpleParticle *sParticle = (SimpleParticle *) pSimple->AddParticle( sizeof( SimpleParticle ), g_Mat_BloodPuff[1], origin );
if ( sParticle == NULL )
{
return;
}
sParticle->m_flLifetime = 0.0f;
sParticle->m_flDieTime = random->RandomFloat( 0.5f, 0.75f );
float speed = random->RandomFloat( 16.0f, 64.0f );
sParticle->m_vecVelocity = vDir * -speed;
sParticle->m_vecVelocity[2] += 16.0f;
sParticle->m_uchColor[0] = 255;
sParticle->m_uchColor[1] = 200;
sParticle->m_uchColor[2] = 32;
sParticle->m_uchStartAlpha = random->RandomInt( 64, 128 );
sParticle->m_uchEndAlpha = 0;
sParticle->m_uchStartSize = random->RandomInt( 16, 32 );
sParticle->m_uchEndSize = sParticle->m_uchStartSize * 2;
sParticle->m_flRoll = random->RandomInt( 0, 360 );
sParticle->m_flRollDelta = random->RandomFloat( -1.0f, 1.0f );
}
#endif
}
//-----------------------------------------------------------------------------
// Purpose:
// Input : &data -
//-----------------------------------------------------------------------------
void AntlionGibCallback( const CEffectData &data )
{
FX_AntlionGib( data.m_vOrigin, data.m_vNormal, data.m_flScale );
}
DECLARE_CLIENT_EFFECT( "AntlionGib", AntlionGibCallback );

Some files were not shown because too many files have changed in this diff Show More