mirror of
https://github.com/nillerusr/source-engine.git
synced 2026-08-07 17:29:36 +00:00
1
This commit is contained in:
@@ -0,0 +1,53 @@
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose: Acts exactly like "AnimatedTexture", but ONLY if the texture
|
||||
// it's working on matches the desired texture to work on.
|
||||
//
|
||||
// This assumes that some other proxy will be switching out the textures.
|
||||
//
|
||||
// $NoKeywords: $
|
||||
//=============================================================================//
|
||||
#include "cbase.h"
|
||||
#include "materialsystem/imaterialproxy.h"
|
||||
#include "materialsystem/imaterialvar.h"
|
||||
#include "materialsystem/imaterial.h"
|
||||
#include "materialsystem/itexture.h"
|
||||
#include "baseanimatedtextureproxy.h"
|
||||
#include "utlstring.h"
|
||||
#include <KeyValues.h>
|
||||
|
||||
// memdbgon must be the last include file in a .cpp file!!!
|
||||
#include "tier0/memdbgon.h"
|
||||
|
||||
class CAnimateSpecificTexture : public CBaseAnimatedTextureProxy
|
||||
{
|
||||
private:
|
||||
CUtlString m_OnlyAnimateOnTexture;
|
||||
public:
|
||||
virtual float GetAnimationStartTime( void* pBaseEntity ) { return 0; }
|
||||
virtual bool Init( IMaterial *pMaterial, KeyValues *pKeyValues );
|
||||
virtual void OnBind( void *pC_BaseEntity );
|
||||
virtual void Release( void ) { delete this; }
|
||||
};
|
||||
|
||||
bool CAnimateSpecificTexture::Init( IMaterial *pMaterial, KeyValues *pKeyValues )
|
||||
{
|
||||
char const* pszAnimateOnTexture = pKeyValues->GetString( "onlyAnimateOnTexture" );
|
||||
if( !pszAnimateOnTexture )
|
||||
return false;
|
||||
|
||||
m_OnlyAnimateOnTexture.Set( pszAnimateOnTexture );
|
||||
|
||||
return CBaseAnimatedTextureProxy::Init( pMaterial, pKeyValues );
|
||||
}
|
||||
|
||||
void CAnimateSpecificTexture::OnBind( void *pC_BaseEntity )
|
||||
{
|
||||
if( FStrEq( m_AnimatedTextureVar->GetTextureValue()->GetName(), m_OnlyAnimateOnTexture ) )
|
||||
{
|
||||
CBaseAnimatedTextureProxy::OnBind( pC_BaseEntity );
|
||||
}
|
||||
//else do nothing
|
||||
}
|
||||
|
||||
EXPOSE_INTERFACE( CAnimateSpecificTexture, IMaterialProxy, "AnimateSpecificTexture" IMATERIAL_PROXY_INTERFACE_VERSION );
|
||||
@@ -0,0 +1,65 @@
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
// $NoKeywords: $
|
||||
//=============================================================================//
|
||||
|
||||
#ifndef C_ENVPROJECTEDTEXTURE_H
|
||||
#define C_ENVPROJECTEDTEXTURE_H
|
||||
#ifdef _WIN32
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
#include "c_baseentity.h"
|
||||
#include "basetypes.h"
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
class C_EnvProjectedTexture : public C_BaseEntity
|
||||
{
|
||||
DECLARE_CLASS( C_EnvProjectedTexture, C_BaseEntity );
|
||||
public:
|
||||
DECLARE_CLIENTCLASS();
|
||||
|
||||
C_EnvProjectedTexture();
|
||||
~C_EnvProjectedTexture();
|
||||
|
||||
virtual void OnDataChanged( DataUpdateType_t updateType );
|
||||
void ShutDownLightHandle( void );
|
||||
|
||||
virtual void Simulate();
|
||||
|
||||
void UpdateLight( bool bForceUpdate );
|
||||
|
||||
bool ShadowsEnabled();
|
||||
|
||||
float GetFOV();
|
||||
|
||||
private:
|
||||
|
||||
ClientShadowHandle_t m_LightHandle;
|
||||
|
||||
EHANDLE m_hTargetEntity;
|
||||
|
||||
bool m_bState;
|
||||
float m_flLightFOV;
|
||||
bool m_bEnableShadows;
|
||||
bool m_bLightOnlyTarget;
|
||||
bool m_bLightWorld;
|
||||
bool m_bCameraSpace;
|
||||
color32 m_cLightColor;
|
||||
float m_flAmbient;
|
||||
char m_SpotlightTextureName[ MAX_PATH ];
|
||||
int m_nSpotlightTextureFrame;
|
||||
int m_nShadowQuality;
|
||||
bool m_bCurrentShadow;
|
||||
|
||||
public:
|
||||
C_EnvProjectedTexture *m_pNext;
|
||||
};
|
||||
|
||||
C_EnvProjectedTexture* GetEnvProjectedTextureList();
|
||||
|
||||
#endif // C_ENVPROJECTEDTEXTURE_H
|
||||
@@ -0,0 +1,798 @@
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose: Material Modify control entity.
|
||||
//
|
||||
//=============================================================================//
|
||||
|
||||
#include "cbase.h"
|
||||
#include "proxyentity.h"
|
||||
#include "materialsystem/imaterial.h"
|
||||
#include "materialsystem/imaterialvar.h"
|
||||
#include "materialsystem/itexture.h"
|
||||
#include "iviewrender.h"
|
||||
#include "texture_group_names.h"
|
||||
#include "baseanimatedtextureproxy.h"
|
||||
#include "toolframework_client.h"
|
||||
|
||||
// memdbgon must be the last include file in a .cpp file!!!
|
||||
#include "tier0/memdbgon.h"
|
||||
|
||||
#define MATERIAL_MODIFY_STRING_SIZE 255
|
||||
#define MATERIAL_MODIFY_ANIMATION_UNSET -1
|
||||
|
||||
// Must match MaterialModifyControl.cpp
|
||||
enum MaterialModifyMode_t
|
||||
{
|
||||
MATERIAL_MODIFY_MODE_NONE = 0,
|
||||
MATERIAL_MODIFY_MODE_SETVAR = 1,
|
||||
MATERIAL_MODIFY_MODE_ANIM_SEQUENCE = 2,
|
||||
MATERIAL_MODIFY_MODE_FLOAT_LERP = 3,
|
||||
};
|
||||
|
||||
// forward declarations
|
||||
void ToolFramework_RecordMaterialParams( IMaterial *pMaterial );
|
||||
|
||||
ConVar debug_materialmodifycontrol_client( "debug_materialmodifycontrol_client", "0" );
|
||||
|
||||
struct materialanimcommands_t
|
||||
{
|
||||
int iFrameStart;
|
||||
int iFrameEnd;
|
||||
bool bWrap;
|
||||
float flFrameRate;
|
||||
};
|
||||
|
||||
struct materialfloatlerpcommands_t
|
||||
{
|
||||
int flStartValue;
|
||||
int flEndValue;
|
||||
float flTransitionTime;
|
||||
};
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// FIXME: This really should inherit from something more lightweight
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
class C_MaterialModifyControl : public C_BaseEntity
|
||||
{
|
||||
public:
|
||||
|
||||
DECLARE_CLASS( C_MaterialModifyControl, C_BaseEntity );
|
||||
|
||||
C_MaterialModifyControl();
|
||||
|
||||
void OnPreDataChanged( DataUpdateType_t updateType );
|
||||
void OnDataChanged( DataUpdateType_t updateType );
|
||||
bool ShouldDraw();
|
||||
|
||||
IMaterial *GetMaterial( void ) { return m_pMaterial; }
|
||||
const char *GetMaterialVariableName( void ) { return m_szMaterialVar; }
|
||||
const char *GetMaterialVariableValue( void ) { return m_szMaterialVarValue; }
|
||||
|
||||
DECLARE_CLIENTCLASS();
|
||||
|
||||
// Animated texture and Float Lerp usage
|
||||
bool HasNewAnimationCommands( void ) { return m_bHasNewAnimationCommands; }
|
||||
void ClearAnimationCommands( void ) { m_bHasNewAnimationCommands = false; }
|
||||
|
||||
// Animated texture usage
|
||||
void GetAnimationCommands( materialanimcommands_t *pCommands );
|
||||
|
||||
// FloatLerp usage
|
||||
void GetFloatLerpCommands( materialfloatlerpcommands_t *pCommands );
|
||||
|
||||
void SetAnimationStartTime( float flTime )
|
||||
{
|
||||
m_flAnimationStartTime = flTime;
|
||||
}
|
||||
float GetAnimationStartTime( void ) const
|
||||
{
|
||||
return m_flAnimationStartTime;
|
||||
}
|
||||
|
||||
MaterialModifyMode_t GetModifyMode( void ) const
|
||||
{
|
||||
return ( MaterialModifyMode_t)m_nModifyMode;
|
||||
}
|
||||
private:
|
||||
|
||||
char m_szMaterialName[MATERIAL_MODIFY_STRING_SIZE];
|
||||
char m_szMaterialVar[MATERIAL_MODIFY_STRING_SIZE];
|
||||
char m_szMaterialVarValue[MATERIAL_MODIFY_STRING_SIZE];
|
||||
IMaterial *m_pMaterial;
|
||||
|
||||
bool m_bHasNewAnimationCommands;
|
||||
|
||||
// Animation commands from the server
|
||||
int m_iFrameStart;
|
||||
int m_iFrameEnd;
|
||||
bool m_bWrap;
|
||||
float m_flFramerate;
|
||||
bool m_bNewAnimCommandsSemaphore;
|
||||
bool m_bOldAnimCommandsSemaphore;
|
||||
|
||||
// Float lerp commands from the server
|
||||
float m_flFloatLerpStartValue;
|
||||
float m_flFloatLerpEndValue;
|
||||
float m_flFloatLerpTransitionTime;
|
||||
bool m_bFloatLerpWrap;
|
||||
float m_flAnimationStartTime;
|
||||
|
||||
int m_nModifyMode;
|
||||
};
|
||||
|
||||
IMPLEMENT_CLIENTCLASS_DT(C_MaterialModifyControl, DT_MaterialModifyControl, CMaterialModifyControl)
|
||||
RecvPropString( RECVINFO( m_szMaterialName ) ),
|
||||
RecvPropString( RECVINFO( m_szMaterialVar ) ),
|
||||
RecvPropString( RECVINFO( m_szMaterialVarValue ) ),
|
||||
RecvPropInt( RECVINFO(m_iFrameStart) ),
|
||||
RecvPropInt( RECVINFO(m_iFrameEnd) ),
|
||||
RecvPropInt( RECVINFO(m_bWrap) ),
|
||||
RecvPropFloat( RECVINFO(m_flFramerate) ),
|
||||
RecvPropInt( RECVINFO(m_bNewAnimCommandsSemaphore) ),
|
||||
RecvPropFloat( RECVINFO(m_flFloatLerpStartValue) ),
|
||||
RecvPropFloat( RECVINFO(m_flFloatLerpEndValue) ),
|
||||
RecvPropFloat( RECVINFO(m_flFloatLerpTransitionTime) ),
|
||||
RecvPropInt( RECVINFO(m_bFloatLerpWrap) ),
|
||||
RecvPropInt( RECVINFO(m_nModifyMode) ),
|
||||
END_RECV_TABLE()
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//------------------------------------------------------------------------------
|
||||
C_MaterialModifyControl::C_MaterialModifyControl()
|
||||
{
|
||||
m_pMaterial = NULL;
|
||||
m_bOldAnimCommandsSemaphore = false;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
void C_MaterialModifyControl::OnPreDataChanged( DataUpdateType_t updateType )
|
||||
{
|
||||
BaseClass::OnPreDataChanged( updateType );
|
||||
|
||||
m_bOldAnimCommandsSemaphore = m_bNewAnimCommandsSemaphore;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//------------------------------------------------------------------------------
|
||||
void C_MaterialModifyControl::OnDataChanged( DataUpdateType_t updateType )
|
||||
{
|
||||
if( updateType == DATA_UPDATE_CREATED )
|
||||
{
|
||||
m_pMaterial = materials->FindMaterial( m_szMaterialName, TEXTURE_GROUP_OTHER );
|
||||
|
||||
// Clear out our variables
|
||||
m_bHasNewAnimationCommands = true;
|
||||
}
|
||||
|
||||
// Detect changes in the anim commands
|
||||
if ( m_bNewAnimCommandsSemaphore != m_bOldAnimCommandsSemaphore )
|
||||
{
|
||||
m_bHasNewAnimationCommands = true;
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
void C_MaterialModifyControl::GetAnimationCommands( materialanimcommands_t *pCommands )
|
||||
{
|
||||
pCommands->iFrameStart = m_iFrameStart;
|
||||
pCommands->iFrameEnd = m_iFrameEnd;
|
||||
pCommands->bWrap = m_bWrap;
|
||||
pCommands->flFrameRate = m_flFramerate;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
void C_MaterialModifyControl::GetFloatLerpCommands( materialfloatlerpcommands_t *pCommands )
|
||||
{
|
||||
pCommands->flStartValue = m_flFloatLerpStartValue;
|
||||
pCommands->flEndValue = m_flFloatLerpEndValue;
|
||||
pCommands->flTransitionTime = m_flFloatLerpTransitionTime;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Purpose: We don't draw.
|
||||
//------------------------------------------------------------------------------
|
||||
bool C_MaterialModifyControl::ShouldDraw()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
//
|
||||
// THE MATERIALMODIFYPROXY ITSELF
|
||||
//
|
||||
class CMaterialModifyProxy : public CBaseAnimatedTextureProxy
|
||||
{
|
||||
public:
|
||||
CMaterialModifyProxy();
|
||||
virtual ~CMaterialModifyProxy();
|
||||
virtual bool Init( IMaterial *pMaterial, KeyValues *pKeyValues );
|
||||
virtual void OnBind( void *pEntity );
|
||||
virtual IMaterial *GetMaterial();
|
||||
|
||||
private:
|
||||
void OnBindSetVar( C_MaterialModifyControl *pControl );
|
||||
void OnBindAnimatedTexture( C_MaterialModifyControl *pControl );
|
||||
void OnBindFloatLerp( C_MaterialModifyControl *pControl );
|
||||
float GetAnimationStartTime( void* pArg );
|
||||
void AnimationWrapped( void* pArg );
|
||||
|
||||
IMaterial *m_pMaterial;
|
||||
|
||||
// texture animation stuff
|
||||
int m_iFrameStart;
|
||||
int m_iFrameEnd;
|
||||
bool m_bReachedEnd;
|
||||
bool m_bCustomWrap;
|
||||
float m_flCustomFramerate;
|
||||
|
||||
// float lerp stuff
|
||||
IMaterialVar *m_pMaterialVar;
|
||||
int m_flStartValue;
|
||||
int m_flEndValue;
|
||||
float m_flStartTime;
|
||||
float m_flTransitionTime;
|
||||
};
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
CMaterialModifyProxy::CMaterialModifyProxy()
|
||||
{
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
CMaterialModifyProxy::~CMaterialModifyProxy()
|
||||
{
|
||||
}
|
||||
|
||||
bool CMaterialModifyProxy::Init( IMaterial *pMaterial, KeyValues *pKeyValues )
|
||||
{
|
||||
// set var stuff
|
||||
m_pMaterial = pMaterial;
|
||||
|
||||
// float lerp stuff
|
||||
m_flStartValue = MATERIAL_MODIFY_ANIMATION_UNSET;
|
||||
m_flEndValue = MATERIAL_MODIFY_ANIMATION_UNSET;
|
||||
|
||||
// animated stuff
|
||||
// m_pMaterial = pMaterial;
|
||||
// m_iFrameStart = MATERIAL_MODIFY_ANIMATION_UNSET;
|
||||
// m_iFrameEnd = MATERIAL_MODIFY_ANIMATION_UNSET;
|
||||
// m_bReachedEnd = false;
|
||||
// return CBaseAnimatedTextureProxy::Init( pMaterial, pKeyValues );
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void CMaterialModifyProxy::OnBind( void *pEntity )
|
||||
{
|
||||
// Get the modified material vars from the entity input
|
||||
IClientRenderable *pRend = (IClientRenderable *)pEntity;
|
||||
if ( pRend )
|
||||
{
|
||||
C_BaseEntity *pBaseEntity = pRend->GetIClientUnknown()->GetBaseEntity();
|
||||
|
||||
if ( pBaseEntity )
|
||||
{
|
||||
if( debug_materialmodifycontrol_client.GetBool() )
|
||||
{
|
||||
// DevMsg( 1, "%s\n", pBaseEntity->GetDebugName() );
|
||||
}
|
||||
int numChildren = 0;
|
||||
bool gotOne = false;
|
||||
for ( C_BaseEntity *pChild = pBaseEntity->FirstMoveChild(); pChild; pChild = pChild->NextMovePeer() )
|
||||
{
|
||||
numChildren++;
|
||||
C_MaterialModifyControl *pControl = dynamic_cast<C_MaterialModifyControl*>( pChild );
|
||||
if ( !pControl )
|
||||
continue;
|
||||
|
||||
if( debug_materialmodifycontrol_client.GetBool() )
|
||||
{
|
||||
// DevMsg( 1, "pControl: 0x%p\n", pControl );
|
||||
}
|
||||
|
||||
switch( pControl->GetModifyMode() )
|
||||
{
|
||||
case MATERIAL_MODIFY_MODE_NONE:
|
||||
break;
|
||||
case MATERIAL_MODIFY_MODE_SETVAR:
|
||||
gotOne = true;
|
||||
OnBindSetVar( pControl );
|
||||
break;
|
||||
case MATERIAL_MODIFY_MODE_ANIM_SEQUENCE:
|
||||
OnBindAnimatedTexture( pControl );
|
||||
break;
|
||||
case MATERIAL_MODIFY_MODE_FLOAT_LERP:
|
||||
OnBindFloatLerp( pControl );
|
||||
break;
|
||||
default:
|
||||
Assert( 0 );
|
||||
break;
|
||||
}
|
||||
}
|
||||
if( gotOne )
|
||||
{
|
||||
// DevMsg( 1, "numChildren: %d\n", numChildren );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ( ToolsEnabled() )
|
||||
{
|
||||
ToolFramework_RecordMaterialParams( GetMaterial() );
|
||||
}
|
||||
}
|
||||
|
||||
IMaterial *CMaterialModifyProxy::GetMaterial()
|
||||
{
|
||||
return m_pMaterial;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
void CMaterialModifyProxy::OnBindSetVar( C_MaterialModifyControl *pControl )
|
||||
{
|
||||
IMaterial *pMaterial = pControl->GetMaterial();
|
||||
if( !pMaterial )
|
||||
{
|
||||
Assert( 0 );
|
||||
return;
|
||||
}
|
||||
|
||||
if ( pMaterial != m_pMaterial )
|
||||
{
|
||||
// Warning( "\t%s!=%s\n", pMaterial->GetName(), m_pMaterial->GetName() );
|
||||
return;
|
||||
}
|
||||
|
||||
bool bFound;
|
||||
IMaterialVar *pMaterialVar = pMaterial->FindVar( pControl->GetMaterialVariableName(), &bFound, false );
|
||||
if ( !bFound )
|
||||
return;
|
||||
|
||||
if( Q_strcmp( pControl->GetMaterialVariableValue(), "" ) )
|
||||
{
|
||||
// const char *pMaterialName = m_pMaterial->GetName();
|
||||
// const char *pMaterialVarName = pMaterialVar->GetName();
|
||||
// const char *pMaterialVarValue = pControl->GetMaterialVariableValue();
|
||||
// if( debug_materialmodifycontrol_client.GetBool()
|
||||
// && Q_stristr( m_pMaterial->GetName(), "faceandhair" )
|
||||
// && Q_stristr( pMaterialVar->GetName(), "self" )
|
||||
// )
|
||||
// {
|
||||
// static int count = 0;
|
||||
// DevMsg( 1, "CMaterialModifyProxy::OnBindSetVar \"%s\" %s=%s %d pControl=0x%p\n",
|
||||
// m_pMaterial->GetName(), pMaterialVar->GetName(), pControl->GetMaterialVariableValue(), count++, pControl );
|
||||
// }
|
||||
pMaterialVar->SetValueAutodetectType( pControl->GetMaterialVariableValue() );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Does the dirty deed
|
||||
//-----------------------------------------------------------------------------
|
||||
void CMaterialModifyProxy::OnBindAnimatedTexture( C_MaterialModifyControl *pControl )
|
||||
{
|
||||
assert ( m_AnimatedTextureVar );
|
||||
if( m_AnimatedTextureVar->GetType() != MATERIAL_VAR_TYPE_TEXTURE )
|
||||
return;
|
||||
|
||||
ITexture *pTexture;
|
||||
pTexture = m_AnimatedTextureVar->GetTextureValue();
|
||||
|
||||
if ( !pControl )
|
||||
return;
|
||||
|
||||
if ( pControl->HasNewAnimationCommands() )
|
||||
{
|
||||
// Read the data from the modify entity
|
||||
materialanimcommands_t sCommands;
|
||||
pControl->GetAnimationCommands( &sCommands );
|
||||
|
||||
m_iFrameStart = sCommands.iFrameStart;
|
||||
m_iFrameEnd = sCommands.iFrameEnd;
|
||||
m_bCustomWrap = sCommands.bWrap;
|
||||
m_flCustomFramerate = sCommands.flFrameRate;
|
||||
m_bReachedEnd = false;
|
||||
|
||||
m_flStartTime = gpGlobals->curtime;
|
||||
|
||||
pControl->ClearAnimationCommands();
|
||||
}
|
||||
|
||||
// Init all the vars based on whether we're using the base material settings,
|
||||
// or the custom ones from the entity input.
|
||||
int numFrames;
|
||||
bool bWrapAnimation;
|
||||
float flFrameRate;
|
||||
int iLastFrame;
|
||||
|
||||
// Do we have a custom frame section from the server?
|
||||
if ( m_iFrameStart != MATERIAL_MODIFY_ANIMATION_UNSET )
|
||||
{
|
||||
if ( m_iFrameEnd == MATERIAL_MODIFY_ANIMATION_UNSET )
|
||||
{
|
||||
m_iFrameEnd = pTexture->GetNumAnimationFrames();
|
||||
}
|
||||
|
||||
numFrames = (m_iFrameEnd - m_iFrameStart) + 1;
|
||||
bWrapAnimation = m_bCustomWrap;
|
||||
flFrameRate = m_flCustomFramerate;
|
||||
iLastFrame = (m_iFrameEnd - 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
numFrames = pTexture->GetNumAnimationFrames();
|
||||
bWrapAnimation = m_WrapAnimation;
|
||||
flFrameRate = m_FrameRate;
|
||||
iLastFrame = (numFrames - 1);
|
||||
}
|
||||
|
||||
// Have we already reached the end? If so, stay there.
|
||||
if ( m_bReachedEnd && !bWrapAnimation )
|
||||
{
|
||||
m_AnimatedTextureFrameNumVar->SetIntValue( iLastFrame );
|
||||
return;
|
||||
}
|
||||
|
||||
// NOTE: Must not use relative time based methods here
|
||||
// because the bind proxy can be called many times per frame.
|
||||
// Prevent multiple Wrap callbacks to be sent for no wrap mode
|
||||
float startTime;
|
||||
if ( m_iFrameStart != MATERIAL_MODIFY_ANIMATION_UNSET )
|
||||
{
|
||||
startTime = m_flStartTime;
|
||||
}
|
||||
else
|
||||
{
|
||||
startTime = GetAnimationStartTime(pControl);
|
||||
}
|
||||
float deltaTime = gpGlobals->curtime - startTime;
|
||||
float prevTime = deltaTime - gpGlobals->frametime;
|
||||
|
||||
// Clamp..
|
||||
if (deltaTime < 0.0f)
|
||||
deltaTime = 0.0f;
|
||||
if (prevTime < 0.0f)
|
||||
prevTime = 0.0f;
|
||||
|
||||
float frame = flFrameRate * deltaTime;
|
||||
float prevFrame = flFrameRate * prevTime;
|
||||
|
||||
int intFrame = ((int)frame) % numFrames;
|
||||
int intPrevFrame = ((int)prevFrame) % numFrames;
|
||||
|
||||
if ( m_iFrameStart != MATERIAL_MODIFY_ANIMATION_UNSET )
|
||||
{
|
||||
intFrame += m_iFrameStart;
|
||||
intPrevFrame += m_iFrameStart;
|
||||
}
|
||||
|
||||
// Report wrap situation...
|
||||
if (intPrevFrame > intFrame)
|
||||
{
|
||||
m_bReachedEnd = true;
|
||||
|
||||
if (bWrapAnimation)
|
||||
{
|
||||
AnimationWrapped( pControl );
|
||||
}
|
||||
else
|
||||
{
|
||||
// Only sent the wrapped message once.
|
||||
// when we're in non-wrapping mode
|
||||
if (prevFrame < numFrames)
|
||||
AnimationWrapped( pControl );
|
||||
intFrame = numFrames - 1;
|
||||
}
|
||||
}
|
||||
|
||||
m_AnimatedTextureFrameNumVar->SetIntValue( intFrame );
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
float CMaterialModifyProxy::GetAnimationStartTime( void* pArg )
|
||||
{
|
||||
IClientRenderable *pRend = (IClientRenderable *)pArg;
|
||||
if (!pRend)
|
||||
return 0.0f;
|
||||
|
||||
C_BaseEntity* pEntity = pRend->GetIClientUnknown()->GetBaseEntity();
|
||||
if (pEntity)
|
||||
{
|
||||
return pEntity->GetTextureAnimationStartTime();
|
||||
}
|
||||
return 0.0f;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
void CMaterialModifyProxy::AnimationWrapped( void* pArg )
|
||||
{
|
||||
IClientRenderable *pRend = (IClientRenderable *)pArg;
|
||||
if (!pRend)
|
||||
return;
|
||||
|
||||
C_BaseEntity* pEntity = pRend->GetIClientUnknown()->GetBaseEntity();
|
||||
if (pEntity)
|
||||
{
|
||||
pEntity->TextureAnimationWrapped();
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Does the dirty deed
|
||||
//-----------------------------------------------------------------------------
|
||||
void CMaterialModifyProxy::OnBindFloatLerp( C_MaterialModifyControl *pControl )
|
||||
{
|
||||
if ( !pControl )
|
||||
return;
|
||||
|
||||
if ( pControl->HasNewAnimationCommands() )
|
||||
{
|
||||
pControl->SetAnimationStartTime( gpGlobals->curtime );
|
||||
pControl->ClearAnimationCommands();
|
||||
}
|
||||
|
||||
// Read the data from the modify entity
|
||||
materialfloatlerpcommands_t sCommands;
|
||||
pControl->GetFloatLerpCommands( &sCommands );
|
||||
|
||||
m_flStartValue = sCommands.flStartValue;
|
||||
m_flEndValue = sCommands.flEndValue;
|
||||
m_flTransitionTime = sCommands.flTransitionTime;
|
||||
m_flStartTime = pControl->GetAnimationStartTime();
|
||||
bool bFound;
|
||||
m_pMaterialVar = m_pMaterial->FindVar( pControl->GetMaterialVariableName(), &bFound, false );
|
||||
|
||||
if( bFound )
|
||||
{
|
||||
float currentValue;
|
||||
if( m_flTransitionTime > 0.0f )
|
||||
{
|
||||
currentValue = m_flStartValue + ( m_flEndValue - m_flStartValue ) * clamp( ( ( gpGlobals->curtime - m_flStartTime ) / m_flTransitionTime ), 0.0f, 1.0f );
|
||||
}
|
||||
else
|
||||
{
|
||||
currentValue = m_flEndValue;
|
||||
}
|
||||
|
||||
if( debug_materialmodifycontrol_client.GetBool() && Q_stristr( m_pMaterial->GetName(), "faceandhair" ) && Q_stristr( m_pMaterialVar->GetName(), "warp" ) )
|
||||
{
|
||||
static int count = 0;
|
||||
DevMsg( 1, "CMaterialFloatLerpProxy::OnBind \"%s\" %s=%f %d\n", m_pMaterial->GetName(), m_pMaterialVar->GetName(), currentValue, count++ );
|
||||
}
|
||||
m_pMaterialVar->SetFloatValue( currentValue );
|
||||
}
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
//
|
||||
// MATERIALMODIFYANIMATED PROXY
|
||||
//
|
||||
class CMaterialModifyAnimatedProxy : public CBaseAnimatedTextureProxy
|
||||
{
|
||||
public:
|
||||
CMaterialModifyAnimatedProxy() {};
|
||||
virtual ~CMaterialModifyAnimatedProxy() {};
|
||||
virtual bool Init( IMaterial *pMaterial, KeyValues *pKeyValues );
|
||||
virtual void OnBind( void *pEntity );
|
||||
|
||||
virtual float GetAnimationStartTime( void* pBaseEntity );
|
||||
virtual void AnimationWrapped( void* pC_BaseEntity );
|
||||
|
||||
private:
|
||||
IMaterial *m_pMaterial;
|
||||
int m_iFrameStart;
|
||||
int m_iFrameEnd;
|
||||
bool m_bReachedEnd;
|
||||
float m_flStartTime;
|
||||
bool m_bCustomWrap;
|
||||
float m_flCustomFramerate;
|
||||
};
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
bool CMaterialModifyAnimatedProxy::Init( IMaterial *pMaterial, KeyValues *pKeyValues )
|
||||
{
|
||||
m_pMaterial = pMaterial;
|
||||
m_iFrameStart = MATERIAL_MODIFY_ANIMATION_UNSET;
|
||||
m_iFrameEnd = MATERIAL_MODIFY_ANIMATION_UNSET;
|
||||
m_bReachedEnd = false;
|
||||
return CBaseAnimatedTextureProxy::Init( pMaterial, pKeyValues );
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Does the dirty deed
|
||||
//-----------------------------------------------------------------------------
|
||||
void CMaterialModifyAnimatedProxy::OnBind( void *pEntity )
|
||||
{
|
||||
assert ( m_AnimatedTextureVar );
|
||||
if( m_AnimatedTextureVar->GetType() != MATERIAL_VAR_TYPE_TEXTURE )
|
||||
return;
|
||||
|
||||
ITexture *pTexture;
|
||||
pTexture = m_AnimatedTextureVar->GetTextureValue();
|
||||
|
||||
// Get the modified material vars from the entity input
|
||||
IClientRenderable *pRend = (IClientRenderable *)pEntity;
|
||||
if ( pRend )
|
||||
{
|
||||
C_BaseEntity *pBaseEntity = pRend->GetIClientUnknown()->GetBaseEntity();
|
||||
if ( pBaseEntity )
|
||||
{
|
||||
for ( C_BaseEntity *pChild = pBaseEntity->FirstMoveChild(); pChild; pChild = pChild->NextMovePeer() )
|
||||
{
|
||||
C_MaterialModifyControl *pControl = dynamic_cast<C_MaterialModifyControl*>( pChild );
|
||||
if ( !pControl )
|
||||
continue;
|
||||
|
||||
if ( !pControl->HasNewAnimationCommands() )
|
||||
continue;
|
||||
|
||||
// Read the data from the modify entity
|
||||
materialanimcommands_t sCommands;
|
||||
pControl->GetAnimationCommands( &sCommands );
|
||||
|
||||
m_iFrameStart = sCommands.iFrameStart;
|
||||
m_iFrameEnd = sCommands.iFrameEnd;
|
||||
m_bCustomWrap = sCommands.bWrap;
|
||||
m_flCustomFramerate = sCommands.flFrameRate;
|
||||
m_bReachedEnd = false;
|
||||
|
||||
m_flStartTime = gpGlobals->curtime;
|
||||
|
||||
pControl->ClearAnimationCommands();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Init all the vars based on whether we're using the base material settings,
|
||||
// or the custom ones from the entity input.
|
||||
int numFrames;
|
||||
bool bWrapAnimation;
|
||||
float flFrameRate;
|
||||
int iLastFrame;
|
||||
|
||||
// Do we have a custom frame section from the server?
|
||||
if ( m_iFrameStart != MATERIAL_MODIFY_ANIMATION_UNSET )
|
||||
{
|
||||
if ( m_iFrameEnd == MATERIAL_MODIFY_ANIMATION_UNSET )
|
||||
{
|
||||
m_iFrameEnd = pTexture->GetNumAnimationFrames();
|
||||
}
|
||||
|
||||
numFrames = (m_iFrameEnd - m_iFrameStart) + 1;
|
||||
bWrapAnimation = m_bCustomWrap;
|
||||
flFrameRate = m_flCustomFramerate;
|
||||
iLastFrame = (m_iFrameEnd - 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
numFrames = pTexture->GetNumAnimationFrames();
|
||||
bWrapAnimation = m_WrapAnimation;
|
||||
flFrameRate = m_FrameRate;
|
||||
iLastFrame = (numFrames - 1);
|
||||
}
|
||||
|
||||
// Have we already reached the end? If so, stay there.
|
||||
if ( m_bReachedEnd && !bWrapAnimation )
|
||||
{
|
||||
m_AnimatedTextureFrameNumVar->SetIntValue( iLastFrame );
|
||||
return;
|
||||
}
|
||||
|
||||
// NOTE: Must not use relative time based methods here
|
||||
// because the bind proxy can be called many times per frame.
|
||||
// Prevent multiple Wrap callbacks to be sent for no wrap mode
|
||||
float startTime;
|
||||
if ( m_iFrameStart != MATERIAL_MODIFY_ANIMATION_UNSET )
|
||||
{
|
||||
startTime = m_flStartTime;
|
||||
}
|
||||
else
|
||||
{
|
||||
startTime = GetAnimationStartTime(pEntity);
|
||||
}
|
||||
float deltaTime = gpGlobals->curtime - startTime;
|
||||
float prevTime = deltaTime - gpGlobals->frametime;
|
||||
|
||||
// Clamp..
|
||||
if (deltaTime < 0.0f)
|
||||
deltaTime = 0.0f;
|
||||
if (prevTime < 0.0f)
|
||||
prevTime = 0.0f;
|
||||
|
||||
float frame = flFrameRate * deltaTime;
|
||||
float prevFrame = flFrameRate * prevTime;
|
||||
|
||||
int intFrame = ((int)frame) % numFrames;
|
||||
int intPrevFrame = ((int)prevFrame) % numFrames;
|
||||
|
||||
if ( m_iFrameStart != MATERIAL_MODIFY_ANIMATION_UNSET )
|
||||
{
|
||||
intFrame += m_iFrameStart;
|
||||
intPrevFrame += m_iFrameStart;
|
||||
}
|
||||
|
||||
// Report wrap situation...
|
||||
if (intPrevFrame > intFrame)
|
||||
{
|
||||
m_bReachedEnd = true;
|
||||
|
||||
if (bWrapAnimation)
|
||||
{
|
||||
AnimationWrapped( pEntity );
|
||||
}
|
||||
else
|
||||
{
|
||||
// Only sent the wrapped message once.
|
||||
// when we're in non-wrapping mode
|
||||
if (prevFrame < numFrames)
|
||||
AnimationWrapped( pEntity );
|
||||
intFrame = numFrames - 1;
|
||||
}
|
||||
}
|
||||
|
||||
m_AnimatedTextureFrameNumVar->SetIntValue( intFrame );
|
||||
|
||||
if ( ToolsEnabled() )
|
||||
{
|
||||
ToolFramework_RecordMaterialParams( GetMaterial() );
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
float CMaterialModifyAnimatedProxy::GetAnimationStartTime( void* pArg )
|
||||
{
|
||||
IClientRenderable *pRend = (IClientRenderable *)pArg;
|
||||
if (!pRend)
|
||||
return 0.0f;
|
||||
|
||||
C_BaseEntity* pEntity = pRend->GetIClientUnknown()->GetBaseEntity();
|
||||
if (pEntity)
|
||||
{
|
||||
return pEntity->GetTextureAnimationStartTime();
|
||||
}
|
||||
return 0.0f;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
void CMaterialModifyAnimatedProxy::AnimationWrapped( void* pArg )
|
||||
{
|
||||
IClientRenderable *pRend = (IClientRenderable *)pArg;
|
||||
if (!pRend)
|
||||
return;
|
||||
|
||||
C_BaseEntity* pEntity = pRend->GetIClientUnknown()->GetBaseEntity();
|
||||
if (pEntity)
|
||||
{
|
||||
pEntity->TextureAnimationWrapped();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
EXPOSE_INTERFACE( CMaterialModifyProxy, IMaterialProxy, "MaterialModify" IMATERIAL_PROXY_INTERFACE_VERSION );
|
||||
EXPOSE_INTERFACE( CMaterialModifyAnimatedProxy, IMaterialProxy, "MaterialModifyAnimated" IMATERIAL_PROXY_INTERFACE_VERSION );
|
||||
@@ -0,0 +1,60 @@
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose: Water LOD control entity.
|
||||
//
|
||||
// $NoKeywords: $
|
||||
//=============================================================================//
|
||||
#include "cbase.h"
|
||||
#include "iviewrender.h"
|
||||
|
||||
// memdbgon must be the last include file in a .cpp file!!!
|
||||
#include "tier0/memdbgon.h"
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// FIXME: This really should inherit from something more lightweight
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Purpose : Water LOD control entity
|
||||
//------------------------------------------------------------------------------
|
||||
class C_WaterLODControl : public C_BaseEntity
|
||||
{
|
||||
public:
|
||||
DECLARE_CLASS( C_WaterLODControl, C_BaseEntity );
|
||||
|
||||
DECLARE_CLIENTCLASS();
|
||||
|
||||
void OnDataChanged(DataUpdateType_t updateType);
|
||||
bool ShouldDraw();
|
||||
|
||||
private:
|
||||
float m_flCheapWaterStartDistance;
|
||||
float m_flCheapWaterEndDistance;
|
||||
};
|
||||
|
||||
IMPLEMENT_CLIENTCLASS_DT(C_WaterLODControl, DT_WaterLODControl, CWaterLODControl)
|
||||
RecvPropFloat(RECVINFO(m_flCheapWaterStartDistance)),
|
||||
RecvPropFloat(RECVINFO(m_flCheapWaterEndDistance)),
|
||||
END_RECV_TABLE()
|
||||
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Purpose :
|
||||
// Input :
|
||||
// Output :
|
||||
//------------------------------------------------------------------------------
|
||||
void C_WaterLODControl::OnDataChanged(DataUpdateType_t updateType)
|
||||
{
|
||||
view->SetCheapWaterStartDistance( m_flCheapWaterStartDistance );
|
||||
view->SetCheapWaterEndDistance( m_flCheapWaterEndDistance );
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// We don't draw...
|
||||
//------------------------------------------------------------------------------
|
||||
bool C_WaterLODControl::ShouldDraw()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,231 @@
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose: Utility code.
|
||||
//
|
||||
// $NoKeywords: $
|
||||
//=============================================================================//
|
||||
#include "cbase.h"
|
||||
#include "IEffects.h"
|
||||
#include "fx.h"
|
||||
#include "c_te_legacytempents.h"
|
||||
|
||||
// memdbgon must be the last include file in a .cpp file!!!
|
||||
#include "tier0/memdbgon.h"
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Client-server neutral effects interface
|
||||
//-----------------------------------------------------------------------------
|
||||
class CEffectsClient : public IEffects
|
||||
{
|
||||
public:
|
||||
CEffectsClient();
|
||||
virtual ~CEffectsClient();
|
||||
|
||||
// Members of the IEffect interface
|
||||
virtual void Beam( const Vector &Start, const Vector &End, int nModelIndex,
|
||||
int nHaloIndex, unsigned char frameStart, unsigned char frameRate,
|
||||
float flLife, unsigned char width, unsigned char endWidth, unsigned char fadeLength,
|
||||
unsigned char noise, unsigned char red, unsigned char green,
|
||||
unsigned char blue, unsigned char brightness, unsigned char speed);
|
||||
virtual void Smoke( const Vector &origin, int modelIndex, float scale, float framerate );
|
||||
virtual void Sparks( const Vector &position, int nMagnitude = 1, int nTrailLength = 1, const Vector *pvecDir = NULL );
|
||||
virtual void Dust( const Vector &pos, const Vector &dir, float size, float speed );
|
||||
virtual void MuzzleFlash( const Vector &origin, const QAngle &angles, float fScale, int type );
|
||||
virtual void MetalSparks( const Vector &position, const Vector &direction );
|
||||
virtual void EnergySplash( const Vector &position, const Vector &direction, bool bExplosive = false );
|
||||
virtual void Ricochet( const Vector &position, const Vector &direction );
|
||||
|
||||
// FIXME: Should these methods remain in this interface? Or go in some
|
||||
// other client-server neutral interface?
|
||||
virtual float Time();
|
||||
virtual bool IsServer();
|
||||
virtual void SuppressEffectsSounds( bool bSuppress );
|
||||
|
||||
private:
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Returning true means don't even call TE func
|
||||
// Input : filter -
|
||||
// *suppress_host -
|
||||
// Output : static bool
|
||||
//-----------------------------------------------------------------------------
|
||||
bool SuppressTE( C_RecipientFilter& filter )
|
||||
{
|
||||
if ( !CanPredict() )
|
||||
return true;
|
||||
|
||||
if ( !filter.GetRecipientCount() )
|
||||
{
|
||||
// Suppress it
|
||||
return true;
|
||||
}
|
||||
|
||||
// There's at least one recipient
|
||||
return false;
|
||||
}
|
||||
|
||||
bool m_bSuppressSound;
|
||||
};
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Client-server neutral effects interface accessor
|
||||
//-----------------------------------------------------------------------------
|
||||
static CEffectsClient s_EffectClient;
|
||||
EXPOSE_SINGLE_INTERFACE_GLOBALVAR(CEffectsClient, IEffects, IEFFECTS_INTERFACE_VERSION, s_EffectClient);
|
||||
IEffects *g_pEffects = &s_EffectClient;
|
||||
|
||||
ConVar r_decals( "r_decals", "2048" );
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// constructor, destructor
|
||||
//-----------------------------------------------------------------------------
|
||||
CEffectsClient::CEffectsClient()
|
||||
{
|
||||
m_bSuppressSound = false;
|
||||
}
|
||||
|
||||
CEffectsClient::~CEffectsClient()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Suppress sound on effects
|
||||
//-----------------------------------------------------------------------------
|
||||
void CEffectsClient::SuppressEffectsSounds( bool bSuppress )
|
||||
{
|
||||
m_bSuppressSound = bSuppress;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Generates a beam
|
||||
//-----------------------------------------------------------------------------
|
||||
void CEffectsClient::Beam( const Vector &vecStartPoint, const Vector &vecEndPoint,
|
||||
int nModelIndex, int nHaloIndex, unsigned char frameStart, unsigned char nFrameRate,
|
||||
float flLife, unsigned char nWidth, unsigned char nEndWidth, unsigned char nFadeLength,
|
||||
unsigned char noise, unsigned char r, unsigned char g,
|
||||
unsigned char b, unsigned char brightness, unsigned char nSpeed)
|
||||
{
|
||||
Assert(0);
|
||||
// CBroadcastRecipientFilter filter;
|
||||
// if ( !SuppressTE( filter ) )
|
||||
// {
|
||||
// beams->CreateBeamPoints( vecStartPoint, vecEndPoint, nModelIndex, nHaloIndex,
|
||||
// m_fHaloScale,
|
||||
// flLife, 0.1 * nWidth, 0.1 * nEndWidth, nFadeLength, 0.01 * nAmplitude, a, 0.1 * nSpeed,
|
||||
// m_nStartFrame, 0.1 * nFrameRate, r, g, b );
|
||||
// }
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Generates various tempent effects
|
||||
//-----------------------------------------------------------------------------
|
||||
void CEffectsClient::Smoke( const Vector &vecOrigin, int modelIndex, float scale, float framerate )
|
||||
{
|
||||
CPVSFilter filter( vecOrigin );
|
||||
if ( !SuppressTE( filter ) )
|
||||
{
|
||||
int iColor = random->RandomInt(20,35);
|
||||
color32 color;
|
||||
color.r = iColor;
|
||||
color.g = iColor;
|
||||
color.b = iColor;
|
||||
color.a = iColor;
|
||||
QAngle angles;
|
||||
VectorAngles( Vector(0,0,1), angles );
|
||||
FX_Smoke( vecOrigin, angles, scale * 0.1f, 4, (unsigned char *)&color, 255 );
|
||||
}
|
||||
}
|
||||
|
||||
void CEffectsClient::Sparks( const Vector &position, int nMagnitude, int nTrailLength, const Vector *pVecDir )
|
||||
{
|
||||
CPVSFilter filter( position );
|
||||
if ( !SuppressTE( filter ) )
|
||||
{
|
||||
FX_ElectricSpark( position, nMagnitude, nTrailLength, pVecDir );
|
||||
}
|
||||
}
|
||||
|
||||
void CEffectsClient::Dust( const Vector &pos, const Vector &dir, float size, float speed )
|
||||
{
|
||||
CPVSFilter filter( pos );
|
||||
if ( !SuppressTE( filter ) )
|
||||
{
|
||||
FX_Dust( pos, dir, size, speed );
|
||||
}
|
||||
}
|
||||
|
||||
void CEffectsClient::MuzzleFlash( const Vector &vecOrigin, const QAngle &vecAngles, float flScale, int iType )
|
||||
{
|
||||
CPVSFilter filter( vecOrigin );
|
||||
if ( !SuppressTE( filter ) )
|
||||
{
|
||||
switch( iType )
|
||||
{
|
||||
case MUZZLEFLASH_TYPE_DEFAULT:
|
||||
FX_MuzzleEffect( vecOrigin, vecAngles, flScale, INVALID_EHANDLE_INDEX );
|
||||
break;
|
||||
|
||||
case MUZZLEFLASH_TYPE_GUNSHIP:
|
||||
FX_GunshipMuzzleEffect( vecOrigin, vecAngles, flScale, INVALID_EHANDLE_INDEX );
|
||||
break;
|
||||
|
||||
case MUZZLEFLASH_TYPE_STRIDER:
|
||||
FX_StriderMuzzleEffect( vecOrigin, vecAngles, flScale, INVALID_EHANDLE_INDEX );
|
||||
break;
|
||||
|
||||
default:
|
||||
Msg("No case for Muzzleflash type: %d\n", iType );
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CEffectsClient::MetalSparks( const Vector &position, const Vector &direction )
|
||||
{
|
||||
CPVSFilter filter( position );
|
||||
if ( !SuppressTE( filter ) )
|
||||
{
|
||||
FX_MetalSpark( position, direction, direction );
|
||||
}
|
||||
}
|
||||
|
||||
void CEffectsClient::EnergySplash( const Vector &position, const Vector &direction, bool bExplosive )
|
||||
{
|
||||
CPVSFilter filter( position );
|
||||
if ( !SuppressTE( filter ) )
|
||||
{
|
||||
FX_EnergySplash( position, direction, bExplosive );
|
||||
}
|
||||
}
|
||||
|
||||
void CEffectsClient::Ricochet( const Vector &position, const Vector &direction )
|
||||
{
|
||||
CPVSFilter filter( position );
|
||||
if ( !SuppressTE( filter ) )
|
||||
{
|
||||
FX_MetalSpark( position, direction, direction );
|
||||
|
||||
if ( !m_bSuppressSound )
|
||||
{
|
||||
FX_RicochetSound( position );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// FIXME: Should these methods remain in this interface? Or go in some
|
||||
// other client-server neutral interface?
|
||||
float CEffectsClient::Time()
|
||||
{
|
||||
return gpGlobals->curtime;
|
||||
}
|
||||
|
||||
|
||||
bool CEffectsClient::IsServer()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,63 @@
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
// $NoKeywords: $
|
||||
//=============================================================================//
|
||||
#include "cbase.h"
|
||||
#include "functionproxy.h"
|
||||
#include "toolframework_client.h"
|
||||
|
||||
// memdbgon must be the last include file in a .cpp file!!!
|
||||
#include "tier0/memdbgon.h"
|
||||
|
||||
// forward declarations
|
||||
void ToolFramework_RecordMaterialParams( IMaterial *pMaterial );
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Returns the player health (from 0 to 1)
|
||||
//-----------------------------------------------------------------------------
|
||||
class CProxyIsNPC : public CResultProxy
|
||||
{
|
||||
public:
|
||||
bool Init( IMaterial *pMaterial, KeyValues *pKeyValues );
|
||||
void OnBind( void *pC_BaseEntity );
|
||||
|
||||
private:
|
||||
CFloatInput m_Factor;
|
||||
};
|
||||
|
||||
bool CProxyIsNPC::Init( IMaterial *pMaterial, KeyValues *pKeyValues )
|
||||
{
|
||||
if (!CResultProxy::Init( pMaterial, pKeyValues ))
|
||||
return false;
|
||||
|
||||
if (!m_Factor.Init( pMaterial, pKeyValues, "scale", 1 ))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void CProxyIsNPC::OnBind( void *pC_BaseEntity )
|
||||
{
|
||||
if ( !pC_BaseEntity )
|
||||
return;
|
||||
|
||||
C_BaseEntity *pEntity = BindArgToEntity( pC_BaseEntity );
|
||||
if ( pEntity && pEntity->IsNPC() )
|
||||
{
|
||||
SetFloatResult( m_Factor.GetFloat() );
|
||||
}
|
||||
else
|
||||
{
|
||||
SetFloatResult( 0.0f );
|
||||
}
|
||||
if ( ToolsEnabled() )
|
||||
{
|
||||
ToolFramework_RecordMaterialParams( GetMaterial() );
|
||||
}
|
||||
}
|
||||
|
||||
EXPOSE_INTERFACE( CProxyIsNPC, IMaterialProxy, "IsNPC" IMATERIAL_PROXY_INTERFACE_VERSION );
|
||||
|
||||
|
||||
@@ -0,0 +1,60 @@
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
// $NoKeywords: $
|
||||
//=============================================================================//
|
||||
#include "cbase.h"
|
||||
#include "materialsystem/imaterialproxy.h"
|
||||
#include "materialsystem/imaterial.h"
|
||||
#include "materialsystem/imaterialvar.h"
|
||||
|
||||
// $monitorTextureVar
|
||||
class CMonitorMaterialProxy : public IMaterialProxy
|
||||
{
|
||||
public:
|
||||
CMonitorMaterialProxy();
|
||||
virtual ~CMonitorMaterialProxy();
|
||||
virtual bool Init( IMaterial *pMaterial, KeyValues *pKeyValues );
|
||||
virtual void OnBind( void *pC_BaseEntity );
|
||||
virtual void Release( void ) { delete this; }
|
||||
private:
|
||||
IMaterialVar *m_pMonitorTextureVar;
|
||||
};
|
||||
|
||||
CMonitorMaterialProxy::CMonitorMaterialProxy()
|
||||
{
|
||||
m_pMonitorTextureVar = NULL;
|
||||
}
|
||||
|
||||
CMonitorMaterialProxy::~CMonitorMaterialProxy()
|
||||
{
|
||||
m_pMonitorTextureVar = NULL;
|
||||
}
|
||||
|
||||
|
||||
bool CMonitorMaterialProxy::Init( IMaterial *pMaterial, KeyValues *pKeyValues )
|
||||
{
|
||||
char const* pMonitorTextureVarName = pKeyValues->getString( "$monitorTextureVar" );
|
||||
if( !pMonitorTextureVarName )
|
||||
return false;
|
||||
|
||||
bool foundVar;
|
||||
m_pMonitorTextureVar = pMaterial->FindVar( pMonitorTextureVarName, &foundVar, false );
|
||||
if( !foundVar )
|
||||
{
|
||||
m_pMonitorTextureVar = NULL;
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void CMonitorMaterialProxy::OnBind( void *pC_BaseEntity )
|
||||
{
|
||||
if( !m_pMonitorTextureVar )
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
EXPOSE_INTERFACE( CMonitorMaterialProxy, IMaterialProxy, "Monitor" IMATERIAL_PROXY_INTERFACE_VERSION );
|
||||
@@ -0,0 +1,245 @@
|
||||
// C_NextBot.cpp
|
||||
// Client-side implementation of Next generation bot system
|
||||
// Author: Michael Booth, April 2005
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
|
||||
#include "cbase.h"
|
||||
#include "C_NextBot.h"
|
||||
#include "debugoverlay_shared.h"
|
||||
#include <bitbuf.h>
|
||||
#include "viewrender.h"
|
||||
|
||||
// memdbgon must be the last include file in a .cpp file!!!
|
||||
#include "tier0/memdbgon.h"
|
||||
|
||||
#undef NextBot
|
||||
|
||||
ConVar NextBotShadowDist( "nb_shadow_dist", "400" );
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
IMPLEMENT_CLIENTCLASS_DT( C_NextBotCombatCharacter, DT_NextBot, NextBotCombatCharacter )
|
||||
END_RECV_TABLE()
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
C_NextBotCombatCharacter::C_NextBotCombatCharacter()
|
||||
{
|
||||
// Left4Dead have surfaces too steep for IK to work properly
|
||||
m_EntClientFlags |= ENTCLIENTFLAG_DONTUSEIK;
|
||||
|
||||
m_shadowType = SHADOWS_SIMPLE;
|
||||
m_forcedShadowType = SHADOWS_NONE;
|
||||
m_bForceShadowType = false;
|
||||
|
||||
TheClientNextBots().Register( this );
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
C_NextBotCombatCharacter::~C_NextBotCombatCharacter()
|
||||
{
|
||||
TheClientNextBots().UnRegister( this );
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
void C_NextBotCombatCharacter::Spawn( void )
|
||||
{
|
||||
BaseClass::Spawn();
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
void C_NextBotCombatCharacter::UpdateClientSideAnimation()
|
||||
{
|
||||
if (IsDormant())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
BaseClass::UpdateClientSideAnimation();
|
||||
}
|
||||
|
||||
|
||||
//--------------------------------------------------------------------------------------------------------
|
||||
void C_NextBotCombatCharacter::UpdateShadowLOD( void )
|
||||
{
|
||||
ShadowType_t oldShadowType = m_shadowType;
|
||||
|
||||
if ( m_bForceShadowType )
|
||||
{
|
||||
m_shadowType = m_forcedShadowType;
|
||||
}
|
||||
else
|
||||
{
|
||||
#ifdef NEED_SPLITSCREEN_INTEGRATION
|
||||
FOR_EACH_VALID_SPLITSCREEN_PLAYER( hh )
|
||||
{
|
||||
C_BasePlayer *pl = C_BasePlayer::GetLocalPlayer(hh);
|
||||
if ( pl )
|
||||
{
|
||||
Vector delta = GetAbsOrigin() - C_BasePlayer::GetLocalPlayer(hh)->GetAbsOrigin();
|
||||
#else
|
||||
{
|
||||
if ( C_BasePlayer::GetLocalPlayer() )
|
||||
{
|
||||
Vector delta = GetAbsOrigin() - C_BasePlayer::GetLocalPlayer()->GetAbsOrigin();
|
||||
#endif
|
||||
if ( delta.IsLengthLessThan( NextBotShadowDist.GetFloat() ) )
|
||||
{
|
||||
m_shadowType = SHADOWS_RENDER_TO_TEXTURE_DYNAMIC;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_shadowType = SHADOWS_SIMPLE;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
m_shadowType = SHADOWS_SIMPLE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ( oldShadowType != m_shadowType )
|
||||
{
|
||||
DestroyShadow();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//--------------------------------------------------------------------------------------------------------
|
||||
ShadowType_t C_NextBotCombatCharacter::ShadowCastType( void )
|
||||
{
|
||||
if ( !IsVisible() )
|
||||
return SHADOWS_NONE;
|
||||
|
||||
if ( m_shadowTimer.IsElapsed() )
|
||||
{
|
||||
m_shadowTimer.Start( 0.15f );
|
||||
UpdateShadowLOD();
|
||||
}
|
||||
|
||||
return m_shadowType;
|
||||
}
|
||||
|
||||
|
||||
//--------------------------------------------------------------------------------------------------------
|
||||
bool C_NextBotCombatCharacter::GetForcedShadowCastType( ShadowType_t* pForcedShadowType ) const
|
||||
{
|
||||
if ( pForcedShadowType )
|
||||
{
|
||||
*pForcedShadowType = m_forcedShadowType;
|
||||
}
|
||||
return m_bForceShadowType;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------------
|
||||
/**
|
||||
* Singleton accessor.
|
||||
* By returning a reference, we guarantee construction of the
|
||||
* instance before its first use.
|
||||
*/
|
||||
C_NextBotManager &TheClientNextBots( void )
|
||||
{
|
||||
static C_NextBotManager manager;
|
||||
return manager;
|
||||
}
|
||||
|
||||
|
||||
//--------------------------------------------------------------------------------------------------------
|
||||
C_NextBotManager::C_NextBotManager( void )
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
//--------------------------------------------------------------------------------------------------------
|
||||
C_NextBotManager::~C_NextBotManager()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
//--------------------------------------------------------------------------------------------------------
|
||||
void C_NextBotManager::Register( C_NextBotCombatCharacter *bot )
|
||||
{
|
||||
m_botList.AddToTail( bot );
|
||||
}
|
||||
|
||||
|
||||
//--------------------------------------------------------------------------------------------------------
|
||||
void C_NextBotManager::UnRegister( C_NextBotCombatCharacter *bot )
|
||||
{
|
||||
m_botList.FindAndRemove( bot );
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
bool C_NextBotManager::SetupInFrustumData( void )
|
||||
{
|
||||
#ifdef ENABLE_AFTER_INTEGRATION
|
||||
// Done already this frame.
|
||||
if ( IsInFrustumDataValid() )
|
||||
return true;
|
||||
|
||||
// Can we use the view data yet?
|
||||
if ( !FrustumCache()->IsValid() )
|
||||
return false;
|
||||
|
||||
// Get the number of active bots.
|
||||
int nBotCount = m_botList.Count();
|
||||
|
||||
// Reset.
|
||||
for ( int iBot = 0; iBot < nBotCount; ++iBot )
|
||||
{
|
||||
// Get the current bot.
|
||||
C_NextBotCombatCharacter *pBot = m_botList[iBot];
|
||||
if ( !pBot )
|
||||
continue;
|
||||
|
||||
pBot->InitFrustumData();
|
||||
}
|
||||
|
||||
FOR_EACH_VALID_SPLITSCREEN_PLAYER( iSlot )
|
||||
{
|
||||
ACTIVE_SPLITSCREEN_PLAYER_GUARD( iSlot );
|
||||
// Get the active local player.
|
||||
C_BasePlayer *pPlayer = C_BasePlayer::GetLocalPlayer();
|
||||
if ( !pPlayer )
|
||||
continue;
|
||||
|
||||
for ( int iBot = 0; iBot < nBotCount; ++iBot )
|
||||
{
|
||||
// Get the current bot.
|
||||
C_NextBotCombatCharacter *pBot = m_botList[iBot];
|
||||
if ( !pBot )
|
||||
continue;
|
||||
|
||||
// Are we in the view frustum?
|
||||
Vector vecMin, vecMax;
|
||||
pBot->CollisionProp()->WorldSpaceAABB( &vecMin, &vecMax );
|
||||
bool bInFrustum = !FrustumCache()->m_Frustums[iSlot].CullBox( vecMin, vecMax );
|
||||
|
||||
if ( bInFrustum )
|
||||
{
|
||||
Vector vecSegment;
|
||||
VectorSubtract( pBot->GetAbsOrigin(), pPlayer->GetAbsOrigin(), vecSegment );
|
||||
float flDistance = vecSegment.LengthSqr();
|
||||
if ( flDistance < pBot->GetInFrustumDistanceSqr() )
|
||||
{
|
||||
pBot->SetInFrustumDistanceSqr( flDistance );
|
||||
}
|
||||
|
||||
pBot->SetInFrustum( true );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Mark as setup this frame.
|
||||
m_nInFrustumFrame = gpGlobals->framecount;
|
||||
#endif
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------------
|
||||
@@ -0,0 +1,134 @@
|
||||
// C_NextBot.h
|
||||
// Next generation bot system
|
||||
// Author: Michael Booth, April 2005
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
|
||||
#ifndef _C_NEXT_BOT_H_
|
||||
#define _C_NEXT_BOT_H_
|
||||
|
||||
#include "c_ai_basenpc.h"
|
||||
|
||||
//----------------------------------------------------------------------------------------------------------------
|
||||
/**
|
||||
* The interface holding IBody information
|
||||
*/
|
||||
class IBodyClient
|
||||
{
|
||||
public:
|
||||
enum ActivityType
|
||||
{
|
||||
MOTION_CONTROLLED_XY = 0x0001, // XY position and orientation of the bot is driven by the animation.
|
||||
MOTION_CONTROLLED_Z = 0x0002, // Z position of the bot is driven by the animation.
|
||||
ACTIVITY_UNINTERRUPTIBLE= 0x0004, // activity can't be changed until animation finishes
|
||||
ACTIVITY_TRANSITORY = 0x0008, // a short animation that takes over from the underlying animation momentarily, resuming it upon completion
|
||||
ENTINDEX_PLAYBACK_RATE = 0x0010, // played back at different rates based on entindex
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
//--------------------------------------------------------------------------------------------------------
|
||||
/**
|
||||
* The client-side implementation of the NextBot
|
||||
*/
|
||||
class C_NextBotCombatCharacter : public C_BaseCombatCharacter
|
||||
{
|
||||
public:
|
||||
DECLARE_CLASS( C_NextBotCombatCharacter, C_BaseCombatCharacter );
|
||||
DECLARE_CLIENTCLASS();
|
||||
|
||||
C_NextBotCombatCharacter();
|
||||
virtual ~C_NextBotCombatCharacter();
|
||||
|
||||
public:
|
||||
virtual void Spawn( void );
|
||||
virtual void UpdateClientSideAnimation( void );
|
||||
virtual ShadowType_t ShadowCastType( void );
|
||||
virtual bool IsNextBot() { return true; }
|
||||
void ForceShadowCastType( bool bForce, ShadowType_t forcedShadowType = SHADOWS_NONE ) { m_bForceShadowType = bForce; m_forcedShadowType = forcedShadowType; }
|
||||
bool GetForcedShadowCastType( ShadowType_t* pForcedShadowType ) const;
|
||||
|
||||
// Local In View Data.
|
||||
void InitFrustumData( void ) { m_bInFrustum = false; m_flFrustumDistanceSqr = FLT_MAX; m_nInFrustumFrame = gpGlobals->framecount; }
|
||||
bool IsInFrustumValid( void ) { return ( m_nInFrustumFrame == gpGlobals->framecount ); }
|
||||
void SetInFrustum( bool bInFrustum ) { m_bInFrustum = bInFrustum; }
|
||||
bool IsInFrustum( void ) { return m_bInFrustum; }
|
||||
void SetInFrustumDistanceSqr( float flDistance ) { m_flFrustumDistanceSqr = flDistance; }
|
||||
float GetInFrustumDistanceSqr( void ) { return m_flFrustumDistanceSqr; }
|
||||
|
||||
private:
|
||||
ShadowType_t m_shadowType; // Are we LOD'd to simple shadows?
|
||||
CountdownTimer m_shadowTimer; // Timer to throttle checks for shadow LOD
|
||||
ShadowType_t m_forcedShadowType;
|
||||
bool m_bForceShadowType;
|
||||
void UpdateShadowLOD( void );
|
||||
|
||||
// Local In View Data.
|
||||
int m_nInFrustumFrame;
|
||||
bool m_bInFrustum;
|
||||
float m_flFrustumDistanceSqr;
|
||||
|
||||
private:
|
||||
C_NextBotCombatCharacter( const C_NextBotCombatCharacter & ); // not defined, not accessible
|
||||
};
|
||||
|
||||
//--------------------------------------------------------------------------------------------------------
|
||||
/**
|
||||
* The C_NextBotManager manager
|
||||
*/
|
||||
class C_NextBotManager
|
||||
{
|
||||
public:
|
||||
C_NextBotManager( void );
|
||||
~C_NextBotManager();
|
||||
|
||||
/**
|
||||
* Execute functor for each NextBot in the system.
|
||||
* If a functor returns false, stop iteration early
|
||||
* and return false.
|
||||
*/
|
||||
template < typename Functor >
|
||||
bool ForEachCombatCharacter( Functor &func )
|
||||
{
|
||||
for( int i=0; i < m_botList.Count(); ++i )
|
||||
{
|
||||
C_NextBotCombatCharacter *character = m_botList[i];
|
||||
if ( character->IsPlayer() )
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if ( character->IsDormant() )
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if ( !func( character ) )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
int GetActiveCount() { return m_botList.Count(); }
|
||||
|
||||
bool SetupInFrustumData( void );
|
||||
bool IsInFrustumDataValid( void ) { return ( m_nInFrustumFrame == gpGlobals->framecount ); }
|
||||
|
||||
private:
|
||||
friend class C_NextBotCombatCharacter;
|
||||
|
||||
void Register( C_NextBotCombatCharacter *bot );
|
||||
void UnRegister( C_NextBotCombatCharacter *bot );
|
||||
|
||||
CUtlVector< C_NextBotCombatCharacter * > m_botList; ///< list of all active NextBots
|
||||
|
||||
int m_nInFrustumFrame;
|
||||
};
|
||||
|
||||
// singleton accessor
|
||||
extern C_NextBotManager &TheClientNextBots( void );
|
||||
|
||||
|
||||
#endif // _C_NEXT_BOT_H_
|
||||
@@ -0,0 +1,59 @@
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
// $NoKeywords: $
|
||||
//=============================================================================//
|
||||
#include "cbase.h"
|
||||
#include "functionproxy.h"
|
||||
#include "toolframework_client.h"
|
||||
|
||||
// memdbgon must be the last include file in a .cpp file!!!
|
||||
#include "tier0/memdbgon.h"
|
||||
|
||||
// forward declarations
|
||||
void ToolFramework_RecordMaterialParams( IMaterial *pMaterial );
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Returns the player health (from 0 to 1)
|
||||
//-----------------------------------------------------------------------------
|
||||
class CProxyHealth : public CResultProxy
|
||||
{
|
||||
public:
|
||||
bool Init( IMaterial *pMaterial, KeyValues *pKeyValues );
|
||||
void OnBind( void *pC_BaseEntity );
|
||||
|
||||
private:
|
||||
CFloatInput m_Factor;
|
||||
};
|
||||
|
||||
bool CProxyHealth::Init( IMaterial *pMaterial, KeyValues *pKeyValues )
|
||||
{
|
||||
if (!CResultProxy::Init( pMaterial, pKeyValues ))
|
||||
return false;
|
||||
|
||||
if (!m_Factor.Init( pMaterial, pKeyValues, "scale", 1 ))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void CProxyHealth::OnBind( void *pC_BaseEntity )
|
||||
{
|
||||
if (!pC_BaseEntity)
|
||||
return;
|
||||
|
||||
C_BaseEntity *pEntity = BindArgToEntity( pC_BaseEntity );
|
||||
|
||||
Assert( m_pResult );
|
||||
SetFloatResult( pEntity->HealthFraction() * m_Factor.GetFloat() );
|
||||
|
||||
if ( ToolsEnabled() )
|
||||
{
|
||||
ToolFramework_RecordMaterialParams( GetMaterial() );
|
||||
}
|
||||
}
|
||||
|
||||
EXPOSE_INTERFACE( CProxyHealth, IMaterialProxy, "Health" IMATERIAL_PROXY_INTERFACE_VERSION );
|
||||
|
||||
|
||||
@@ -0,0 +1,317 @@
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
#include "cbase.h"
|
||||
|
||||
#include "KeyValues.h"
|
||||
#include "cdll_client_int.h"
|
||||
#include "view_scene.h"
|
||||
#include "viewrender.h"
|
||||
#include "tier0/icommandline.h"
|
||||
#include "materialsystem/imesh.h"
|
||||
#include "materialsystem/imaterial.h"
|
||||
#include "materialsystem/imaterialsystemhardwareconfig.h"
|
||||
#include "materialsystem/imaterialvar.h"
|
||||
|
||||
#include "ScreenSpaceEffects.h"
|
||||
|
||||
// memdbgon must be the last include file in a .cpp file!!!
|
||||
#include "tier0/memdbgon.h"
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// CScreenSpaceEffectRegistration code
|
||||
// Used to register and effect with the IScreenSpaceEffectManager
|
||||
//------------------------------------------------------------------------------
|
||||
CScreenSpaceEffectRegistration *CScreenSpaceEffectRegistration::s_pHead = NULL;
|
||||
|
||||
CScreenSpaceEffectRegistration::CScreenSpaceEffectRegistration( const char *pName, IScreenSpaceEffect *pEffect )
|
||||
{
|
||||
m_pEffectName = pName;
|
||||
m_pEffect = pEffect;
|
||||
m_pNext = s_pHead;
|
||||
s_pHead = this;
|
||||
}
|
||||
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// CScreenSpaceEffectManager - Implementation of IScreenSpaceEffectManager
|
||||
//------------------------------------------------------------------------------
|
||||
class CScreenSpaceEffectManager : public IScreenSpaceEffectManager
|
||||
{
|
||||
public:
|
||||
|
||||
virtual void InitScreenSpaceEffects( );
|
||||
virtual void ShutdownScreenSpaceEffects( );
|
||||
|
||||
virtual IScreenSpaceEffect *GetScreenSpaceEffect( const char *pEffectName );
|
||||
|
||||
virtual void SetScreenSpaceEffectParams( const char *pEffectName, KeyValues *params );
|
||||
virtual void SetScreenSpaceEffectParams( IScreenSpaceEffect *pEffect, KeyValues *params );
|
||||
|
||||
virtual void EnableScreenSpaceEffect( const char *pEffectName );
|
||||
virtual void EnableScreenSpaceEffect( IScreenSpaceEffect *pEffect );
|
||||
|
||||
virtual void DisableScreenSpaceEffect( const char *pEffectName );
|
||||
virtual void DisableScreenSpaceEffect( IScreenSpaceEffect *pEffect );
|
||||
|
||||
virtual void DisableAllScreenSpaceEffects( );
|
||||
|
||||
virtual void RenderEffects( int x, int y, int w, int h );
|
||||
};
|
||||
|
||||
CScreenSpaceEffectManager g_ScreenSpaceEffectManager;
|
||||
IScreenSpaceEffectManager *g_pScreenSpaceEffects = &g_ScreenSpaceEffectManager;
|
||||
|
||||
//---------------------------------------------------------------------------------------
|
||||
// CScreenSpaceEffectManager::InitScreenSpaceEffects - Initialise all registered effects
|
||||
//---------------------------------------------------------------------------------------
|
||||
void CScreenSpaceEffectManager::InitScreenSpaceEffects( )
|
||||
{
|
||||
if ( CommandLine()->FindParm( "-filmgrain" ) )
|
||||
{
|
||||
GetScreenSpaceEffect( "filmgrain" )->Enable( true );
|
||||
}
|
||||
|
||||
for( CScreenSpaceEffectRegistration *pReg=CScreenSpaceEffectRegistration::s_pHead; pReg!=NULL; pReg=pReg->m_pNext )
|
||||
{
|
||||
IScreenSpaceEffect *pEffect = pReg->m_pEffect;
|
||||
if( pEffect )
|
||||
{
|
||||
bool bIsEnabled = pEffect->IsEnabled( );
|
||||
pEffect->Init( );
|
||||
pEffect->Enable( bIsEnabled );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//----------------------------------------------------------------------------------------
|
||||
// CScreenSpaceEffectManager::ShutdownScreenSpaceEffects - Shutdown all registered effects
|
||||
//----------------------------------------------------------------------------------------
|
||||
void CScreenSpaceEffectManager::ShutdownScreenSpaceEffects( )
|
||||
{
|
||||
for( CScreenSpaceEffectRegistration *pReg=CScreenSpaceEffectRegistration::s_pHead; pReg!=NULL; pReg=pReg->m_pNext )
|
||||
{
|
||||
IScreenSpaceEffect *pEffect = pReg->m_pEffect;
|
||||
if( pEffect )
|
||||
{
|
||||
pEffect->Shutdown( );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//---------------------------------------------------------------------------------------
|
||||
// CScreenSpaceEffectManager::GetScreenSpaceEffect - Returns a point to the named effect
|
||||
//---------------------------------------------------------------------------------------
|
||||
IScreenSpaceEffect *CScreenSpaceEffectManager::GetScreenSpaceEffect( const char *pEffectName )
|
||||
{
|
||||
for( CScreenSpaceEffectRegistration *pReg=CScreenSpaceEffectRegistration::s_pHead; pReg!=NULL; pReg=pReg->m_pNext )
|
||||
{
|
||||
if( !Q_stricmp( pReg->m_pEffectName, pEffectName ) )
|
||||
{
|
||||
IScreenSpaceEffect *pEffect = pReg->m_pEffect;
|
||||
return pEffect;
|
||||
}
|
||||
}
|
||||
|
||||
Warning( "Could not find screen space effect %s\n", pEffectName );
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
//---------------------------------------------------------------------------------------
|
||||
// CScreenSpaceEffectManager::SetScreenSpaceEffectParams
|
||||
// - Assign parameters to the specified effect
|
||||
//---------------------------------------------------------------------------------------
|
||||
void CScreenSpaceEffectManager::SetScreenSpaceEffectParams( const char *pEffectName, KeyValues *params )
|
||||
{
|
||||
IScreenSpaceEffect *pEffect = GetScreenSpaceEffect( pEffectName );
|
||||
if( pEffect )
|
||||
SetScreenSpaceEffectParams( pEffect, params );
|
||||
}
|
||||
|
||||
void CScreenSpaceEffectManager::SetScreenSpaceEffectParams( IScreenSpaceEffect *pEffect, KeyValues *params )
|
||||
{
|
||||
if( pEffect )
|
||||
pEffect->SetParameters( params );
|
||||
}
|
||||
|
||||
|
||||
//---------------------------------------------------------------------------------------
|
||||
// CScreenSpaceEffectManager::EnableScreenSpaceEffect
|
||||
// - Enables the specified effect
|
||||
//---------------------------------------------------------------------------------------
|
||||
void CScreenSpaceEffectManager::EnableScreenSpaceEffect( const char *pEffectName )
|
||||
{
|
||||
IScreenSpaceEffect *pEffect = GetScreenSpaceEffect( pEffectName );
|
||||
if( pEffect )
|
||||
EnableScreenSpaceEffect( pEffect );
|
||||
}
|
||||
|
||||
void CScreenSpaceEffectManager::EnableScreenSpaceEffect( IScreenSpaceEffect *pEffect )
|
||||
{
|
||||
if( pEffect )
|
||||
pEffect->Enable( true );
|
||||
}
|
||||
|
||||
|
||||
//---------------------------------------------------------------------------------------
|
||||
// CScreenSpaceEffectManager::DisableScreenSpaceEffect
|
||||
// - Disables the specified effect
|
||||
//---------------------------------------------------------------------------------------
|
||||
void CScreenSpaceEffectManager::DisableScreenSpaceEffect( const char *pEffectName )
|
||||
{
|
||||
IScreenSpaceEffect *pEffect = GetScreenSpaceEffect( pEffectName );
|
||||
if( pEffect )
|
||||
DisableScreenSpaceEffect( pEffect );
|
||||
}
|
||||
|
||||
void CScreenSpaceEffectManager::DisableScreenSpaceEffect( IScreenSpaceEffect *pEffect )
|
||||
{
|
||||
if( pEffect )
|
||||
pEffect->Enable( false );
|
||||
}
|
||||
|
||||
|
||||
//---------------------------------------------------------------------------------------
|
||||
// CScreenSpaceEffectManager::DisableAllScreenSpaceEffects
|
||||
// - Disables all registered screen space effects
|
||||
//---------------------------------------------------------------------------------------
|
||||
void CScreenSpaceEffectManager::DisableAllScreenSpaceEffects( )
|
||||
{
|
||||
for( CScreenSpaceEffectRegistration *pReg=CScreenSpaceEffectRegistration::s_pHead; pReg!=NULL; pReg=pReg->m_pNext )
|
||||
{
|
||||
IScreenSpaceEffect *pEffect = pReg->m_pEffect;
|
||||
if( pEffect )
|
||||
{
|
||||
pEffect->Enable( false );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//---------------------------------------------------------------------------------------
|
||||
// CScreenSpaceEffectManager::RenderEffects
|
||||
// - Renders all registered screen space effects
|
||||
//---------------------------------------------------------------------------------------
|
||||
void CScreenSpaceEffectManager::RenderEffects( int x, int y, int w, int h )
|
||||
{
|
||||
for( CScreenSpaceEffectRegistration *pReg=CScreenSpaceEffectRegistration::s_pHead; pReg!=NULL; pReg=pReg->m_pNext )
|
||||
{
|
||||
IScreenSpaceEffect *pEffect = pReg->m_pEffect;
|
||||
if( pEffect )
|
||||
{
|
||||
pEffect->Render( x, y, w, h );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Example post-processing effect
|
||||
//------------------------------------------------------------------------------
|
||||
class CExampleEffect : public IScreenSpaceEffect
|
||||
{
|
||||
public:
|
||||
CExampleEffect( );
|
||||
~CExampleEffect( );
|
||||
|
||||
void Init( );
|
||||
void Shutdown( );
|
||||
|
||||
void SetParameters( KeyValues *params );
|
||||
|
||||
void Render( int x, int y, int w, int h );
|
||||
|
||||
void Enable( bool bEnable );
|
||||
bool IsEnabled( );
|
||||
|
||||
private:
|
||||
|
||||
bool m_bEnable;
|
||||
|
||||
CMaterialReference m_Material;
|
||||
};
|
||||
|
||||
ADD_SCREENSPACE_EFFECT( CExampleEffect, exampleeffect );
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// CExampleEffect constructor
|
||||
//------------------------------------------------------------------------------
|
||||
CExampleEffect::CExampleEffect( )
|
||||
{
|
||||
m_bEnable = false;
|
||||
}
|
||||
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// CExampleEffect destructor
|
||||
//------------------------------------------------------------------------------
|
||||
CExampleEffect::~CExampleEffect( )
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// CExampleEffect init
|
||||
//------------------------------------------------------------------------------
|
||||
void CExampleEffect::Init( )
|
||||
{
|
||||
// This is just example code, init your effect material here
|
||||
//m_Material.Init( "engine/exampleeffect", TEXTURE_GROUP_OTHER );
|
||||
|
||||
m_bEnable = false;
|
||||
}
|
||||
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// CExampleEffect shutdown
|
||||
//------------------------------------------------------------------------------
|
||||
void CExampleEffect::Shutdown( )
|
||||
{
|
||||
m_Material.Shutdown();
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// CExampleEffect enable
|
||||
//------------------------------------------------------------------------------
|
||||
void CExampleEffect::Enable( bool bEnable )
|
||||
{
|
||||
// This is just example code, don't enable it
|
||||
// m_bEnable = bEnable;
|
||||
}
|
||||
|
||||
bool CExampleEffect::IsEnabled( )
|
||||
{
|
||||
return m_bEnable;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// CExampleEffect SetParameters
|
||||
//------------------------------------------------------------------------------
|
||||
void CExampleEffect::SetParameters( KeyValues *params )
|
||||
{
|
||||
if( params->GetDataType( "example_param" ) == KeyValues::TYPE_STRING )
|
||||
{
|
||||
// ...
|
||||
}
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// CExampleEffect render
|
||||
//------------------------------------------------------------------------------
|
||||
void CExampleEffect::Render( int x, int y, int w, int h )
|
||||
{
|
||||
if ( !IsEnabled() )
|
||||
return;
|
||||
|
||||
// Render Effect
|
||||
Rect_t actualRect;
|
||||
UpdateScreenEffectTexture( 0, x, y, w, h, false, &actualRect );
|
||||
ITexture *pTexture = GetFullFrameFrameBufferTexture( 0 );
|
||||
|
||||
CMatRenderContextPtr pRenderContext( materials );
|
||||
|
||||
pRenderContext->DrawScreenSpaceRectangle( m_Material, x, y, w, h,
|
||||
actualRect.x, actualRect.y, actualRect.x+actualRect.width-1, actualRect.y+actualRect.height-1,
|
||||
pTexture->GetActualWidth(), pTexture->GetActualHeight() );
|
||||
}
|
||||
@@ -0,0 +1,88 @@
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
// $NoKeywords: $
|
||||
//
|
||||
//=====================================================================================//
|
||||
|
||||
#ifndef SCREENSPACEEFFECTS_H
|
||||
#define SCREENSPACEEFFECTS_H
|
||||
|
||||
#ifdef _WIN32
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
class KeyValues;
|
||||
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Simple base class for screen space post-processing effects
|
||||
//------------------------------------------------------------------------------
|
||||
abstract_class IScreenSpaceEffect
|
||||
{
|
||||
public:
|
||||
|
||||
virtual void Init( ) = 0;
|
||||
virtual void Shutdown( ) = 0;
|
||||
|
||||
virtual void SetParameters( KeyValues *params ) = 0;
|
||||
|
||||
virtual void Render( int x, int y, int w, int h ) = 0;
|
||||
|
||||
virtual void Enable( bool bEnable ) = 0;
|
||||
virtual bool IsEnabled( ) = 0;
|
||||
};
|
||||
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Interface class for managing screen space post-processing effects
|
||||
//------------------------------------------------------------------------------
|
||||
abstract_class IScreenSpaceEffectManager
|
||||
{
|
||||
public:
|
||||
|
||||
virtual void InitScreenSpaceEffects( ) = 0;
|
||||
virtual void ShutdownScreenSpaceEffects( ) = 0;
|
||||
|
||||
virtual IScreenSpaceEffect *GetScreenSpaceEffect( const char *pEffectName ) = 0;
|
||||
|
||||
virtual void SetScreenSpaceEffectParams( const char *pEffectName, KeyValues *params ) = 0;
|
||||
virtual void SetScreenSpaceEffectParams( IScreenSpaceEffect *pEffect, KeyValues *params ) = 0;
|
||||
|
||||
virtual void EnableScreenSpaceEffect( const char *pEffectName ) = 0;
|
||||
virtual void EnableScreenSpaceEffect( IScreenSpaceEffect *pEffect ) = 0;
|
||||
|
||||
virtual void DisableScreenSpaceEffect( const char *pEffectName ) = 0;
|
||||
virtual void DisableScreenSpaceEffect( IScreenSpaceEffect *pEffect ) = 0;
|
||||
|
||||
virtual void DisableAllScreenSpaceEffects( ) = 0;
|
||||
|
||||
virtual void RenderEffects( int x, int y, int w, int h ) = 0;
|
||||
};
|
||||
|
||||
extern IScreenSpaceEffectManager *g_pScreenSpaceEffects;
|
||||
|
||||
|
||||
//-------------------------------------------------------------------------------------
|
||||
// Registration class for adding screen space effects to the IScreenSpaceEffectManager
|
||||
//-------------------------------------------------------------------------------------
|
||||
class CScreenSpaceEffectRegistration
|
||||
{
|
||||
public:
|
||||
CScreenSpaceEffectRegistration( const char *pName, IScreenSpaceEffect *pEffect );
|
||||
|
||||
const char *m_pEffectName;
|
||||
IScreenSpaceEffect *m_pEffect;
|
||||
|
||||
CScreenSpaceEffectRegistration *m_pNext;
|
||||
|
||||
static CScreenSpaceEffectRegistration *s_pHead;
|
||||
};
|
||||
|
||||
#define ADD_SCREENSPACE_EFFECT( CEffect, pEffectName ) CEffect pEffectName##_effect; \
|
||||
CScreenSpaceEffectRegistration pEffectName##_reg( #pEffectName, &pEffectName##_effect );
|
||||
|
||||
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,172 @@
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose: This is a panel which is rendered image on top of an entity
|
||||
//
|
||||
// $Revision: $
|
||||
// $NoKeywords: $
|
||||
//=============================================================================//
|
||||
#include "cbase.h"
|
||||
#include "TeamBitmapImage.h"
|
||||
#include <KeyValues.h>
|
||||
#include "vgui_bitmapimage.h"
|
||||
#include "panelmetaclassmgr.h"
|
||||
#include "VGuiMatSurface/IMatSystemSurface.h"
|
||||
#include <vgui_controls/Panel.h>
|
||||
|
||||
// memdbgon must be the last include file in a .cpp file!!!
|
||||
#include "tier0/memdbgon.h"
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// A multiplexer bitmap that chooses a bitmap based on team
|
||||
//-----------------------------------------------------------------------------
|
||||
CTeamBitmapImage::CTeamBitmapImage() : m_Alpha(1.0f)
|
||||
{
|
||||
memset( m_ppImage, 0, BITMAP_COUNT * sizeof(BitmapImage*) );
|
||||
m_pEntity = NULL;
|
||||
m_bRelativeTeams = 0;
|
||||
}
|
||||
|
||||
CTeamBitmapImage::~CTeamBitmapImage()
|
||||
{
|
||||
int i;
|
||||
for ( i = 0; i < BITMAP_COUNT; ++i )
|
||||
{
|
||||
if (m_ppImage[i])
|
||||
delete m_ppImage[i];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// initialization
|
||||
//-----------------------------------------------------------------------------
|
||||
bool CTeamBitmapImage::Init( vgui::Panel *pParent, KeyValues* pInitData, C_BaseEntity* pEntity )
|
||||
{
|
||||
static const char *pRelativeTeamNames[BITMAP_COUNT] =
|
||||
{
|
||||
"NoTeam",
|
||||
"MyTeam",
|
||||
"EnemyTeam",
|
||||
};
|
||||
|
||||
static const char *pAbsoluteTeamNames[BITMAP_COUNT] =
|
||||
{
|
||||
"Team0",
|
||||
"Team1",
|
||||
"Team2",
|
||||
};
|
||||
|
||||
m_pEntity = pEntity;
|
||||
m_bRelativeTeams = (pInitData->GetInt( "relativeteam" ) != 0);
|
||||
|
||||
const char **ppTeamNames = m_bRelativeTeams ? pRelativeTeamNames : pAbsoluteTeamNames;
|
||||
|
||||
int i;
|
||||
for ( i = 0 ; i < BITMAP_COUNT; ++i )
|
||||
{
|
||||
// Default to null
|
||||
m_ppImage[i] = NULL;
|
||||
|
||||
// Look for team section
|
||||
KeyValues *pTeamKV = pInitData->FindKey( ppTeamNames[i] );
|
||||
if ( !pTeamKV )
|
||||
continue;
|
||||
|
||||
char const* pClassImage = pTeamKV->GetString( "material" );
|
||||
if ( !pClassImage || !pClassImage[ 0 ] )
|
||||
return false;
|
||||
|
||||
// modulation color
|
||||
Color color;
|
||||
if (!ParseRGBA( pTeamKV, "color", color ))
|
||||
color.SetColor( 255, 255, 255, 255 );
|
||||
|
||||
// hook in the bitmap
|
||||
m_ppImage[i] = new BitmapImage( pParent->GetVPanel(), pClassImage );
|
||||
m_ppImage[i]->SetColor( color );
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Alpha modulate...
|
||||
//-----------------------------------------------------------------------------
|
||||
void CTeamBitmapImage::SetAlpha( float alpha )
|
||||
{
|
||||
m_Alpha = clamp( alpha, 0.0f, 1.0f );
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// draw
|
||||
//-----------------------------------------------------------------------------
|
||||
void CTeamBitmapImage::Paint( float yaw /*= 0.0f*/ )
|
||||
{
|
||||
if (m_Alpha == 0.0f)
|
||||
return;
|
||||
|
||||
int team = 0;
|
||||
if (m_bRelativeTeams)
|
||||
{
|
||||
if (GetEntity())
|
||||
{
|
||||
if (GetEntity()->GetTeamNumber() != 0)
|
||||
{
|
||||
team = GetEntity()->InLocalTeam() ? 1 : 2;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (GetEntity())
|
||||
team = GetEntity()->GetTeamNumber();
|
||||
}
|
||||
|
||||
// Paint the image for the current team
|
||||
if (m_ppImage[team])
|
||||
{
|
||||
// Modulate the color based on the alpha....
|
||||
Color color = m_ppImage[team]->GetColor();
|
||||
int alpha = color[3];
|
||||
color[3] = (alpha * m_Alpha);
|
||||
m_ppImage[team]->SetColor( color );
|
||||
|
||||
if ( yaw != 0.0f )
|
||||
{
|
||||
g_pMatSystemSurface->DisableClipping( true );
|
||||
|
||||
m_ppImage[team]->DoPaint( m_ppImage[team]->GetRenderSizePanel(), yaw );
|
||||
|
||||
g_pMatSystemSurface->DisableClipping( false );
|
||||
}
|
||||
else
|
||||
{
|
||||
// Paint
|
||||
m_ppImage[team]->Paint();
|
||||
}
|
||||
|
||||
// restore previous color
|
||||
color[3] = alpha;
|
||||
m_ppImage[team]->SetColor( color );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Helper method to initialize a team image from KeyValues data..
|
||||
//-----------------------------------------------------------------------------
|
||||
bool InitializeTeamImage( KeyValues *pInitData, const char* pSectionName, vgui::Panel *pParent, C_BaseEntity *pEntity, CTeamBitmapImage* pTeamImage )
|
||||
{
|
||||
KeyValues *pTeamImageSection = pInitData;
|
||||
if (pSectionName)
|
||||
{
|
||||
pTeamImageSection = pInitData->FindKey( pSectionName );
|
||||
if ( !pTeamImageSection )
|
||||
return false;
|
||||
}
|
||||
|
||||
return pTeamImage->Init( pParent, pTeamImageSection, pEntity );
|
||||
}
|
||||
|
||||
@@ -0,0 +1,80 @@
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose: This is a panel which is rendered image on top of an entity
|
||||
//
|
||||
// $Revision: $
|
||||
// $NoKeywords: $
|
||||
//=============================================================================//
|
||||
|
||||
#ifndef TEAMBITMAPIMAGE_H
|
||||
#define TEAMBITMAPIMAGE_H
|
||||
|
||||
#ifdef _WIN32
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
//#include "tf_shareddefs.h"
|
||||
|
||||
#include <vgui/VGUI.h>
|
||||
|
||||
namespace vgui
|
||||
{
|
||||
class Panel;
|
||||
}
|
||||
|
||||
class BitmapImage;
|
||||
class C_BaseEntity;
|
||||
class KeyValues;
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// A multiplexer bitmap that chooses a bitmap based on team
|
||||
//-----------------------------------------------------------------------------
|
||||
class CTeamBitmapImage
|
||||
{
|
||||
public:
|
||||
// construction, destruction
|
||||
CTeamBitmapImage();
|
||||
~CTeamBitmapImage();
|
||||
|
||||
// initialization
|
||||
bool Init( vgui::Panel *pParent, KeyValues* pInitData, C_BaseEntity* pEntity );
|
||||
|
||||
// Alpha override...
|
||||
void SetAlpha( float alpha );
|
||||
|
||||
// Paint the sucka. Paint it the size of the parent panel
|
||||
void Paint( float yaw = 0.0f );
|
||||
|
||||
protected:
|
||||
// Wrapper so we can implement this with EHANDLES some day
|
||||
C_BaseEntity *GetEntity() { return m_pEntity; }
|
||||
|
||||
private:
|
||||
enum
|
||||
{
|
||||
// NOTE: Was MAX_TF_TEAMS not 4, but I don't like the dependency here.
|
||||
BITMAP_COUNT = 4 + 1
|
||||
};
|
||||
|
||||
BitmapImage *m_ppImage[ BITMAP_COUNT ];
|
||||
C_BaseEntity *m_pEntity;
|
||||
float m_Alpha;
|
||||
bool m_bRelativeTeams;
|
||||
};
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Helper method to initialize a team image from KeyValues data..
|
||||
// KeyValues contains the bitmap data. pSectionName, if it exists,
|
||||
// indicates which subsection of pInitData should be looked at to get at the
|
||||
// image data. The final argument is the bitmap image to initialize.
|
||||
// The function returns true if it succeeded.
|
||||
//
|
||||
// NOTE: This function looks for the key values 'material' and 'color'
|
||||
// and uses them to set up the material + modulation color of the image
|
||||
//-----------------------------------------------------------------------------
|
||||
bool InitializeTeamImage( KeyValues *pInitData, const char* pSectionName,
|
||||
vgui::Panel *pParent, C_BaseEntity *pEntity, CTeamBitmapImage* pBitmapImage );
|
||||
|
||||
|
||||
#endif // TEAMBITMAPIMAGE_H
|
||||
@@ -0,0 +1,83 @@
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose: This is a panel which is rendered image on top of an entity
|
||||
//
|
||||
// $Revision: $
|
||||
// $NoKeywords: $
|
||||
//=============================================================================//
|
||||
#include "cbase.h"
|
||||
#include "ViewConeImage.h"
|
||||
#include <KeyValues.h>
|
||||
#include <vgui_controls/Panel.h>
|
||||
#include "VGuiMatSurface/IMatSystemSurface.h"
|
||||
|
||||
// memdbgon must be the last include file in a .cpp file!!!
|
||||
#include "tier0/memdbgon.h"
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// initialization
|
||||
//-----------------------------------------------------------------------------
|
||||
bool CViewConeImage::Init( vgui::Panel *pParent, KeyValues* pInitData )
|
||||
{
|
||||
Assert( pParent );
|
||||
|
||||
// Load viewcone material
|
||||
if (!m_Image.Init( pParent->GetVPanel(), pInitData ))
|
||||
return false;
|
||||
|
||||
// Position the view cone...
|
||||
int viewconesize = pInitData->GetInt( "size", 32 );
|
||||
m_Image.SetRenderSize( viewconesize, viewconesize );
|
||||
|
||||
int cx, cy;
|
||||
pParent->GetSize( cx, cy );
|
||||
m_Image.SetPos( (cx - viewconesize) / 2, (cy - viewconesize) / 2 );
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Paint the sucka
|
||||
//-----------------------------------------------------------------------------
|
||||
void CViewConeImage::Paint( float yaw )
|
||||
{
|
||||
g_pMatSystemSurface->DisableClipping( true );
|
||||
|
||||
m_Image.DoPaint( NULL, yaw );
|
||||
|
||||
g_pMatSystemSurface->DisableClipping( false );
|
||||
}
|
||||
|
||||
void CViewConeImage::SetColor( int r, int g, int b )
|
||||
{
|
||||
m_Image.SetColor( Color( r, g, b, 255 ) );
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Helper method to initialize a view cone image from KeyValues data..
|
||||
// KeyValues contains the bitmap data, pSectionName, if it exists,
|
||||
// indicates which subsection of pInitData should be looked at to get at the
|
||||
// image data. The final argument is the bitmap image to initialize.
|
||||
// The function returns true if it succeeded.
|
||||
//
|
||||
// NOTE: This function looks for the key values 'material' and 'color'
|
||||
// and uses them to set up the material + modulation color of the image
|
||||
//-----------------------------------------------------------------------------
|
||||
bool InitializeViewConeImage( KeyValues *pInitData, const char* pSectionName,
|
||||
vgui::Panel *pParent, CViewConeImage* pViewConeImage )
|
||||
{
|
||||
KeyValues *pViewConeImageSection;
|
||||
if (pSectionName)
|
||||
{
|
||||
pViewConeImageSection = pInitData->FindKey( pSectionName );
|
||||
if ( !pViewConeImageSection )
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
pViewConeImageSection = pInitData;
|
||||
}
|
||||
|
||||
return pViewConeImage->Init( pParent, pViewConeImageSection );
|
||||
}
|
||||
|
||||
@@ -0,0 +1,56 @@
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose: This is a panel which draws a viewcone
|
||||
//
|
||||
// $Revision: $
|
||||
// $NoKeywords: $
|
||||
//=============================================================================//
|
||||
|
||||
#ifndef VIEWCONEIMAGE_H
|
||||
#define VIEWCONEIMAGE_H
|
||||
|
||||
#include "shareddefs.h"
|
||||
#include "vgui_bitmapimage.h"
|
||||
|
||||
namespace vgui
|
||||
{
|
||||
class Panel;
|
||||
}
|
||||
|
||||
class C_BaseEntity;
|
||||
class KeyValues;
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// A bitmap that renders a view cone based on angles
|
||||
//-----------------------------------------------------------------------------
|
||||
class CViewConeImage
|
||||
{
|
||||
public:
|
||||
// initialization
|
||||
bool Init( vgui::Panel *pParent, KeyValues* pInitData );
|
||||
|
||||
// Paint the sucka
|
||||
void Paint( float yaw );
|
||||
|
||||
void SetColor( int r, int g, int b );
|
||||
|
||||
private:
|
||||
BitmapImage m_Image;
|
||||
};
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Helper method to initialize a view cone image from KeyValues data..
|
||||
// KeyValues contains the bitmap data, pSectionName, if it exists,
|
||||
// indicates which subsection of pInitData should be looked at to get at the
|
||||
// image data. The final argument is the bitmap image to initialize.
|
||||
// The function returns true if it succeeded.
|
||||
//
|
||||
// NOTE: This function looks for the key values 'material' and 'color'
|
||||
// and uses them to set up the material + modulation color of the image
|
||||
//-----------------------------------------------------------------------------
|
||||
bool InitializeViewConeImage( KeyValues *pInitData, const char* pSectionName,
|
||||
vgui::Panel *pParent, CViewConeImage* pViewConeImage );
|
||||
|
||||
|
||||
#endif // VIEWCONEIMAGE_H
|
||||
@@ -0,0 +1,83 @@
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
// $NoKeywords: $
|
||||
//=============================================================================//
|
||||
#include "cbase.h"
|
||||
#include "materialsystem/imaterialproxy.h"
|
||||
#include "materialsystem/imaterial.h"
|
||||
#include "materialsystem/imaterialvar.h"
|
||||
#include "iviewrender.h"
|
||||
#include "toolframework_client.h"
|
||||
|
||||
// memdbgon must be the last include file in a .cpp file!!!
|
||||
#include "tier0/memdbgon.h"
|
||||
|
||||
// forward declarations
|
||||
void ToolFramework_RecordMaterialParams( IMaterial *pMaterial );
|
||||
|
||||
// no inputs, assumes that the results go into $CHEAPWATERSTARTDISTANCE and $CHEAPWATERENDDISTANCE
|
||||
class CWaterLODMaterialProxy : public IMaterialProxy
|
||||
{
|
||||
public:
|
||||
CWaterLODMaterialProxy();
|
||||
virtual ~CWaterLODMaterialProxy();
|
||||
virtual bool Init( IMaterial *pMaterial, KeyValues *pKeyValues );
|
||||
virtual void OnBind( void *pC_BaseEntity );
|
||||
virtual void Release( void ) { delete this; }
|
||||
virtual IMaterial *GetMaterial();
|
||||
|
||||
private:
|
||||
IMaterialVar *m_pCheapWaterStartDistanceVar;
|
||||
IMaterialVar *m_pCheapWaterEndDistanceVar;
|
||||
};
|
||||
|
||||
CWaterLODMaterialProxy::CWaterLODMaterialProxy()
|
||||
{
|
||||
m_pCheapWaterStartDistanceVar = NULL;
|
||||
m_pCheapWaterEndDistanceVar = NULL;
|
||||
}
|
||||
|
||||
CWaterLODMaterialProxy::~CWaterLODMaterialProxy()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
bool CWaterLODMaterialProxy::Init( IMaterial *pMaterial, KeyValues *pKeyValues )
|
||||
{
|
||||
bool foundVar;
|
||||
m_pCheapWaterStartDistanceVar = pMaterial->FindVar( "$CHEAPWATERSTARTDISTANCE", &foundVar, false );
|
||||
if( !foundVar )
|
||||
return false;
|
||||
|
||||
m_pCheapWaterEndDistanceVar = pMaterial->FindVar( "$CHEAPWATERENDDISTANCE", &foundVar, false );
|
||||
if( !foundVar )
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void CWaterLODMaterialProxy::OnBind( void *pC_BaseEntity )
|
||||
{
|
||||
if( !m_pCheapWaterStartDistanceVar || !m_pCheapWaterEndDistanceVar )
|
||||
{
|
||||
return;
|
||||
}
|
||||
float start, end;
|
||||
view->GetWaterLODParams( start, end );
|
||||
m_pCheapWaterStartDistanceVar->SetFloatValue( start );
|
||||
m_pCheapWaterEndDistanceVar->SetFloatValue( end );
|
||||
|
||||
if ( ToolsEnabled() )
|
||||
{
|
||||
ToolFramework_RecordMaterialParams( GetMaterial() );
|
||||
}
|
||||
}
|
||||
|
||||
IMaterial *CWaterLODMaterialProxy::GetMaterial()
|
||||
{
|
||||
return m_pCheapWaterStartDistanceVar->GetOwningMaterial();
|
||||
}
|
||||
|
||||
EXPOSE_INTERFACE( CWaterLODMaterialProxy, IMaterialProxy, "WaterLOD" IMATERIAL_PROXY_INTERFACE_VERSION );
|
||||
@@ -0,0 +1,78 @@
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
//=============================================================================//
|
||||
|
||||
#include "cbase.h"
|
||||
#include "materialsystem/imaterialproxy.h"
|
||||
#include "materialsystem/imaterial.h"
|
||||
#include "materialsystem/imaterialvar.h"
|
||||
#include "c_world.h"
|
||||
#include "toolframework_client.h"
|
||||
|
||||
// memdbgon must be the last include file in a .cpp file!!!
|
||||
#include "tier0/memdbgon.h"
|
||||
|
||||
// forward declarations
|
||||
void ToolFramework_RecordMaterialParams( IMaterial *pMaterial );
|
||||
|
||||
class CWorldDimsProxy : public IMaterialProxy
|
||||
{
|
||||
public:
|
||||
CWorldDimsProxy();
|
||||
virtual ~CWorldDimsProxy();
|
||||
virtual bool Init( IMaterial *pMaterial, KeyValues *pKeyValues );
|
||||
virtual void OnBind( void *pC_BaseEntity );
|
||||
virtual void Release( void ) { delete this; }
|
||||
virtual IMaterial *GetMaterial();
|
||||
|
||||
|
||||
public:
|
||||
IMaterialVar *m_pMinsVar;
|
||||
IMaterialVar *m_pMaxsVar;
|
||||
};
|
||||
|
||||
|
||||
CWorldDimsProxy::CWorldDimsProxy()
|
||||
{
|
||||
m_pMinsVar = m_pMaxsVar = NULL;
|
||||
}
|
||||
|
||||
CWorldDimsProxy::~CWorldDimsProxy()
|
||||
{
|
||||
}
|
||||
|
||||
bool CWorldDimsProxy::Init( IMaterial *pMaterial, KeyValues *pKeyValues )
|
||||
{
|
||||
m_pMinsVar = pMaterial->FindVar( "$world_mins", NULL, false );
|
||||
m_pMaxsVar = pMaterial->FindVar( "$world_maxs", NULL, false );
|
||||
return true;
|
||||
}
|
||||
|
||||
void CWorldDimsProxy::OnBind( void *pC_BaseEntity )
|
||||
{
|
||||
if ( m_pMinsVar && m_pMaxsVar )
|
||||
{
|
||||
C_World *pWorld = GetClientWorldEntity();
|
||||
if ( pWorld )
|
||||
{
|
||||
m_pMinsVar->SetVecValue( (const float*)&pWorld->m_WorldMins, 3 );
|
||||
m_pMaxsVar->SetVecValue( (const float*)&pWorld->m_WorldMaxs, 3 );
|
||||
}
|
||||
}
|
||||
|
||||
if ( ToolsEnabled() )
|
||||
{
|
||||
ToolFramework_RecordMaterialParams( GetMaterial() );
|
||||
}
|
||||
}
|
||||
|
||||
IMaterial *CWorldDimsProxy::GetMaterial()
|
||||
{
|
||||
return m_pMinsVar->GetOwningMaterial();
|
||||
}
|
||||
|
||||
EXPOSE_INTERFACE( CWorldDimsProxy, IMaterialProxy, "WorldDims" IMATERIAL_PROXY_INTERFACE_VERSION );
|
||||
|
||||
|
||||
@@ -0,0 +1,720 @@
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose: Generic in-game abuse reporting
|
||||
//
|
||||
// $NoKeywords: $
|
||||
//=============================================================================//
|
||||
|
||||
#include "cbase.h"
|
||||
#include "abuse_report.h"
|
||||
#include "abuse_report_ui.h"
|
||||
#include "filesystem.h"
|
||||
#include "imageutils.h"
|
||||
#include "econ/confirm_dialog.h"
|
||||
#include "econ/econ_notifications.h"
|
||||
|
||||
inline bool IsLoggedOnToSteam()
|
||||
{
|
||||
return steamapicontext != NULL && steamapicontext->SteamUser() != NULL && steamapicontext->SteamUser()->BLoggedOn();
|
||||
}
|
||||
|
||||
const char CAbuseReportManager::k_rchScreenShotFilenameBase[] = "abuse_report";
|
||||
const char CAbuseReportManager::k_rchScreenShotFilename[] = "screenshots\\abuse_report.jpg";
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
class CEconNotification_AbuseReportReady : public CEconNotification
|
||||
{
|
||||
public:
|
||||
CEconNotification_AbuseReportReady() : CEconNotification()
|
||||
{
|
||||
m_bHasTriggered = false;
|
||||
m_bShowInGame = false;
|
||||
}
|
||||
|
||||
~CEconNotification_AbuseReportReady()
|
||||
{
|
||||
//if ( !m_bHasTriggered )
|
||||
//{
|
||||
// ReallyTrigger();
|
||||
//}
|
||||
}
|
||||
|
||||
virtual void MarkForDeletion()
|
||||
{
|
||||
m_bHasTriggered = true;
|
||||
|
||||
CEconNotification::MarkForDeletion();
|
||||
}
|
||||
|
||||
virtual bool BShowInGameElements() const { return m_bShowInGame; }
|
||||
virtual EType NotificationType() { return eType_Trigger; }
|
||||
virtual void Trigger()
|
||||
{
|
||||
ReallyTrigger();
|
||||
MarkForDeletion();
|
||||
}
|
||||
|
||||
virtual const char *GetUnlocalizedHelpText()
|
||||
{
|
||||
return "#AbuseReport_Notification_Help";
|
||||
}
|
||||
|
||||
static bool IsNotificationType( CEconNotification *pNotification ) { return dynamic_cast< CEconNotification_AbuseReportReady *>( pNotification ) != NULL; }
|
||||
static bool IsInGameNotificationType( CEconNotification *pNotification )
|
||||
{
|
||||
CEconNotification_AbuseReportReady *n = dynamic_cast< CEconNotification_AbuseReportReady *>( pNotification );
|
||||
return n != NULL && n->BShowInGameElements();
|
||||
}
|
||||
|
||||
bool m_bShowInGame;
|
||||
|
||||
private:
|
||||
|
||||
void ReallyTrigger()
|
||||
{
|
||||
Assert( !m_bHasTriggered );
|
||||
m_bHasTriggered = true;
|
||||
engine->ClientCmd_Unrestricted( "abuse_report_submit" );
|
||||
}
|
||||
|
||||
bool m_bHasTriggered;
|
||||
};
|
||||
|
||||
AbuseIncidentData_t::AbuseIncidentData_t()
|
||||
{
|
||||
m_nScreenShotWaitFrames = 5;
|
||||
}
|
||||
|
||||
AbuseIncidentData_t::~AbuseIncidentData_t()
|
||||
{
|
||||
}
|
||||
|
||||
bool AbuseIncidentData_t::Poll()
|
||||
{
|
||||
bool bReady = true;
|
||||
|
||||
// Poll player data
|
||||
for ( int i = 0 ; i < m_vecPlayers.Count() ; ++i )
|
||||
{
|
||||
|
||||
// Make sure sure Steam knows we want the Avatar
|
||||
PlayerData_t *p = &m_vecPlayers[i];
|
||||
if ( p->m_iSteamAvatarIndex < 0 )
|
||||
{
|
||||
if ( steamapicontext && steamapicontext->SteamUser() )
|
||||
{
|
||||
|
||||
p->m_iSteamAvatarIndex = steamapicontext->SteamFriends()->GetLargeFriendAvatar( p->m_steamID );
|
||||
if ( p->m_iSteamAvatarIndex < 0 )
|
||||
{
|
||||
bReady = false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
p->m_iSteamAvatarIndex = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Screenshot ready?
|
||||
if ( !m_bitmapScreenshot.IsValid() && m_nScreenShotWaitFrames > 0 )
|
||||
{
|
||||
--m_nScreenShotWaitFrames;
|
||||
|
||||
// Just load the whole file into a memory buffer
|
||||
char szFullPath[ MAX_PATH ] = "";
|
||||
if ( !g_pFullFileSystem->RelativePathToFullPath( CAbuseReportManager::k_rchScreenShotFilename, NULL, szFullPath, ARRAYSIZE(szFullPath) ) )
|
||||
{
|
||||
Assert( false ); // ???
|
||||
}
|
||||
|
||||
// Load it
|
||||
|
||||
if ( g_pFullFileSystem->FileExists( szFullPath ) )
|
||||
{
|
||||
|
||||
// Load the screenshot into a local buffer
|
||||
if ( !g_pFullFileSystem->ReadFile( CAbuseReportManager::k_rchScreenShotFilename, NULL, m_bufScreenshotFileData ) )
|
||||
{
|
||||
Warning( "Failed to read back %s\n", CAbuseReportManager::k_rchScreenShotFilename );
|
||||
m_nScreenShotWaitFrames = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
ConversionErrorType nErrorCode = ImgUtl_LoadBitmap( szFullPath, m_bitmapScreenshot );
|
||||
if ( nErrorCode != CE_SUCCESS )
|
||||
{
|
||||
Warning( "Abuse report screenshot %s failed to load with error code %d\n", CAbuseReportManager::k_rchScreenShotFilename, nErrorCode );
|
||||
Assert( nErrorCode == CE_SUCCESS );
|
||||
m_nScreenShotWaitFrames = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
// !KLUDGE! Resize to power of two dimensions, since VGUI doesn't like odd sizes
|
||||
ImgUtl_ResizeBitmap( m_bitmapScreenshot, 1024, 1024, &m_bitmapScreenshot );
|
||||
}
|
||||
}
|
||||
g_pFullFileSystem->RemoveFile( CAbuseReportManager::k_rchScreenShotFilename );
|
||||
}
|
||||
}
|
||||
|
||||
return bReady;
|
||||
}
|
||||
|
||||
CAbuseReportManager *g_AbuseReportMgr;
|
||||
|
||||
CAbuseReportManager::CAbuseReportManager()
|
||||
{
|
||||
m_pIncidentData = NULL;
|
||||
m_bTestReport = false;
|
||||
m_eIncidentDataStatus = k_EIncidentDataStatus_None;
|
||||
m_bReportUIPending = false;
|
||||
|
||||
// We're the singleton --- set global pointer
|
||||
Assert( g_AbuseReportMgr == NULL );
|
||||
g_AbuseReportMgr = this;
|
||||
m_timeLastReportReadyNotification = 0.0;
|
||||
m_adrCurrentServer.Clear();
|
||||
}
|
||||
|
||||
CAbuseReportManager::~CAbuseReportManager()
|
||||
{
|
||||
Assert( m_pIncidentData == NULL );
|
||||
}
|
||||
|
||||
char const *CAbuseReportManager::Name()
|
||||
{
|
||||
return "AbuseRepotManager";
|
||||
}
|
||||
|
||||
bool CAbuseReportManager::Init()
|
||||
{
|
||||
// Clean out any temporary files
|
||||
Assert( m_pIncidentData == NULL );
|
||||
DestroyIncidentData();
|
||||
|
||||
ListenForGameEvent( "teamplay_round_win" );
|
||||
ListenForGameEvent( "tf_game_over" );
|
||||
ListenForGameEvent( "player_death" );
|
||||
ListenForGameEvent( "server_spawn" );
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void CAbuseReportManager::LevelShutdownPreEntity()
|
||||
{
|
||||
|
||||
// Don't keep the dialog open across a level transition. Don't discard their
|
||||
// report data, but let's kill the dialog
|
||||
if ( g_AbuseReportDlg.Get() != NULL )
|
||||
{
|
||||
Warning( "Abuse report dialog open during level shutdown. Closing it.\n" );
|
||||
g_AbuseReportDlg.Get()->Close();
|
||||
}
|
||||
|
||||
// And clear the 'pending' flag
|
||||
m_bReportUIPending = false;
|
||||
}
|
||||
|
||||
void CAbuseReportManager::FireGameEvent( IGameEvent *event )
|
||||
{
|
||||
//C_BasePlayer *pLocalPlayer = C_BasePlayer::GetLocalPlayer();
|
||||
|
||||
const char *eventname = event->GetName();
|
||||
|
||||
if ( !eventname || !eventname[0] )
|
||||
return;
|
||||
|
||||
if (
|
||||
!Q_strcmp( "teamplay_round_win", eventname )
|
||||
|| !Q_strcmp( "tf_game_over", eventname )
|
||||
) {
|
||||
// Periodically remind them that they have a report ready to file
|
||||
CheckCreateReportReadyNotification( 60.0 * 5.0, true, 10.0f );
|
||||
}
|
||||
else if ( !Q_strcmp( "player_death", eventname ) )
|
||||
{
|
||||
// In some maps, the round just never ends.
|
||||
// So make sure we do remind them every now and then about this.
|
||||
// Just not too often
|
||||
CheckCreateReportReadyNotification( 60.0 * 20.0, true, 5.0f );
|
||||
}
|
||||
else if ( !Q_strcmp( "server_spawn", eventname ) )
|
||||
{
|
||||
m_adrCurrentServer.Clear();
|
||||
m_adrCurrentServer.SetFromString( event->GetString( "address", "" ), false );
|
||||
m_adrCurrentServer.SetPort( event->GetInt( "port", 0 ) );
|
||||
|
||||
m_steamIDCurrentServer = CSteamID();
|
||||
if ( steamapicontext && steamapicontext->SteamUser() && GetUniverse() != k_EUniverseInvalid )
|
||||
{
|
||||
m_steamIDCurrentServer.SetFromString( event->GetString( "steamid", "" ), GetUniverse() );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CAbuseReportManager::Shutdown()
|
||||
{
|
||||
// Close the dialog, if any
|
||||
LevelShutdownPreEntity();
|
||||
|
||||
DestroyIncidentData();
|
||||
|
||||
// Clear global pointer
|
||||
Assert( g_AbuseReportMgr == this );
|
||||
if ( g_AbuseReportMgr == this )
|
||||
{
|
||||
g_AbuseReportMgr = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
void CAbuseReportManager::Update( float frametime )
|
||||
{
|
||||
|
||||
// if a dialog is already displayed, make sure we don't try to activate another
|
||||
if ( g_AbuseReportDlg.Get() != NULL )
|
||||
{
|
||||
m_bReportUIPending = false;
|
||||
}
|
||||
|
||||
// Poll report data, if any
|
||||
if ( m_pIncidentData != NULL )
|
||||
{
|
||||
if ( m_eIncidentDataStatus == k_EIncidentDataStatus_Preparing )
|
||||
{
|
||||
if ( m_pIncidentData->Poll() )
|
||||
{
|
||||
m_eIncidentDataStatus = k_EIncidentDataStatus_Ready;
|
||||
CheckCreateReportReadyNotification( 1.0f, true, 7.0f );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Assert( m_eIncidentDataStatus == k_EIncidentDataStatus_Ready );
|
||||
}
|
||||
|
||||
if ( m_eIncidentDataStatus == k_EIncidentDataStatus_Ready && m_bReportUIPending )
|
||||
{
|
||||
m_bReportUIPending = false;
|
||||
ActivateSubmitReportUI();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
m_bReportUIPending = false;
|
||||
}
|
||||
|
||||
// Re-create notification constantly in the menu.
|
||||
// While in game, we will only popup notifications
|
||||
// periodically at round end or player death
|
||||
CheckCreateReportReadyNotification( 10.0, false, 999.0f );
|
||||
}
|
||||
|
||||
void CAbuseReportManager::SubmitReportUIRequested()
|
||||
{
|
||||
if ( g_AbuseReportDlg.Get() != NULL )
|
||||
{
|
||||
Assert( g_AbuseReportDlg.Get() == NULL );
|
||||
return;
|
||||
}
|
||||
|
||||
// If no report data already, then create some
|
||||
if ( m_pIncidentData == NULL )
|
||||
{
|
||||
QueueReport();
|
||||
if ( m_pIncidentData == NULL )
|
||||
{
|
||||
// Failed
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Set flag to bring up the reporting UI at earliest opportunity,
|
||||
// once all data has been fetched asynchronously
|
||||
m_bReportUIPending = true;
|
||||
}
|
||||
|
||||
bool CAbuseReportManager::CreateAndPopulateIncident()
|
||||
{
|
||||
Assert( m_pIncidentData == NULL );
|
||||
|
||||
// by default, just create the base class version
|
||||
m_pIncidentData = new AbuseIncidentData_t;
|
||||
|
||||
// And populate it
|
||||
return PopulateIncident();
|
||||
}
|
||||
|
||||
bool CAbuseReportManager::PopulateIncident()
|
||||
{
|
||||
if ( m_pIncidentData == NULL )
|
||||
{
|
||||
Assert( m_pIncidentData );
|
||||
return false;
|
||||
}
|
||||
|
||||
// Queue a screenshot
|
||||
CUtlString cmd;
|
||||
cmd.Format( "__screenshot_internal \"%s\"", k_rchScreenShotFilenameBase );
|
||||
engine->ClientCmd_Unrestricted( cmd );
|
||||
|
||||
// Set status as preparing
|
||||
m_eIncidentDataStatus = k_EIncidentDataStatus_Preparing;
|
||||
|
||||
m_pIncidentData->m_bCanReportGameServer = false;
|
||||
|
||||
m_pIncidentData->m_adrGameServer.Clear();
|
||||
if (
|
||||
m_adrCurrentServer.IsValid()
|
||||
&& !m_adrCurrentServer.IsLocalhost()
|
||||
&& m_steamIDCurrentServer.IsValid()
|
||||
&& ( !m_adrCurrentServer.IsReservedAdr() || m_steamIDCurrentServer.GetEUniverse() != k_EUniversePublic )
|
||||
)
|
||||
{
|
||||
m_pIncidentData->m_adrGameServer = m_adrCurrentServer;
|
||||
m_pIncidentData->m_steamIDGameServer = m_steamIDCurrentServer;
|
||||
m_pIncidentData->m_bCanReportGameServer = true;
|
||||
}
|
||||
|
||||
m_pIncidentData->m_matWorldToClip = engine->WorldToScreenMatrix();
|
||||
|
||||
// Add in players
|
||||
for (int i = 1 ; i <= gpGlobals->maxClients ; ++i )
|
||||
{
|
||||
CBasePlayer *player = UTIL_PlayerByIndex( i );
|
||||
|
||||
#ifndef _DEBUG
|
||||
// Skip local players
|
||||
if ( player != NULL && player->IsLocalPlayer() )
|
||||
{
|
||||
continue;
|
||||
}
|
||||
#endif
|
||||
|
||||
// Get player info from the engine. This works even if they haven't spawned yet.
|
||||
player_info_t pi;
|
||||
if ( !engine->GetPlayerInfo( i, &pi ) )
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if ( pi.fakeplayer )
|
||||
{
|
||||
continue;
|
||||
}
|
||||
if ( pi.friendsID == 0 )
|
||||
{
|
||||
continue;
|
||||
}
|
||||
CSteamID steamID( pi.friendsID, 1, GetUniverse(), k_EAccountTypeIndividual );
|
||||
if ( !steamID.IsValid() )
|
||||
{
|
||||
Assert( steamID.IsValid() );
|
||||
continue;
|
||||
}
|
||||
|
||||
int arrayIndex = m_pIncidentData->m_vecPlayers.AddToTail();
|
||||
AbuseIncidentData_t::PlayerData_t *p = &m_pIncidentData->m_vecPlayers[ arrayIndex ];
|
||||
|
||||
p->m_iClientIndex = i;
|
||||
p->m_steamID = steamID;
|
||||
p->m_sPersona = pi.name;
|
||||
p->m_bHasEntity = false;
|
||||
p->m_bRenderBoundsValid = false;
|
||||
p->m_screenBoundsMin.x = p->m_screenBoundsMin.y = 1.0f;
|
||||
p->m_screenBoundsMax.x = p->m_screenBoundsMax.y = 0.0f;
|
||||
|
||||
if ( player==NULL )
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
p->m_bHasEntity = true;
|
||||
player->GetRenderBounds( p->m_vecRenderBoundsMin, p->m_vecRenderBoundsMax );
|
||||
p->m_matModelToWorld.CopyFrom3x4( player->RenderableToWorldTransform() );
|
||||
MatrixMultiply( m_pIncidentData->m_matWorldToClip, p->m_matModelToWorld, p->m_matModelToClip );
|
||||
|
||||
// Gather up screen extents
|
||||
p->m_bRenderBoundsValid = false;
|
||||
for ( int j = 0 ; j < 8 ; ++j )
|
||||
{
|
||||
|
||||
// Get corner point in model space
|
||||
Vector4D modelCorner(
|
||||
( j & 1 ) ? p->m_vecRenderBoundsMax.x : p->m_vecRenderBoundsMin.x,
|
||||
( j & 2 ) ? p->m_vecRenderBoundsMax.y : p->m_vecRenderBoundsMin.y,
|
||||
( j & 4 ) ? p->m_vecRenderBoundsMax.z : p->m_vecRenderBoundsMin.z,
|
||||
1.0f
|
||||
);
|
||||
|
||||
// Transform to clip space
|
||||
Vector4D clipCorner;
|
||||
Vector4DMultiply( p->m_matModelToClip, modelCorner, clipCorner );
|
||||
|
||||
//Msg( "%6.3f, %6.3f, %6.3f, %6.3f\n", clipCorner[0], clipCorner[1], clipCorner[2], clipCorner[3] );
|
||||
|
||||
// If all points behind near clip plane, don't try to
|
||||
// figure out screen space bounds
|
||||
if ( clipCorner[3] > .1f )
|
||||
{
|
||||
p->m_bRenderBoundsValid = true;
|
||||
}
|
||||
|
||||
// Push w forward to "near clip plane"
|
||||
float w = MAX( clipCorner[3], .1f );
|
||||
|
||||
// Divide by w to project, and convert normalized device coordinates
|
||||
// where the view volume is (-1...1), to normalized screen coords, where
|
||||
// they are from 0...1
|
||||
float x = ( clipCorner[0] / w + 1.0f ) / 2.0f;
|
||||
float y = ( -clipCorner[1] / w + 1.0f ) / 2.0f;
|
||||
p->m_screenBoundsMin.x = MIN( p->m_screenBoundsMin.x, x );
|
||||
p->m_screenBoundsMax.x = MAX( p->m_screenBoundsMax.x, x );
|
||||
p->m_screenBoundsMin.y = MIN( p->m_screenBoundsMin.y, y );
|
||||
p->m_screenBoundsMax.y = MAX( p->m_screenBoundsMax.y, y );
|
||||
}
|
||||
|
||||
// Clip projected rect to the screen
|
||||
if ( p->m_bRenderBoundsValid )
|
||||
{
|
||||
p->m_screenBoundsMin.x = MAX( p->m_screenBoundsMin.x, 0.0f );
|
||||
p->m_screenBoundsMax.x = MIN( p->m_screenBoundsMax.x, 1.0f );
|
||||
p->m_screenBoundsMin.y = MAX( p->m_screenBoundsMin.y, 0.0f );
|
||||
p->m_screenBoundsMax.y = MIN( p->m_screenBoundsMax.y, 1.0f );
|
||||
|
||||
p->m_bRenderBoundsValid =
|
||||
p->m_screenBoundsMin.x + .01f < p->m_screenBoundsMax.x
|
||||
&& p->m_screenBoundsMin.y + .01f < p->m_screenBoundsMax.y;
|
||||
}
|
||||
|
||||
// Sanity check that we agree on what their steam ID is!
|
||||
if ( player->GetSteamID( &steamID ) )
|
||||
{
|
||||
Assert( p->m_steamID == steamID );
|
||||
}
|
||||
}
|
||||
|
||||
// Test harness: add in a handful of fake players
|
||||
#ifdef _DEBUG
|
||||
if ( m_bTestReport )
|
||||
{
|
||||
int arrayIndex = m_pIncidentData->m_vecPlayers.AddToTail();
|
||||
AbuseIncidentData_t::PlayerData_t *p = &m_pIncidentData->m_vecPlayers[ arrayIndex ];
|
||||
|
||||
p->m_iClientIndex = -1;
|
||||
p->m_sPersona = "Lippencott";
|
||||
p->m_steamID.SetFromUint64( 148618791998333672 );
|
||||
|
||||
arrayIndex = m_pIncidentData->m_vecPlayers.AddToTail();
|
||||
p = &m_pIncidentData->m_vecPlayers[ arrayIndex ];
|
||||
|
||||
p->m_iClientIndex = -1;
|
||||
p->m_sPersona = "EricS";
|
||||
p->m_steamID.SetFromUint64( 148618791998195668 );
|
||||
|
||||
arrayIndex = m_pIncidentData->m_vecPlayers.AddToTail();
|
||||
p = &m_pIncidentData->m_vecPlayers[ arrayIndex ];
|
||||
|
||||
p->m_iClientIndex = -1;
|
||||
p->m_sPersona = "Sarenya";
|
||||
p->m_steamID.SetFromUint64( 148618791998429832 );
|
||||
|
||||
arrayIndex = m_pIncidentData->m_vecPlayers.AddToTail();
|
||||
p = &m_pIncidentData->m_vecPlayers[ arrayIndex ];
|
||||
|
||||
|
||||
p->m_iClientIndex = -1;
|
||||
p->m_sPersona = "fletch";
|
||||
p->m_steamID.SetFromUint64( 148618791998436114 );
|
||||
{
|
||||
AbuseIncidentData_t::PlayerImage_t img;
|
||||
img.m_eType = AbuseIncidentData_t::k_PlayerImageType_UGC;
|
||||
img.m_hUGCHandle = 6978249415967519;
|
||||
p->m_vecImages.AddToTail( img );
|
||||
}
|
||||
|
||||
if ( !m_pIncidentData->m_bCanReportGameServer)
|
||||
{
|
||||
m_pIncidentData->m_adrGameServer.SetFromString( "123.45.67.89:27015", false );
|
||||
m_pIncidentData->m_steamIDGameServer = CSteamID( 12345, 0, GetUniverse(), k_EAccountTypeAnonGameServer );
|
||||
m_pIncidentData->m_bCanReportGameServer = true;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
// Make sure there is at least one other person we could file a report against!
|
||||
if ( m_pIncidentData->m_vecPlayers.Count() < 1 )
|
||||
{
|
||||
Warning( "No players to accuse of abuse, cannot file report\n" );
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void CAbuseReportManager::DestroyIncidentData()
|
||||
{
|
||||
if ( m_pIncidentData != NULL )
|
||||
{
|
||||
delete m_pIncidentData;
|
||||
m_pIncidentData = NULL;
|
||||
}
|
||||
m_eIncidentDataStatus = k_EIncidentDataStatus_None;
|
||||
|
||||
// Get rid of any existing screenshot file, both locally
|
||||
// and in the cloud. We don't want this to count against
|
||||
// our quota
|
||||
if ( steamapicontext && steamapicontext->SteamRemoteStorage() && steamapicontext->SteamRemoteStorage()->FileExists( k_rchScreenShotFilename ) )
|
||||
{
|
||||
steamapicontext->SteamRemoteStorage()->FileDelete( k_rchScreenShotFilename );
|
||||
}
|
||||
|
||||
if ( g_pFullFileSystem->FileExists( k_rchScreenShotFilename ) ) // !KLUDGE! To prevent warning if the file doesn't exist!
|
||||
{
|
||||
g_pFullFileSystem->RemoveFile( k_rchScreenShotFilename );
|
||||
}
|
||||
|
||||
m_timeLastReportReadyNotification = 0.0;
|
||||
|
||||
// Make sure we don't have any notifications queued
|
||||
NotificationQueue_Remove( &CEconNotification_AbuseReportReady::IsNotificationType );
|
||||
}
|
||||
|
||||
void CAbuseReportManager::QueueReport()
|
||||
{
|
||||
// Dialog is already active?
|
||||
if ( g_AbuseReportDlg.Get() != NULL )
|
||||
{
|
||||
Warning( "Cannot capture another incident report. Submission dialog is active.\n" );
|
||||
return;
|
||||
}
|
||||
|
||||
// Destroy any existing data
|
||||
DestroyIncidentData();
|
||||
|
||||
// Make sure we're logged on to Steam
|
||||
if ( !IsLoggedOnToSteam() )
|
||||
{
|
||||
g_AbuseReportMgr->ShowNoSteamErrorMessage();
|
||||
return;
|
||||
}
|
||||
|
||||
if ( CreateAndPopulateIncident() )
|
||||
{
|
||||
Msg( "Captured data for abuse report.\n");
|
||||
}
|
||||
else
|
||||
{
|
||||
Warning( "Failed to captured data for abuse report.\n");
|
||||
DestroyIncidentData();
|
||||
}
|
||||
}
|
||||
|
||||
void CAbuseReportManager::ShowNoSteamErrorMessage()
|
||||
{
|
||||
ShowMessageBox( "#AbuseReport_NoSteamTitle", "#AbuseReport_NoSteamMessage", "#GameUI_OK" );
|
||||
}
|
||||
|
||||
void CAbuseReportManager::CheckCreateReportReadyNotification( float flMinSecondsSinceLastNotification, bool bInGame, float flLifetime )
|
||||
{
|
||||
// We have to have some data ready
|
||||
if ( m_pIncidentData == NULL || m_eIncidentDataStatus != k_EIncidentDataStatus_Ready )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// Don't pester them if they are already trying to do something about it
|
||||
if ( g_AbuseReportDlg.Get() != NULL || m_bReportUIPending )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// Already notified them too recently?
|
||||
if ( m_timeLastReportReadyNotification != 0.0 && Plat_FloatTime() < m_timeLastReportReadyNotification + flMinSecondsSinceLastNotification )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// Already a notification in the queue?
|
||||
if ( bInGame )
|
||||
{
|
||||
if ( NotificationQueue_Count( &CEconNotification_AbuseReportReady::IsInGameNotificationType ) > 0 )
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if ( NotificationQueue_Count( &CEconNotification_AbuseReportReady::IsNotificationType ) > 0 )
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
CreateReportReadyNotification( bInGame, flLifetime );
|
||||
}
|
||||
|
||||
void CAbuseReportManager::CreateReportReadyNotification( bool bInGame, float flLifetime )
|
||||
{
|
||||
NotificationQueue_Remove( &CEconNotification_AbuseReportReady::IsNotificationType );
|
||||
CEconNotification_AbuseReportReady *pNotification = new CEconNotification_AbuseReportReady();
|
||||
pNotification->SetText( "AbuseReport_Notification" );
|
||||
pNotification->SetLifetime( flLifetime );
|
||||
pNotification->m_bShowInGame = bInGame;
|
||||
NotificationQueue_Add( pNotification );
|
||||
|
||||
m_timeLastReportReadyNotification = Plat_FloatTime();
|
||||
}
|
||||
|
||||
CON_COMMAND_F( abuse_report_queue, "Capture data for abuse report and queue for submission. Use abose_report_submit to activate UI to submit the report", FCVAR_DONTRECORD )
|
||||
{
|
||||
if ( !g_AbuseReportMgr )
|
||||
{
|
||||
Warning( "abuse_report_queue: No abuse report manager, cannot create report.\n" );
|
||||
return;
|
||||
}
|
||||
|
||||
g_AbuseReportMgr->QueueReport();
|
||||
}
|
||||
|
||||
CON_COMMAND_F( abuse_report_submit, "Activate UI to submit queued report. Use abuse_report_queue to capture data for the report the report", FCVAR_DONTRECORD )
|
||||
{
|
||||
if ( !g_AbuseReportMgr )
|
||||
{
|
||||
Warning( "abuse_report_submit: No abuse report manager, cannot submit report.\n" );
|
||||
return;
|
||||
}
|
||||
|
||||
// Make sure we're logged on to Steam
|
||||
if ( !IsLoggedOnToSteam() )
|
||||
{
|
||||
g_AbuseReportMgr->ShowNoSteamErrorMessage();
|
||||
return;
|
||||
}
|
||||
|
||||
if ( g_AbuseReportDlg.Get() != NULL )
|
||||
{
|
||||
// Dialog is already active
|
||||
return;
|
||||
}
|
||||
g_AbuseReportMgr->SubmitReportUIRequested();
|
||||
}
|
||||
|
||||
// Test harness
|
||||
#ifdef _DEBUG
|
||||
|
||||
CON_COMMAND_F( abuse_report_test, "Make a test abuse incident and activate UI", FCVAR_DONTRECORD )
|
||||
{
|
||||
if ( !g_AbuseReportMgr )
|
||||
{
|
||||
Assert( g_AbuseReportMgr );
|
||||
return;
|
||||
}
|
||||
g_AbuseReportMgr->m_bTestReport = true;
|
||||
g_AbuseReportMgr->QueueReport();
|
||||
g_AbuseReportMgr->m_bTestReport = false;
|
||||
engine->ClientCmd_Unrestricted( "abuse_report_submit" );
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,274 @@
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose: Generic in-game abuse reporting
|
||||
//
|
||||
// $NoKeywords: $
|
||||
//=============================================================================//
|
||||
|
||||
#ifndef ABUSE_REPORT_H
|
||||
#define ABUSE_REPORT_H
|
||||
#ifdef _WIN32
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
#include <igamesystem.h>
|
||||
#include <GameEventListener.h>
|
||||
#include <bitmap/bitmap.h>
|
||||
#include <netadr.h>
|
||||
|
||||
/// Different content types that can be reported as abusive.
|
||||
///
|
||||
/// WARNING: These enum values MUST MATCH the values in Steam's
|
||||
/// ECommunityContentType!
|
||||
enum EAbuseReportContentType
|
||||
{
|
||||
k_EAbuseReportContentNoSelection = -1, // dummy ilegal value: the user has not made a selection
|
||||
k_EAbuseReportContentUnspecified = 0, // we use this to mean "other"
|
||||
//k_EAbuseReportContentAll = 1, // reset all community content
|
||||
k_EAbuseReportContentAvatarImage = 2, // clear avatar image
|
||||
//k_EAbuseReportContentProfileText = 3, // reset profile text
|
||||
//k_EAbuseReportContentWebLinks = 4, // delete web links
|
||||
//k_EAbuseReportContentAnnouncement = 5,
|
||||
//k_EAbuseReportContentEventText = 6,
|
||||
//k_EAbuseReportContentCustomCSS = 7,
|
||||
//k_EAbuseReportContentProfileURL = 8, // delete community URL ID
|
||||
k_EAbuseReportContentComments = 9, // just comments this guy has written
|
||||
k_EAbuseReportContentPersonaName = 10, // persona name
|
||||
//k_EAbuseReportContentScreenshot = 11, // screenshot
|
||||
//k_EAbuseReportContentVideo = 12, // videos
|
||||
k_EAbuseReportContentCheating = 13, // cheating
|
||||
k_EAbuseReportContentUGCImage = 14, // Image stored in UGC --- the report is accusing the image of being offensive
|
||||
k_EAbuseReportContentActorUGCImage = 15, // Abuse report actor has uploaded a UGC image to server as supporting documentation of their claim
|
||||
};
|
||||
|
||||
|
||||
/// Types of reasons why a violation report was issued
|
||||
///
|
||||
/// WARNING: These enum values MUST MATCH the values in Steam's
|
||||
/// EAbuseReportType!
|
||||
enum EAbuseReportType
|
||||
{
|
||||
k_EAbuseReportTypeNoSelection = -1, // dummy ilegal value: the user has not made a selection
|
||||
k_EAbuseReportTypeUnspecified = 0,
|
||||
k_EAbuseReportTypeInappropriate = 1, // just not ok to post
|
||||
k_EAbuseReportTypeProhibited = 2, // prohibited by EULA or general law
|
||||
k_EAbuseReportTypeSpamming = 3, // excessive spamming
|
||||
k_EAbuseReportTypeAdvertisement = 4, // unwanted advertisement
|
||||
//k_EAbuseReportTypeExploit = 5, // content data attempts to exploit code issue
|
||||
k_EAbuseReportTypeSpoofing = 6, // user/group is impersonating an official contact
|
||||
k_EAbuseReportTypeLanguage = 7, // bad language
|
||||
k_EAbuseReportTypeAdultContent = 8, // any kind of adult material, references etc
|
||||
k_EAbuseReportTypeHarassment = 9, // harassment, discrimination, racism etc
|
||||
k_EAbuseReportTypeCheating = 10, // cheating
|
||||
};
|
||||
|
||||
/// Container class that has everything we need to know in order to file
|
||||
/// an abuse report, which is significantly more than the data we actually
|
||||
/// include in a particular abuse report. It's everything we save off at the
|
||||
/// time the user initiates the abuse reporting mechanism. Games can derive
|
||||
/// their own report types and put game-specific data in here.
|
||||
struct AbuseIncidentData_t
|
||||
{
|
||||
AbuseIncidentData_t();
|
||||
virtual ~AbuseIncidentData_t();
|
||||
|
||||
enum EPlayerImageType
|
||||
{
|
||||
k_PlayerImageType_UGC,
|
||||
k_PlayerImageType_Spray,
|
||||
};
|
||||
|
||||
/// A custom image of the player's that could be considered offensive
|
||||
struct PlayerImage_t
|
||||
{
|
||||
|
||||
/// What kind of image is it?
|
||||
EPlayerImageType m_eType;
|
||||
|
||||
/// For UGC images, what's the handle?
|
||||
uint64 m_hUGCHandle;
|
||||
};
|
||||
|
||||
/// Info we remember for one player.
|
||||
struct PlayerData_t
|
||||
{
|
||||
PlayerData_t()
|
||||
{
|
||||
m_iClientIndex = -1;
|
||||
m_iSteamAvatarIndex = -1;
|
||||
}
|
||||
|
||||
/// The client index. (See UTIL_PlayerByIndex). Note that this
|
||||
/// index is really only valid at the time the incident is captured.
|
||||
/// Because players can leave after the incident is captured.
|
||||
int m_iClientIndex;
|
||||
|
||||
/// The name they were going by at the time
|
||||
CUtlString m_sPersona;
|
||||
|
||||
/// Their steam ID. This is essential so we can file
|
||||
/// an abuse report!
|
||||
CSteamID m_steamID;
|
||||
|
||||
/// Index of steam friends icon for their avatar.
|
||||
/// 0 if they don't have one!
|
||||
int m_iSteamAvatarIndex;
|
||||
|
||||
/// Do we have an entity for this player? They might not have spawned,
|
||||
/// or might be outside our PVS, etc.
|
||||
bool m_bHasEntity;
|
||||
|
||||
/// Model transform for the player's render stuff
|
||||
VMatrix m_matModelToWorld;
|
||||
|
||||
/// Model->clip matrix for the player's render stuff
|
||||
VMatrix m_matModelToClip;
|
||||
|
||||
/// True if the render bounds are approximately correct, false if not
|
||||
bool m_bRenderBoundsValid;
|
||||
|
||||
/// Bounds (in model space) of the player's renderable stuff
|
||||
Vector m_vecRenderBoundsMin, m_vecRenderBoundsMax;
|
||||
|
||||
/// Bounds (in normalized screen space coords 0...1) of the player's
|
||||
/// renderable stuff
|
||||
Vector2D m_screenBoundsMin, m_screenBoundsMax;
|
||||
|
||||
/// List of his images
|
||||
CUtlVector<PlayerImage_t> m_vecImages;
|
||||
};
|
||||
|
||||
/// List of base player data. You got more data per player in your derived
|
||||
/// incident type? Store it in a parallel array.
|
||||
CUtlVector<PlayerData_t> m_vecPlayers;
|
||||
|
||||
/// Camera world -> clip matrix.
|
||||
VMatrix m_matWorldToClip;
|
||||
|
||||
/// Screenshot
|
||||
Bitmap_t m_bitmapScreenshot;
|
||||
|
||||
// Screenshot file data
|
||||
CUtlBuffer m_bufScreenshotFileData;
|
||||
|
||||
/// Number of frames we're willing to wait for the engine to write out a screenshot.
|
||||
/// Zero if we already failed
|
||||
int m_nScreenShotWaitFrames;
|
||||
|
||||
/// Is it possible to report the game server itself for abuse?
|
||||
bool m_bCanReportGameServer;
|
||||
|
||||
/// What Game Server/IP are we on? Will be an invalid address if we don't know
|
||||
netadr_t m_adrGameServer;
|
||||
|
||||
/// Steam ID of the game server / IP we are on
|
||||
CSteamID m_steamIDGameServer;
|
||||
|
||||
/// Poll report (some data may have to be fetched asynchronously),
|
||||
/// return true if everything is ready
|
||||
virtual bool Poll();
|
||||
};
|
||||
|
||||
/// Generic abuse reporting panel. Your
|
||||
class CAbuseReportManager : public CBaseGameSystemPerFrame, public CGameEventListener
|
||||
{
|
||||
public:
|
||||
CAbuseReportManager();
|
||||
virtual ~CAbuseReportManager();
|
||||
|
||||
//
|
||||
// CAutoGameSystemPerFrame overrides
|
||||
//
|
||||
virtual char const *Name();
|
||||
virtual bool Init();
|
||||
virtual void Shutdown();
|
||||
virtual void LevelShutdownPreEntity();
|
||||
|
||||
//
|
||||
// CGameEventListener overrides
|
||||
//
|
||||
virtual void FireGameEvent( IGameEvent *event );
|
||||
|
||||
// CAutoGameSystemPerFrame defines different stuff depending on which DLL we're building
|
||||
#ifdef CLIENT_DLL
|
||||
|
||||
// Do our frame-time processing
|
||||
virtual void Update( float frametime );
|
||||
|
||||
#else
|
||||
#error "Why is this being included?"
|
||||
#endif
|
||||
|
||||
/// Called when the console command is executed to capture data for a report
|
||||
virtual void QueueReport();
|
||||
|
||||
/// Called when the console command is executed to submit data for a report
|
||||
virtual void SubmitReportUIRequested();
|
||||
|
||||
/// Called to actually trigger the report UI, after all data is ready
|
||||
virtual void ActivateSubmitReportUI() = 0;
|
||||
|
||||
/// Fetch the incident that's queued to be reported
|
||||
AbuseIncidentData_t *GetIncidentData() const { return m_pIncidentData; }
|
||||
|
||||
/// Delete any current report incident. Also should clean
|
||||
/// out any temporary files used by the incident system.
|
||||
virtual void DestroyIncidentData();
|
||||
|
||||
/// Show a message box complaining about lack of steam
|
||||
/// connection
|
||||
virtual void ShowNoSteamErrorMessage();
|
||||
|
||||
/// Insert a a notification into the queue indicating that an unfiled report is ready
|
||||
virtual void CreateReportReadyNotification( bool bInGame, float flLifetime );
|
||||
|
||||
/// Test harness. Set this to true, to generate fake data
|
||||
bool m_bTestReport;
|
||||
|
||||
static const char k_rchScreenShotFilenameBase[];
|
||||
static const char k_rchScreenShotFilename[];
|
||||
|
||||
protected:
|
||||
|
||||
/// Your app will probably define its own abuse report types.
|
||||
/// if so, you will need to override this function.
|
||||
/// The base class just calls new to create an object, then calls
|
||||
/// PopulateIncident()
|
||||
virtual bool CreateAndPopulateIncident();
|
||||
|
||||
/// Fill in the details about the current incident. This just fills in the
|
||||
/// base class data, and it should be called from CreateAndPopulateIncident
|
||||
bool PopulateIncident();
|
||||
|
||||
/// Current incident that is pending to be reported or is being generated.
|
||||
/// Might be NULL.
|
||||
AbuseIncidentData_t *m_pIncidentData;
|
||||
|
||||
/// Status of incident data.
|
||||
enum EIncidentDataStatus
|
||||
{
|
||||
k_EIncidentDataStatus_None,
|
||||
k_EIncidentDataStatus_Preparing, // we shuld call Poll() until it's ready
|
||||
k_EIncidentDataStatus_Ready, // it's ready
|
||||
};
|
||||
EIncidentDataStatus m_eIncidentDataStatus;
|
||||
|
||||
/// Do we want to show the report UI as soon as the report is ready?
|
||||
bool m_bReportUIPending;
|
||||
|
||||
void CheckCreateReportReadyNotification( float flMinSecondsSinceLastNotification, bool bInGame, float flLifetime );
|
||||
|
||||
/// Time when we last pestered them about filing their report
|
||||
double m_timeLastReportReadyNotification;
|
||||
|
||||
/// Address of the lasts server we connected to
|
||||
netadr_t m_adrCurrentServer;
|
||||
CSteamID m_steamIDCurrentServer;
|
||||
|
||||
};
|
||||
|
||||
/// Pointer to the app-specific instance. This pointer mght be NULL! Your
|
||||
/// app should define set this pointer if it uses the system
|
||||
extern CAbuseReportManager *g_AbuseReportMgr;
|
||||
|
||||
#endif // ABUSE_REPORT_H
|
||||
@@ -0,0 +1,949 @@
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose: Generic in-game abuse reporting
|
||||
//
|
||||
// $NoKeywords: $
|
||||
//=============================================================================//
|
||||
|
||||
#include "cbase.h"
|
||||
#include "abuse_report_ui.h"
|
||||
#include "econ/econ_controls.h"
|
||||
#include "ienginevgui.h"
|
||||
#include "vgui/ISurface.h"
|
||||
#include <vgui_controls/TextEntry.h>
|
||||
#include <vgui_controls/ComboBox.h>
|
||||
#include <vgui_controls/RadioButton.h>
|
||||
#include "vgui_bitmappanel.h"
|
||||
#include "vgui_avatarimage.h"
|
||||
#include "gc_clientsystem.h"
|
||||
#include "econ/tool_items/tool_items.h"
|
||||
#include "econ/econ_gcmessages.h"
|
||||
#include "econ/confirm_dialog.h"
|
||||
#include "tool_items/custom_texture_cache.h"
|
||||
|
||||
vgui::DHANDLE<CAbuseReportDlg> g_AbuseReportDlg;
|
||||
|
||||
CAbuseReportDlg::CAbuseReportDlg( vgui::Panel *parent, AbuseIncidentData_t *pIncidentData )
|
||||
: EditablePanel( parent, "AbuseReportSubmitDialog" )
|
||||
, m_pSubmitButton( NULL )
|
||||
, m_pScreenShot( NULL )
|
||||
, m_pScreenShotAttachCheckButton( NULL )
|
||||
, m_pOffensiveImage( NULL )
|
||||
, m_pDescriptionTextEntry( NULL )
|
||||
, m_pPlayerLabel( NULL )
|
||||
, m_pPlayerRadio( NULL )
|
||||
, m_pGameServerRadio( NULL )
|
||||
, m_pPlayerCombo( NULL )
|
||||
, m_pAbuseContentLabel( NULL )
|
||||
, m_pAbuseContentCombo( NULL )
|
||||
, m_pAbuseTypeLabel( NULL )
|
||||
, m_pAbuseTypeCombo( NULL )
|
||||
, m_pScreenShotBitmap( NULL )
|
||||
, m_pAvatarImage( NULL )
|
||||
, m_pNoAvatarLabel( NULL )
|
||||
, m_pCustomTextureImagePanel( NULL )
|
||||
, m_pNoCustomTexturesLabel( NULL )
|
||||
, m_pCustomTextureNextButton( NULL )
|
||||
, m_pCustomTexturePrevButton( NULL )
|
||||
, m_iUserImageIndex( 0 )
|
||||
, m_pIncidentData( pIncidentData )
|
||||
{
|
||||
vgui::HScheme scheme = vgui::scheme()->LoadSchemeFromFileEx( enginevgui->GetPanel( PANEL_CLIENTDLL ), "resource/ClientScheme.res", "ClientScheme" );
|
||||
SetScheme(scheme);
|
||||
SetProportional( true );
|
||||
//m_pContainer = new vgui::EditablePanel( this, "Container" );
|
||||
|
||||
Assert( g_AbuseReportDlg.Get() == NULL );
|
||||
g_AbuseReportDlg.Set( this );
|
||||
|
||||
engine->ExecuteClientCmd("gameui_preventescape");
|
||||
}
|
||||
|
||||
CAbuseReportDlg::~CAbuseReportDlg()
|
||||
{
|
||||
Assert( g_AbuseReportDlg.Get() == this );
|
||||
if ( g_AbuseReportDlg.Get() == this )
|
||||
{
|
||||
engine->ExecuteClientCmd("gameui_allowescape");
|
||||
g_AbuseReportDlg = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
void CAbuseReportDlg::OnCommand( const char *command )
|
||||
{
|
||||
if ( !Q_stricmp( command, "cancel" ) )
|
||||
{
|
||||
Close();
|
||||
return;
|
||||
}
|
||||
if ( !Q_stricmp( command, "discard" ) )
|
||||
{
|
||||
Close();
|
||||
g_AbuseReportMgr->DestroyIncidentData();
|
||||
return;
|
||||
}
|
||||
if ( !Q_stricmp( command, "submit" ) )
|
||||
{
|
||||
OnSubmitReport();
|
||||
return;
|
||||
}
|
||||
if ( !Q_stricmp( command, "nextcustomtexture" ) )
|
||||
{
|
||||
++m_iUserImageIndex;
|
||||
UpdateCustomTextures();
|
||||
return;
|
||||
}
|
||||
|
||||
if ( !Q_stricmp( command, "prevcustomtexture" ) )
|
||||
{
|
||||
--m_iUserImageIndex;
|
||||
UpdateCustomTextures();
|
||||
return;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void CAbuseReportDlg::MakeModal()
|
||||
{
|
||||
TFModalStack()->PushModal( this );
|
||||
MakePopup();
|
||||
MoveToFront();
|
||||
SetKeyBoardInputEnabled( true );
|
||||
SetMouseInputEnabled( true );
|
||||
|
||||
// !KLUDGE! Initially set the dialog to be hidden, so we can take a screenshot!
|
||||
SetEnabled( m_pIncidentData != NULL );
|
||||
//SetVisible( m_pIncidentData != NULL );
|
||||
}
|
||||
|
||||
void CAbuseReportDlg::Close()
|
||||
{
|
||||
TFModalStack()->PopModal( this );
|
||||
SetVisible( false );
|
||||
MarkForDeletion();
|
||||
}
|
||||
|
||||
const char *CAbuseReportDlg::GetResFilename()
|
||||
{
|
||||
return "Resource/UI/AbuseReportSubmitDialog.res";
|
||||
//return "Resource/UI/QuickplayDialog.res";
|
||||
}
|
||||
|
||||
void CAbuseReportDlg::PerformLayout()
|
||||
{
|
||||
BaseClass::PerformLayout();
|
||||
|
||||
// Center it, keeping requested size
|
||||
int x, y, ww, wt, wide, tall;
|
||||
vgui::surface()->GetWorkspaceBounds( x, y, ww, wt );
|
||||
GetSize(wide, tall);
|
||||
SetPos(x + ((ww - wide) / 2), y + ((wt - tall) / 2));
|
||||
|
||||
// @todo setup
|
||||
}
|
||||
|
||||
class CCustomTextureImagePanel : public vgui::Panel
|
||||
{
|
||||
public:
|
||||
CCustomTextureImagePanel( Panel *parent, const char *panelName ) : vgui::Panel( parent, panelName )
|
||||
{
|
||||
m_ugcHandle = 0;
|
||||
}
|
||||
|
||||
uint64 m_ugcHandle;
|
||||
|
||||
virtual void Paint()
|
||||
{
|
||||
if ( m_ugcHandle == 0 )
|
||||
{
|
||||
return;
|
||||
}
|
||||
int iTextureHandle = GetCustomTextureGuiHandle( m_ugcHandle );
|
||||
if ( iTextureHandle <= 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
vgui::surface()->DrawSetColor(COLOR_WHITE);
|
||||
vgui::surface()->DrawSetTexture( iTextureHandle );
|
||||
int iWide, iTall;
|
||||
GetSize( iWide, iTall );
|
||||
|
||||
vgui::Vertex_t verts[4];
|
||||
verts[0].Init( Vector2D( 0, 0 ), Vector2D( 0.0f, 0.0f ) );
|
||||
verts[1].Init( Vector2D( iWide, 0 ), Vector2D( 1.0f, 0.0f ) );
|
||||
verts[2].Init( Vector2D( iWide, iTall ), Vector2D( 1.0f, 1.0f ) );
|
||||
verts[3].Init( Vector2D( 0, iTall ), Vector2D( 0.0f, 1.0f ) );
|
||||
|
||||
vgui::surface()->DrawTexturedPolygon( 4, verts );
|
||||
vgui::surface()->DrawSetColor(COLOR_WHITE);
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
class CAbuseReportScreenShotPanel : public CBitmapPanel
|
||||
{
|
||||
public:
|
||||
CAbuseReportScreenShotPanel( CAbuseReportDlg *pDlg, const char *panelName )
|
||||
: CBitmapPanel( pDlg, panelName )
|
||||
, m_pDlg( pDlg )
|
||||
{}
|
||||
|
||||
CAbuseReportDlg *m_pDlg;
|
||||
|
||||
virtual void Paint()
|
||||
{
|
||||
CBitmapPanel::Paint();
|
||||
|
||||
const AbuseIncidentData_t::PlayerData_t *p = m_pDlg->GetAccusedPlayerPtr();
|
||||
if ( p == NULL || !p->m_bRenderBoundsValid )
|
||||
{
|
||||
return;
|
||||
}
|
||||
int w, t;
|
||||
GetSize( w, t );
|
||||
|
||||
int x0 = int( p->m_screenBoundsMin.x * (float)w );
|
||||
int y0 = int( p->m_screenBoundsMin.y * (float)t );
|
||||
int x1 = int( p->m_screenBoundsMax.x * (float)w );
|
||||
int y1 = int( p->m_screenBoundsMax.y * (float)t );
|
||||
|
||||
vgui::surface()->DrawSetColor( Color(200, 10, 10, 200 ) );
|
||||
vgui::surface()->DrawOutlinedRect( x0, y0, x1, y1 );
|
||||
vgui::surface()->DrawSetColor( COLOR_WHITE );
|
||||
}
|
||||
};
|
||||
|
||||
void CAbuseReportDlg::ApplySchemeSettings( vgui::IScheme *pScheme )
|
||||
{
|
||||
EditablePanel::ApplySchemeSettings( pScheme );
|
||||
|
||||
m_pScreenShotBitmap = new CAbuseReportScreenShotPanel( this, "ScreenShotBitmap" );
|
||||
m_pCustomTextureImagePanel = new CCustomTextureImagePanel( this, "CustomTextureImage" );
|
||||
|
||||
LoadControlSettings( GetResFilename() );
|
||||
|
||||
m_pPlayerRadio = dynamic_cast<vgui::RadioButton *>(FindChildByName( "PlayerRadio", true ));
|
||||
Assert( m_pPlayerRadio );
|
||||
if ( m_pPlayerRadio )
|
||||
{
|
||||
m_pPlayerRadio->SetVisible( m_pIncidentData->m_bCanReportGameServer );
|
||||
}
|
||||
|
||||
m_pGameServerRadio = dynamic_cast<vgui::RadioButton *>(FindChildByName( "GameServerRadio", true ));
|
||||
Assert( m_pGameServerRadio );
|
||||
if ( m_pGameServerRadio )
|
||||
{
|
||||
m_pGameServerRadio->SetVisible( m_pIncidentData->m_bCanReportGameServer );
|
||||
}
|
||||
|
||||
m_pPlayerLabel = FindChildByName( "PlayerLabel", true );
|
||||
Assert( m_pPlayerLabel );
|
||||
|
||||
m_pScreenShotAttachCheckButton = dynamic_cast<vgui::CheckButton *>(FindChildByName( "ScreenShotAttachCheckButton", true ));
|
||||
Assert( m_pScreenShotAttachCheckButton );
|
||||
if ( m_pScreenShotAttachCheckButton )
|
||||
{
|
||||
m_pScreenShotAttachCheckButton->SetSelected( true );
|
||||
}
|
||||
|
||||
m_pSubmitButton = dynamic_cast<vgui::Button *>(FindChildByName( "SubmitButton", true ));
|
||||
Assert( m_pSubmitButton );
|
||||
|
||||
m_pDescriptionTextEntry = dynamic_cast<vgui::TextEntry *>(FindChildByName( "DescriptionTextEntry", true ));
|
||||
Assert( m_pDescriptionTextEntry );
|
||||
if ( m_pDescriptionTextEntry )
|
||||
{
|
||||
m_pDescriptionTextEntry->SetMultiline( true );
|
||||
}
|
||||
|
||||
m_pAvatarImage = dynamic_cast<CAvatarImagePanel *>(FindChildByName( "AvatarImage", true ));
|
||||
Assert( m_pAvatarImage );
|
||||
|
||||
m_pNoAvatarLabel = FindChildByName( "NoAvatarLabel", true );
|
||||
Assert( m_pNoAvatarLabel );
|
||||
|
||||
m_pNoCustomTexturesLabel = FindChildByName( "NoCustomTexturesLabel", true );
|
||||
Assert( m_pNoCustomTexturesLabel );
|
||||
|
||||
m_pCustomTextureNextButton = dynamic_cast<vgui::Button *>(FindChildByName( "CustomTextureNextButton", true ));
|
||||
Assert( m_pCustomTextureNextButton );
|
||||
|
||||
m_pCustomTexturePrevButton = dynamic_cast<vgui::Button *>(FindChildByName( "CustomTexturePrevButton", true ));
|
||||
Assert( m_pCustomTexturePrevButton );
|
||||
|
||||
m_pPlayerCombo = dynamic_cast<vgui::ComboBox *>(FindChildByName( "PlayerComboBox", true ));
|
||||
Assert( m_pPlayerCombo );
|
||||
|
||||
m_pAbuseContentLabel = FindChildByName( "AbuseContentLabel", true );
|
||||
Assert( m_pAbuseContentLabel );
|
||||
|
||||
m_pAbuseContentCombo = dynamic_cast<vgui::ComboBox *>(FindChildByName( "AbuseContentComboBox", true ));
|
||||
Assert( m_pAbuseContentCombo );
|
||||
if ( m_pAbuseContentCombo )
|
||||
{
|
||||
m_pAbuseContentCombo->AddItem( "#AbuseReport_SelectOne", new KeyValues( "AbuseContent", "code", k_EAbuseReportContentNoSelection ) );
|
||||
m_pAbuseContentCombo->AddItem( "#AbuseReport_ContentAvatarImage", new KeyValues( "AbuseContent", "code", k_EAbuseReportContentAvatarImage ) );
|
||||
m_pAbuseContentCombo->AddItem( "#AbuseReport_ContentPlayerName", new KeyValues( "AbuseContent", "code", k_EAbuseReportContentPersonaName ) );
|
||||
m_pAbuseContentCombo->AddItem( "#AbuseReport_ContentItemDecal", new KeyValues( "AbuseContent", "code", k_EAbuseReportContentUGCImage ) );
|
||||
m_pAbuseContentCombo->AddItem( "#AbuseReport_ContentChatText", new KeyValues( "AbuseContent", "code", k_EAbuseReportContentComments ) );
|
||||
m_pAbuseContentCombo->AddItem( "#AbuseReport_ContentCheating", new KeyValues( "AbuseContent", "code", k_EAbuseReportContentCheating ) );
|
||||
m_pAbuseContentCombo->AddItem( "#AbuseReport_ContentOther", new KeyValues( "AbuseContent", "code", k_EAbuseReportContentUnspecified ) );
|
||||
m_pAbuseContentCombo->SilentActivateItemByRow( 0 );
|
||||
m_pAbuseContentCombo->SetNumberOfEditLines( m_pAbuseContentCombo->GetItemCount() );
|
||||
}
|
||||
|
||||
m_pAbuseTypeLabel = FindChildByName( "AbuseTypeLabel", true );
|
||||
Assert( m_pAbuseTypeLabel );
|
||||
|
||||
m_pAbuseTypeCombo = dynamic_cast<vgui::ComboBox *>(FindChildByName( "AbuseTypeComboBox", true ));
|
||||
Assert( m_pAbuseTypeCombo );
|
||||
|
||||
Assert( m_pScreenShotBitmap );
|
||||
if ( m_pScreenShotBitmap && m_pIncidentData->m_bitmapScreenshot.IsValid() )
|
||||
{
|
||||
m_pScreenShotBitmap->SetBitmap( m_pIncidentData->m_bitmapScreenshot );
|
||||
}
|
||||
|
||||
PopulatePlayerList();
|
||||
SetIsAccusingGameServer( false );
|
||||
|
||||
SetEnabled( true );
|
||||
SetVisible( true );
|
||||
}
|
||||
|
||||
bool CAbuseReportDlg::IsAccusingGameServer()
|
||||
{
|
||||
return m_pIncidentData && m_pIncidentData->m_bCanReportGameServer && m_pGameServerRadio && m_pGameServerRadio->IsSelected();
|
||||
}
|
||||
|
||||
EAbuseReportContentType CAbuseReportDlg::GetAbuseContentType()
|
||||
{
|
||||
if ( m_pAbuseContentCombo == NULL || IsAccusingGameServer() )
|
||||
{
|
||||
Assert( m_pAbuseContentCombo );
|
||||
return k_EAbuseReportContentNoSelection;
|
||||
}
|
||||
KeyValues *pUserData = m_pAbuseContentCombo->GetActiveItemUserData();
|
||||
if ( pUserData == NULL )
|
||||
{
|
||||
return k_EAbuseReportContentNoSelection;
|
||||
}
|
||||
return (EAbuseReportContentType)pUserData->GetInt( "code", k_EAbuseReportContentNoSelection );
|
||||
}
|
||||
|
||||
EAbuseReportType CAbuseReportDlg::GetAbuseType()
|
||||
{
|
||||
if ( m_pAbuseTypeCombo == NULL || IsAccusingGameServer() )
|
||||
{
|
||||
Assert( m_pAbuseTypeCombo );
|
||||
return k_EAbuseReportTypeNoSelection;
|
||||
}
|
||||
KeyValues *pUserData = m_pAbuseTypeCombo->GetActiveItemUserData();
|
||||
if ( pUserData == NULL )
|
||||
{
|
||||
return k_EAbuseReportTypeNoSelection;
|
||||
}
|
||||
return (EAbuseReportType)pUserData->GetInt( "code", k_EAbuseReportTypeNoSelection );
|
||||
}
|
||||
|
||||
CUtlString CAbuseReportDlg::GetAbuseDescription()
|
||||
{
|
||||
char buf[ 1024 ] = "";
|
||||
if ( m_pDescriptionTextEntry )
|
||||
{
|
||||
m_pDescriptionTextEntry->GetText( buf, ARRAYSIZE(buf) );
|
||||
}
|
||||
|
||||
return CUtlString( buf );
|
||||
}
|
||||
|
||||
int CAbuseReportDlg::GetAccusedPlayerIndex()
|
||||
{
|
||||
// If accusing a game server, then there's no player
|
||||
if ( IsAccusingGameServer() )
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
if ( m_pPlayerCombo == NULL )
|
||||
{
|
||||
Assert( m_pPlayerCombo );
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Item 0 is the "<select one>" item
|
||||
return m_pPlayerCombo->GetActiveItem() - 1;
|
||||
}
|
||||
|
||||
const AbuseIncidentData_t::PlayerData_t *CAbuseReportDlg::GetAccusedPlayerPtr()
|
||||
{
|
||||
int iPlayerIndex = GetAccusedPlayerIndex();
|
||||
if ( iPlayerIndex < 0 )
|
||||
return NULL;
|
||||
return &m_pIncidentData->m_vecPlayers[ iPlayerIndex ];
|
||||
}
|
||||
|
||||
bool CAbuseReportDlg::GetAttachScreenShot()
|
||||
{
|
||||
if ( m_pScreenShotAttachCheckButton == NULL )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if ( !m_pScreenShotAttachCheckButton->IsVisible() )
|
||||
{
|
||||
// We hide the checkbutton when the option is not applicable
|
||||
return false;
|
||||
}
|
||||
return m_pScreenShotAttachCheckButton->IsSelected();
|
||||
}
|
||||
|
||||
void CAbuseReportDlg::PopulatePlayerList()
|
||||
{
|
||||
if ( m_pIncidentData == NULL || m_pPlayerCombo == NULL )
|
||||
{
|
||||
Assert( m_pIncidentData );
|
||||
Assert( m_pPlayerCombo );
|
||||
return;
|
||||
}
|
||||
m_pPlayerCombo->RemoveAll();
|
||||
m_pPlayerCombo->AddItem( "#AbuseReport_SelectOne", NULL );
|
||||
for ( int i = 0 ; i < m_pIncidentData->m_vecPlayers.Count() ; ++i )
|
||||
{
|
||||
AbuseIncidentData_t::PlayerData_t *p = &m_pIncidentData->m_vecPlayers[i];
|
||||
m_pPlayerCombo->AddItem( p->m_sPersona, NULL );
|
||||
}
|
||||
m_pPlayerCombo->SilentActivateItemByRow( 0 );
|
||||
|
||||
m_pPlayerCombo->SetNumberOfEditLines( MIN( m_pPlayerCombo->GetItemCount()+1, 12 ) );
|
||||
}
|
||||
|
||||
void CAbuseReportDlg::UpdateSubmitButton()
|
||||
{
|
||||
if ( !m_pSubmitButton )
|
||||
{
|
||||
Assert( m_pSubmitButton );
|
||||
return;
|
||||
}
|
||||
|
||||
bool bEnable = false;
|
||||
if ( IsAccusingGameServer() )
|
||||
{
|
||||
bEnable = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
EAbuseReportContentType eContent = GetAbuseContentType();
|
||||
const AbuseIncidentData_t::PlayerData_t *pAccused = GetAccusedPlayerPtr();
|
||||
if (
|
||||
eContent >= 0
|
||||
&& GetAbuseType() >= 0
|
||||
&& pAccused != NULL )
|
||||
{
|
||||
bEnable = true;
|
||||
if ( eContent == k_EAbuseReportContentAvatarImage && pAccused->m_iSteamAvatarIndex <= 0 )
|
||||
{
|
||||
// Cannot accuse somebody of having a bad avatar image, if they
|
||||
// don't have one set
|
||||
bEnable = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
if ( GetAbuseDescription().IsEmpty() )
|
||||
{
|
||||
bEnable = false;
|
||||
}
|
||||
|
||||
m_pSubmitButton->SetEnabled( bEnable );
|
||||
}
|
||||
|
||||
void CAbuseReportDlg::ContentTypeChanged()
|
||||
{
|
||||
|
||||
// Save current abuse type. We want to keep it the same,
|
||||
// if possible
|
||||
EAbuseReportType abuseType = GetAbuseType();
|
||||
EAbuseReportContentType contentType = GetAbuseContentType();
|
||||
|
||||
// Show/hide screen shot / image select
|
||||
bool bShowScreenshot = false;
|
||||
bool bShowAttach = false;
|
||||
switch ( contentType )
|
||||
{
|
||||
default:
|
||||
Assert( false );
|
||||
case k_EAbuseReportContentNoSelection:
|
||||
case k_EAbuseReportContentPersonaName:
|
||||
bShowScreenshot = true;
|
||||
bShowAttach = false;
|
||||
break;
|
||||
|
||||
case k_EAbuseReportContentUnspecified:
|
||||
case k_EAbuseReportContentComments:
|
||||
case k_EAbuseReportContentCheating:
|
||||
bShowScreenshot = true;
|
||||
bShowAttach = true;
|
||||
break;
|
||||
|
||||
case k_EAbuseReportContentAvatarImage:
|
||||
case k_EAbuseReportContentUGCImage:
|
||||
bShowScreenshot = false;
|
||||
bShowAttach = false;
|
||||
break;
|
||||
}
|
||||
|
||||
bShowScreenshot = bShowScreenshot && m_pIncidentData->m_bitmapScreenshot.IsValid();
|
||||
|
||||
// Make sure we have everything we need to upload a screenshot
|
||||
bShowAttach = bShowAttach
|
||||
&& bShowScreenshot
|
||||
&& ( GetAccusedPlayerIndex() >= 0 )
|
||||
&& m_pIncidentData->m_bufScreenshotFileData.TellPut() > 0
|
||||
&& steamapicontext
|
||||
&& ( steamapicontext->SteamUtils() != NULL )
|
||||
&& ( steamapicontext->SteamRemoteStorage() != NULL );
|
||||
|
||||
if ( m_pScreenShotBitmap )
|
||||
{
|
||||
m_pScreenShotBitmap->SetVisible( bShowScreenshot );
|
||||
}
|
||||
if ( m_pScreenShotAttachCheckButton )
|
||||
{
|
||||
m_pScreenShotAttachCheckButton->SetVisible( bShowAttach );
|
||||
}
|
||||
|
||||
UpdateAvatarImage();
|
||||
UpdateCustomTextures();
|
||||
|
||||
// Populate abuse type
|
||||
if ( m_pAbuseTypeCombo )
|
||||
{
|
||||
|
||||
// If the combo box was invisible, then they didn't really make a purposeful decision
|
||||
if ( !m_pAbuseTypeCombo->IsVisible() )
|
||||
{
|
||||
abuseType = k_EAbuseReportTypeNoSelection;
|
||||
}
|
||||
m_pAbuseTypeCombo->RemoveAll();
|
||||
switch ( contentType )
|
||||
{
|
||||
default:
|
||||
Assert( false );
|
||||
case k_EAbuseReportContentNoSelection:
|
||||
m_pAbuseTypeCombo->SetVisible( false );
|
||||
abuseType = k_EAbuseReportTypeNoSelection;
|
||||
m_pAbuseTypeCombo->AddItem( "#AbuseReport_SelectOne", new KeyValues( "AbuseType", "code", k_EAbuseReportTypeNoSelection ) );
|
||||
break;
|
||||
|
||||
case k_EAbuseReportContentCheating:
|
||||
m_pAbuseTypeCombo->SetVisible( false );
|
||||
abuseType = k_EAbuseReportTypeCheating;
|
||||
m_pAbuseTypeCombo->AddItem( "#AbuseReport_TypeCheating", new KeyValues( "AbuseType", "code", k_EAbuseReportTypeCheating ) );
|
||||
break;
|
||||
|
||||
case k_EAbuseReportContentUnspecified:
|
||||
case k_EAbuseReportContentComments:
|
||||
case k_EAbuseReportContentPersonaName:
|
||||
case k_EAbuseReportContentAvatarImage:
|
||||
case k_EAbuseReportContentUGCImage:
|
||||
m_pAbuseTypeCombo->SetVisible( true );
|
||||
m_pAbuseTypeCombo->AddItem( "#AbuseReport_SelectOne", new KeyValues( "AbuseType", "code", k_EAbuseReportTypeNoSelection ) );
|
||||
m_pAbuseTypeCombo->AddItem( "#AbuseReport_TypeSpam", new KeyValues( "AbuseType", "code", k_EAbuseReportTypeSpamming ) );
|
||||
m_pAbuseTypeCombo->AddItem( "#AbuseReport_TypeAdvertisement", new KeyValues( "AbuseType", "code", k_EAbuseReportTypeAdvertisement ) );
|
||||
m_pAbuseTypeCombo->AddItem( "#AbuseReport_TypeLanguage", new KeyValues( "AbuseType", "code", k_EAbuseReportTypeLanguage ) );
|
||||
m_pAbuseTypeCombo->AddItem( "#AbuseReport_TypeAdultContent", new KeyValues( "AbuseType", "code", k_EAbuseReportTypeAdultContent ) );
|
||||
m_pAbuseTypeCombo->AddItem( "#AbuseReport_TypeHarassment", new KeyValues( "AbuseType", "code", k_EAbuseReportTypeHarassment ) );
|
||||
m_pAbuseTypeCombo->AddItem( "#AbuseReport_TypeProhibited", new KeyValues( "AbuseType", "code", k_EAbuseReportTypeProhibited ) );
|
||||
m_pAbuseTypeCombo->AddItem( "#AbuseReport_TypeSpoofing", new KeyValues( "AbuseType", "code", k_EAbuseReportTypeSpoofing ) );
|
||||
//m_pAbuseTypeCombo->AddItem( "#AbuseReport_TypeCheating", new KeyValues( "AbuseType", "code", k_EAbuseReportTypeCheating ) );
|
||||
m_pAbuseTypeCombo->AddItem( "#AbuseReport_TypeInappropriate", new KeyValues( "AbuseType", "code", k_EAbuseReportTypeInappropriate ) );
|
||||
m_pAbuseTypeCombo->AddItem( "#AbuseReport_TypeOther", new KeyValues( "AbuseType", "code", k_EAbuseReportTypeUnspecified ) );
|
||||
break;
|
||||
}
|
||||
|
||||
// Now select the proper row
|
||||
int sel = 0;
|
||||
for ( int i = 0 ; i < m_pAbuseTypeCombo->GetItemCount() ; ++i ) {
|
||||
if ( m_pAbuseTypeCombo->GetItemUserData(i)->GetInt("code") == abuseType )
|
||||
{
|
||||
sel = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
m_pAbuseTypeCombo->SilentActivateItemByRow( sel );
|
||||
m_pAbuseTypeCombo->SetNumberOfEditLines( m_pAbuseTypeCombo->GetItemCount() );
|
||||
if ( m_pAbuseTypeLabel )
|
||||
{
|
||||
m_pAbuseTypeLabel->SetVisible( m_pAbuseTypeCombo->IsVisible() );
|
||||
}
|
||||
}
|
||||
|
||||
UpdateSubmitButton();
|
||||
}
|
||||
|
||||
void CAbuseReportDlg::OnRadioButtonChecked( vgui::Panel *panel )
|
||||
{
|
||||
if ( panel == m_pPlayerRadio )
|
||||
{
|
||||
SetIsAccusingGameServer( false );
|
||||
}
|
||||
else if ( panel == m_pGameServerRadio )
|
||||
{
|
||||
SetIsAccusingGameServer( true );
|
||||
}
|
||||
else
|
||||
{
|
||||
Assert( !"Clicked on unknown radio" );
|
||||
}
|
||||
}
|
||||
|
||||
void CAbuseReportDlg::SetIsAccusingGameServer( bool bAccuseGameServer )
|
||||
{
|
||||
if ( m_pGameServerRadio && m_pGameServerRadio->IsSelected() != bAccuseGameServer )
|
||||
{
|
||||
m_pGameServerRadio->SetSelected( bAccuseGameServer );
|
||||
}
|
||||
if ( m_pPlayerRadio && m_pPlayerRadio->IsSelected() == bAccuseGameServer)
|
||||
{
|
||||
m_pPlayerRadio->SetSelected( !bAccuseGameServer );
|
||||
}
|
||||
if ( m_pPlayerLabel )
|
||||
{
|
||||
m_pPlayerLabel->SetVisible( !bAccuseGameServer );
|
||||
}
|
||||
if ( m_pPlayerCombo )
|
||||
{
|
||||
m_pPlayerCombo->SetVisible( !bAccuseGameServer );
|
||||
}
|
||||
|
||||
PlayerChanged();
|
||||
}
|
||||
|
||||
void CAbuseReportDlg::PlayerChanged()
|
||||
{
|
||||
m_iUserImageIndex = 0;
|
||||
|
||||
bool bShow = ( GetAccusedPlayerIndex() >= 0 );
|
||||
if ( m_pAbuseContentCombo != NULL )
|
||||
{
|
||||
m_pAbuseContentCombo->SetVisible( bShow );
|
||||
}
|
||||
if ( m_pAbuseContentLabel != NULL )
|
||||
{
|
||||
m_pAbuseContentLabel->SetVisible( bShow );
|
||||
}
|
||||
|
||||
ContentTypeChanged();
|
||||
}
|
||||
|
||||
void CAbuseReportDlg::UpdateAvatarImage()
|
||||
{
|
||||
if ( m_pAvatarImage == NULL || m_pNoAvatarLabel == NULL )
|
||||
{
|
||||
Assert( m_pAvatarImage );
|
||||
Assert( m_pNoAvatarLabel );
|
||||
return;
|
||||
}
|
||||
|
||||
const AbuseIncidentData_t::PlayerData_t *pAccused = GetAccusedPlayerPtr();
|
||||
if ( GetAbuseContentType() == k_EAbuseReportContentAvatarImage && pAccused != NULL )
|
||||
{
|
||||
if ( pAccused->m_iSteamAvatarIndex > 0 )
|
||||
{
|
||||
m_pAvatarImage->SetShouldDrawFriendIcon( false );
|
||||
m_pAvatarImage->SetPlayer( pAccused->m_steamID, k_EAvatarSize184x184 );
|
||||
|
||||
m_pAvatarImage->SetVisible( true );
|
||||
m_pNoAvatarLabel->SetVisible( false );
|
||||
}
|
||||
else
|
||||
{
|
||||
m_pAvatarImage->SetVisible( false );
|
||||
m_pNoAvatarLabel->SetVisible( true );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
m_pAvatarImage->SetVisible( false );
|
||||
m_pNoAvatarLabel->SetVisible( false );
|
||||
}
|
||||
}
|
||||
|
||||
void CAbuseReportDlg::UpdateCustomTextures()
|
||||
{
|
||||
if ( m_pCustomTextureImagePanel == NULL || m_pNoCustomTexturesLabel == NULL || m_pCustomTextureNextButton == NULL || m_pCustomTexturePrevButton == NULL )
|
||||
{
|
||||
Assert( m_pCustomTextureImagePanel );
|
||||
Assert( m_pNoCustomTexturesLabel );
|
||||
Assert( m_pCustomTextureNextButton );
|
||||
Assert( m_pCustomTexturePrevButton );
|
||||
return;
|
||||
}
|
||||
|
||||
const AbuseIncidentData_t::PlayerData_t *pAccused = GetAccusedPlayerPtr();
|
||||
bool bShowScrollButtons = false;
|
||||
if ( GetAbuseContentType() == k_EAbuseReportContentUGCImage && pAccused != NULL )
|
||||
{
|
||||
int iSelectedCustomImage = GetSelectedCustomImage();
|
||||
|
||||
if ( iSelectedCustomImage >= 0 )
|
||||
{
|
||||
|
||||
// Currently the only thing we support...
|
||||
Assert( pAccused->m_vecImages[ iSelectedCustomImage].m_eType == AbuseIncidentData_t::k_PlayerImageType_UGC );
|
||||
|
||||
m_pCustomTextureImagePanel->m_ugcHandle = pAccused->m_vecImages[ iSelectedCustomImage].m_hUGCHandle;
|
||||
|
||||
m_pCustomTextureImagePanel->SetVisible( true );
|
||||
m_pNoCustomTexturesLabel->SetVisible( false );
|
||||
|
||||
int n = pAccused->m_vecImages.Count();
|
||||
if ( n > 1 )
|
||||
{
|
||||
bShowScrollButtons = true;
|
||||
m_pCustomTextureNextButton->SetEnabled( iSelectedCustomImage < n-1 );
|
||||
m_pCustomTexturePrevButton->SetEnabled( iSelectedCustomImage > 0 );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
m_pCustomTextureImagePanel->SetVisible( false );
|
||||
m_pNoCustomTexturesLabel->SetVisible( true );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
m_pCustomTextureImagePanel->SetVisible( false );
|
||||
m_pNoCustomTexturesLabel->SetVisible( false );
|
||||
}
|
||||
m_pCustomTextureNextButton->SetVisible( bShowScrollButtons );
|
||||
m_pCustomTexturePrevButton->SetVisible( bShowScrollButtons );
|
||||
}
|
||||
|
||||
int CAbuseReportDlg::GetSelectedCustomImage()
|
||||
{
|
||||
if ( GetAbuseContentType() != k_EAbuseReportContentUGCImage )
|
||||
{
|
||||
m_iUserImageIndex = 0;
|
||||
return -1;
|
||||
}
|
||||
|
||||
const AbuseIncidentData_t::PlayerData_t *pAccused = GetAccusedPlayerPtr();
|
||||
if ( pAccused == NULL )
|
||||
{
|
||||
m_iUserImageIndex = 0;
|
||||
return -1;
|
||||
}
|
||||
|
||||
int n = pAccused->m_vecImages.Count();
|
||||
if ( n < 1 )
|
||||
{
|
||||
m_iUserImageIndex = 0;
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Wrap currently selected index
|
||||
m_iUserImageIndex = ( m_iUserImageIndex + n*10 ) % n;
|
||||
|
||||
// Return it
|
||||
return m_iUserImageIndex;
|
||||
}
|
||||
|
||||
void CAbuseReportDlg::OnTextChanged( vgui::Panel *panel )
|
||||
{
|
||||
if ( panel == m_pPlayerCombo )
|
||||
{
|
||||
PlayerChanged();
|
||||
}
|
||||
else if ( panel == m_pAbuseContentCombo )
|
||||
{
|
||||
ContentTypeChanged();
|
||||
}
|
||||
else
|
||||
{
|
||||
UpdateSubmitButton();
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Job to do the async work of submitting the report
|
||||
//-----------------------------------------------------------------------------
|
||||
class CSubmitAbuseReportJob : public GCSDK::CGCClientJob
|
||||
{
|
||||
public:
|
||||
bool m_bGameServer;
|
||||
|
||||
|
||||
CSubmitAbuseReportJob( )
|
||||
: GCSDK::CGCClientJob( GCClientSystem()->GetGCClient() )
|
||||
{
|
||||
m_bGameServer = false;
|
||||
}
|
||||
|
||||
virtual bool BYieldingRunGCJob()
|
||||
{
|
||||
EResult result = RunJob();
|
||||
|
||||
// Tear down our dialogs
|
||||
CloseWaitingDialog();
|
||||
|
||||
CAbuseReportDlg *pDlg = g_AbuseReportDlg.Get();
|
||||
if ( pDlg )
|
||||
{
|
||||
pDlg->Close();
|
||||
pDlg = NULL;
|
||||
}
|
||||
|
||||
// And destroy the queued report!
|
||||
g_AbuseReportMgr->DestroyIncidentData();
|
||||
|
||||
// now show a dialog box explaining the outcome
|
||||
switch ( result )
|
||||
{
|
||||
case k_EResultOK:
|
||||
ShowMessageBox( "#AbuseReport_SucceededTitle", "#AbuseReport_SucceededMessage", "#GameUI_OK" );
|
||||
break;
|
||||
|
||||
case k_EResultLimitExceeded:
|
||||
ShowMessageBox(
|
||||
"#AbuseReport_TooMuchFailedTitle",
|
||||
m_bGameServer ? "#AbuseReport_TooMuchFailedMessageGameServer" : "#AbuseReport_TooMuchFailedMessage",
|
||||
"#GameUI_OK"
|
||||
);
|
||||
break;
|
||||
|
||||
default:
|
||||
ShowMessageBox( "#AbuseReport_GenericFailureTitle", "#AbuseReport_GenericFailureMessage", "#GameUI_OK" );
|
||||
break;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
EResult RunJob()
|
||||
{
|
||||
CAbuseReportDlg *pDlg = g_AbuseReportDlg.Get();
|
||||
if ( pDlg == NULL )
|
||||
{
|
||||
return k_EResultFail;
|
||||
}
|
||||
m_bGameServer = pDlg->IsAccusingGameServer();
|
||||
EAbuseReportContentType eContentSelected = pDlg->GetAbuseContentType();
|
||||
EAbuseReportContentType eContentReported = eContentSelected;
|
||||
EAbuseReportType eAbuseType = pDlg->GetAbuseType();
|
||||
const AbuseIncidentData_t::PlayerData_t *pAccused = pDlg->GetAccusedPlayerPtr();
|
||||
const AbuseIncidentData_t *pIncidentData = g_AbuseReportMgr->GetIncidentData();
|
||||
CUtlString sAbuseDescription = pDlg->GetAbuseDescription();
|
||||
netadr_t adrGameServer = pIncidentData->m_adrGameServer;
|
||||
CSteamID steamIDGameServer = pIncidentData->m_steamIDGameServer;
|
||||
uint64 gid = 0;
|
||||
|
||||
// Check if we should upload the screenshot
|
||||
if ( pDlg->GetAttachScreenShot() && steamapicontext && steamapicontext->SteamUtils() && steamapicontext->SteamRemoteStorage() )
|
||||
{
|
||||
|
||||
// Write the local copy of the file
|
||||
if ( !steamapicontext->SteamRemoteStorage()->FileWrite( CAbuseReportManager::k_rchScreenShotFilename, pIncidentData->m_bufScreenshotFileData.Base(), pIncidentData->m_bufScreenshotFileData.TellPut() ) )
|
||||
{
|
||||
Warning( "Failed to save local cloud copy of %s\n", CAbuseReportManager::k_rchScreenShotFilename );
|
||||
return k_EResultFail;
|
||||
}
|
||||
|
||||
// Share it. This initiates the upload to cloud
|
||||
Msg( "Starting upload of %s to UFS....\n", CAbuseReportManager::k_rchScreenShotFilename );
|
||||
SteamAPICall_t hFileShareApiCall = steamapicontext->SteamRemoteStorage()->FileShare( CAbuseReportManager::k_rchScreenShotFilename );
|
||||
if ( hFileShareApiCall == k_uAPICallInvalid )
|
||||
{
|
||||
Warning( "Failed to share %s\n", CAbuseReportManager::k_rchScreenShotFilename );
|
||||
return k_EResultFail;
|
||||
}
|
||||
|
||||
// Check if we're busy
|
||||
bool bFailed;
|
||||
RemoteStorageFileShareResult_t result;
|
||||
while ( !steamapicontext->SteamUtils()->GetAPICallResult(hFileShareApiCall,
|
||||
&result, sizeof(result), RemoteStorageFileShareResult_t::k_iCallback, &bFailed) )
|
||||
{
|
||||
BYield();
|
||||
}
|
||||
|
||||
// Clear pointer, it could have been destroyed while we were yielding, make sure we don't reference it
|
||||
pDlg = NULL;
|
||||
|
||||
if ( bFailed || result.m_eResult != k_EResultOK )
|
||||
{
|
||||
Warning( "Failed to share %s; result code %d\n", CAbuseReportManager::k_rchScreenShotFilename, result.m_eResult );
|
||||
return result.m_eResult;
|
||||
}
|
||||
|
||||
Msg( "%s shared to UGC OK\n", CAbuseReportManager::k_rchScreenShotFilename );
|
||||
gid = result.m_hFile;
|
||||
|
||||
// SWitch the content type being reported, so the support tool will know what to
|
||||
// do with the GID.
|
||||
eContentReported = k_EAbuseReportContentActorUGCImage;
|
||||
}
|
||||
else if ( eContentSelected == k_EAbuseReportContentUGCImage )
|
||||
{
|
||||
Assert( !m_bGameServer );
|
||||
int iImageindex = pDlg->GetSelectedCustomImage();
|
||||
Assert( iImageindex >= 0 );
|
||||
gid = pAccused->m_vecImages[iImageindex].m_hUGCHandle;
|
||||
}
|
||||
|
||||
//
|
||||
// Fill out the report message
|
||||
//
|
||||
GCSDK::CProtoBufMsg<CMsgGCReportAbuse> msg( k_EMsgGC_ReportAbuse );
|
||||
if ( m_bGameServer )
|
||||
{
|
||||
msg.Body().set_target_steam_id( steamIDGameServer.ConvertToUint64() );
|
||||
msg.Body().set_target_game_server_ip( adrGameServer.GetIPHostByteOrder() );
|
||||
msg.Body().set_target_game_server_port( adrGameServer.GetPort() );
|
||||
}
|
||||
else
|
||||
{
|
||||
msg.Body().set_target_steam_id( pAccused->m_steamID.ConvertToUint64() );
|
||||
msg.Body().set_content_type( eContentReported );
|
||||
msg.Body().set_abuse_type( eAbuseType );
|
||||
}
|
||||
msg.Body().set_description( sAbuseDescription );
|
||||
if (gid != 0 )
|
||||
{
|
||||
msg.Body().set_gid( gid );
|
||||
}
|
||||
|
||||
// Send the message to the GC, and await the reply
|
||||
GCSDK::CProtoBufMsg<CMsgGCReportAbuseResponse> msgReply;
|
||||
if ( !BYldSendMessageAndGetReply( msg, 10, &msgReply, k_EMsgGC_ReportAbuseResponse ) )
|
||||
{
|
||||
Warning( "Abuse report failed: Did not get reply from GC\n" );
|
||||
return k_EResultTimeout;
|
||||
}
|
||||
|
||||
EResult result = (EResult)msgReply.Body().result();
|
||||
if ( result != k_EResultOK )
|
||||
{
|
||||
Warning( "Abuse report failed with failure code %d. %s\n", result, msgReply.Body().error_message().c_str() );
|
||||
}
|
||||
|
||||
// OK
|
||||
return result;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
void CAbuseReportDlg::OnSubmitReport()
|
||||
{
|
||||
// throw up a waiting dialog
|
||||
SetEnabled( false );
|
||||
ShowWaitingDialog( new CGenericWaitingDialog( this ), "#AbuseReport_Busy", true, false, 0.0f );
|
||||
|
||||
// We need to be in the global singleton handle, because that's how the job knows
|
||||
// to get to us (and how it knows if we've died)!
|
||||
Assert( g_AbuseReportDlg.Get() == this );
|
||||
|
||||
// Start a job
|
||||
CSubmitAbuseReportJob *pJob = new CSubmitAbuseReportJob();
|
||||
pJob->StartJob( NULL );
|
||||
}
|
||||
@@ -0,0 +1,100 @@
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose: Generic in-game abuse reporting
|
||||
//
|
||||
// $NoKeywords: $
|
||||
//=============================================================================//
|
||||
|
||||
#ifndef ABUSE_REPORT_UI_H
|
||||
#define ABUSE_REPORT_UI_H
|
||||
#ifdef _WIN32
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
#include "abuse_report.h"
|
||||
#include <vgui_controls/EditablePanel.h>
|
||||
|
||||
class CAvatarImagePanel;
|
||||
class CCustomTextureImagePanel;
|
||||
class CAbuseReportScreenShotPanel;
|
||||
|
||||
class CAbuseReportDlg : public vgui::EditablePanel
|
||||
{
|
||||
DECLARE_CLASS_SIMPLE( CAbuseReportDlg, vgui::EditablePanel );
|
||||
|
||||
public:
|
||||
CAbuseReportDlg( vgui::Panel *parent, AbuseIncidentData_t *pIncidentData );
|
||||
~CAbuseReportDlg();
|
||||
|
||||
virtual void OnCommand(const char *command);
|
||||
virtual void Close();
|
||||
virtual void ApplySchemeSettings( vgui::IScheme *pScheme );
|
||||
virtual void PerformLayout();
|
||||
|
||||
virtual void MakeModal();
|
||||
|
||||
bool IsAccusingGameServer();
|
||||
EAbuseReportContentType GetAbuseContentType();
|
||||
EAbuseReportType GetAbuseType();
|
||||
int GetAccusedPlayerIndex();
|
||||
const AbuseIncidentData_t::PlayerData_t *GetAccusedPlayerPtr();
|
||||
int GetUserImageIndex();
|
||||
int GetSelectedCustomImage();
|
||||
CUtlString GetAbuseDescription();
|
||||
bool GetAttachScreenShot();
|
||||
|
||||
protected:
|
||||
|
||||
MESSAGE_FUNC_PTR( OnRadioButtonChecked, "RadioButtonChecked", panel );
|
||||
|
||||
virtual const char *GetResFilename();
|
||||
|
||||
vgui::Button *m_pSubmitButton;
|
||||
|
||||
vgui::Button *m_pScreenShot;
|
||||
vgui::CheckButton *m_pScreenShotAttachCheckButton;
|
||||
|
||||
vgui::Button *m_pCustomTextureNextButton;
|
||||
vgui::Button *m_pCustomTexturePrevButton;
|
||||
vgui::Button *m_pOffensiveImage;
|
||||
|
||||
vgui::TextEntry *m_pDescriptionTextEntry;
|
||||
vgui::Panel *m_pPlayerLabel;
|
||||
vgui::RadioButton *m_pPlayerRadio;
|
||||
vgui::RadioButton *m_pGameServerRadio;
|
||||
vgui::ComboBox *m_pPlayerCombo;
|
||||
vgui::Panel *m_pAbuseContentLabel;
|
||||
vgui::ComboBox *m_pAbuseContentCombo;
|
||||
vgui::Panel *m_pAbuseTypeLabel;
|
||||
vgui::ComboBox *m_pAbuseTypeCombo;
|
||||
|
||||
CAbuseReportScreenShotPanel *m_pScreenShotBitmap;
|
||||
|
||||
CAvatarImagePanel *m_pAvatarImage;
|
||||
vgui::Panel *m_pNoAvatarLabel;
|
||||
|
||||
CCustomTextureImagePanel *m_pCustomTextureImagePanel;
|
||||
vgui::Panel *m_pNoCustomTexturesLabel;
|
||||
|
||||
AbuseIncidentData_t *m_pIncidentData;
|
||||
|
||||
int m_iUserImageIndex;
|
||||
|
||||
MESSAGE_FUNC_PTR( OnTextChanged, "TextChanged", panel ); // send by combo box when it changes
|
||||
|
||||
void PopulatePlayerList();
|
||||
void UpdateSubmitButton();
|
||||
void SetIsAccusingGameServer( bool bAccuseGameServer );
|
||||
void PlayerChanged();
|
||||
void ContentTypeChanged();
|
||||
void UpdateAvatarImage();
|
||||
void UpdateCustomTextures();
|
||||
|
||||
virtual void OnSubmitReport();
|
||||
};
|
||||
|
||||
/// Global pointer to the submission dialiog.
|
||||
/// NULL if it's not displayed
|
||||
extern vgui::DHANDLE<CAbuseReportDlg> g_AbuseReportDlg;
|
||||
|
||||
#endif // ABUSE_REPORT_UI_H
|
||||
@@ -0,0 +1,272 @@
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
// $NoKeywords: $
|
||||
//=============================================================================
|
||||
|
||||
#include "cbase.h"
|
||||
#include "hud.h"
|
||||
#include "hud_macros.h"
|
||||
#include "hudelement.h"
|
||||
#include "iclientmode.h"
|
||||
#include "ienginevgui.h"
|
||||
#include <vgui/ILocalize.h>
|
||||
#include <vgui/ISurface.h>
|
||||
#include <vgui/IVGui.h>
|
||||
#include <vgui_controls/EditablePanel.h>
|
||||
#include <vgui_controls/Label.h>
|
||||
#include <vgui_controls/ImagePanel.h>
|
||||
#include "achievement_notification_panel.h"
|
||||
#include "steam/steam_api.h"
|
||||
#include "iachievementmgr.h"
|
||||
#include "fmtstr.h"
|
||||
|
||||
// memdbgon must be the last include file in a .cpp file!!!
|
||||
#include "tier0/memdbgon.h"
|
||||
|
||||
using namespace vgui;
|
||||
|
||||
#define ACHIEVEMENT_NOTIFICATION_DURATION 10.0f
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
DECLARE_HUDELEMENT_DEPTH( CAchievementNotificationPanel, 100 );
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
CAchievementNotificationPanel::CAchievementNotificationPanel( const char *pElementName ) : CHudElement( pElementName ), BaseClass( NULL, "AchievementNotificationPanel" )
|
||||
{
|
||||
Panel *pParent = g_pClientMode->GetViewport();
|
||||
SetParent( pParent );
|
||||
|
||||
m_flHideTime = 0;
|
||||
m_pPanelBackground = new EditablePanel( this, "Notification_Background" );
|
||||
m_pIcon = new ImagePanel( this, "Notification_Icon" );
|
||||
m_pLabelHeading = new Label( this, "HeadingLabel", "" );
|
||||
m_pLabelTitle = new Label( this, "TitleLabel", "" );
|
||||
|
||||
m_pIcon->SetShouldScaleImage( true );
|
||||
|
||||
vgui::ivgui()->AddTickSignal( GetVPanel() );
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
void CAchievementNotificationPanel::Init()
|
||||
{
|
||||
ListenForGameEvent( "achievement_event" );
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
void CAchievementNotificationPanel::ApplySchemeSettings( IScheme *pScheme )
|
||||
{
|
||||
// load control settings...
|
||||
LoadControlSettings( "resource/UI/AchievementNotification.res" );
|
||||
|
||||
BaseClass::ApplySchemeSettings( pScheme );
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
void CAchievementNotificationPanel::PerformLayout( void )
|
||||
{
|
||||
BaseClass::PerformLayout();
|
||||
|
||||
// Set background color of various elements. Need to do this in code, if we do it in res file it gets slammed by the
|
||||
// scheme. (Incl. label background: some products don't have label background colors set in their scheme and helpfully slam it to white.)
|
||||
SetBgColor( Color( 0, 0, 0, 0 ) );
|
||||
m_pLabelHeading->SetBgColor( Color( 0, 0, 0, 0 ) );
|
||||
m_pLabelTitle->SetBgColor( Color( 0, 0, 0, 0 ) );
|
||||
m_pPanelBackground->SetBgColor( Color( 62,70,55, 200 ) );
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
void CAchievementNotificationPanel::FireGameEvent( IGameEvent * event )
|
||||
{
|
||||
const char *name = event->GetName();
|
||||
if ( 0 == Q_strcmp( name, "achievement_event" ) )
|
||||
{
|
||||
const char *pchName = event->GetString( "achievement_name" );
|
||||
int iCur = event->GetInt( "cur_val" );
|
||||
int iMax = event->GetInt( "max_val" );
|
||||
wchar_t szLocalizedName[256]=L"";
|
||||
|
||||
if ( IsPC() )
|
||||
{
|
||||
// shouldn't ever get achievement progress if steam not running and user logged in, but check just in case
|
||||
if ( !steamapicontext->SteamUserStats() )
|
||||
{
|
||||
Msg( "Steam not running, achievement progress notification not displayed\n" );
|
||||
}
|
||||
else
|
||||
{
|
||||
// use Steam to show achievement progress UI
|
||||
steamapicontext->SteamUserStats()->IndicateAchievementProgress( pchName, iCur, iMax );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// on X360 we need to show our own achievement progress UI
|
||||
|
||||
const wchar_t *pchLocalizedName = ACHIEVEMENT_LOCALIZED_NAME_FROM_STR( pchName );
|
||||
Assert( pchLocalizedName );
|
||||
if ( !pchLocalizedName || !pchLocalizedName[0] )
|
||||
return;
|
||||
Q_wcsncpy( szLocalizedName, pchLocalizedName, sizeof( szLocalizedName ) );
|
||||
|
||||
// this is achievement progress, compose the message of form: "<name> (<#>/<max>)"
|
||||
wchar_t szFmt[128]=L"";
|
||||
wchar_t szText[512]=L"";
|
||||
wchar_t szNumFound[16]=L"";
|
||||
wchar_t szNumTotal[16]=L"";
|
||||
_snwprintf( szNumFound, ARRAYSIZE( szNumFound ), L"%i", iCur );
|
||||
_snwprintf( szNumTotal, ARRAYSIZE( szNumTotal ), L"%i", iMax );
|
||||
|
||||
const wchar_t *pchFmt = g_pVGuiLocalize->Find( "#GameUI_Achievement_Progress_Fmt" );
|
||||
if ( !pchFmt || !pchFmt[0] )
|
||||
return;
|
||||
Q_wcsncpy( szFmt, pchFmt, sizeof( szFmt ) );
|
||||
|
||||
g_pVGuiLocalize->ConstructString_safe( szText, szFmt, 3, szLocalizedName, szNumFound, szNumTotal );
|
||||
AddNotification( pchName, g_pVGuiLocalize->Find( "#GameUI_Achievement_Progress" ), szText );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Called on each tick
|
||||
//-----------------------------------------------------------------------------
|
||||
void CAchievementNotificationPanel::OnTick( void )
|
||||
{
|
||||
if ( ( m_flHideTime > 0 ) && ( m_flHideTime < gpGlobals->curtime ) )
|
||||
{
|
||||
m_flHideTime = 0;
|
||||
ShowNextNotification();
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
bool CAchievementNotificationPanel::ShouldDraw( void )
|
||||
{
|
||||
return ( ( m_flHideTime > 0 ) && ( m_flHideTime > gpGlobals->curtime ) && CHudElement::ShouldDraw() );
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
void CAchievementNotificationPanel::AddNotification( const char *szIconBaseName, const wchar_t *pHeading, const wchar_t *pTitle )
|
||||
{
|
||||
// put this notification in our queue
|
||||
int iQueueItem = m_queueNotification.AddToTail();
|
||||
Notification_t ¬ification = m_queueNotification[iQueueItem];
|
||||
Q_strncpy( notification.szIconBaseName, szIconBaseName, ARRAYSIZE( notification.szIconBaseName ) );
|
||||
Q_wcsncpy( notification.szHeading, pHeading, sizeof( notification.szHeading ) );
|
||||
Q_wcsncpy( notification.szTitle, pTitle, sizeof( notification.szTitle ) );
|
||||
|
||||
// if we are not currently displaying a notification, go ahead and show this one
|
||||
if ( 0 == m_flHideTime )
|
||||
{
|
||||
ShowNextNotification();
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Shows next notification in queue if there is one
|
||||
//-----------------------------------------------------------------------------
|
||||
void CAchievementNotificationPanel::ShowNextNotification()
|
||||
{
|
||||
// see if we have anything to do
|
||||
if ( 0 == m_queueNotification.Count() )
|
||||
{
|
||||
m_flHideTime = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
Notification_t ¬ification = m_queueNotification[ m_queueNotification.Head() ];
|
||||
|
||||
m_flHideTime = gpGlobals->curtime + ACHIEVEMENT_NOTIFICATION_DURATION;
|
||||
|
||||
// set the text and icon in the dialog
|
||||
SetDialogVariable( "heading", notification.szHeading );
|
||||
SetDialogVariable( "title", notification.szTitle );
|
||||
const char *pchIconBaseName = notification.szIconBaseName;
|
||||
if ( pchIconBaseName && pchIconBaseName[0] )
|
||||
{
|
||||
m_pIcon->SetImage( CFmtStr( "achievements/%s.vmt", pchIconBaseName ) );
|
||||
}
|
||||
|
||||
// resize the panel so it always looks good
|
||||
|
||||
// get fonts
|
||||
HFont hFontHeading = m_pLabelHeading->GetFont();
|
||||
HFont hFontTitle = m_pLabelTitle->GetFont();
|
||||
// determine how wide the text strings are
|
||||
int iHeadingWidth = UTIL_ComputeStringWidth( hFontHeading, notification.szHeading );
|
||||
int iTitleWidth = UTIL_ComputeStringWidth( hFontTitle, notification.szTitle );
|
||||
// use the widest string
|
||||
int iTextWidth = MAX( iHeadingWidth, iTitleWidth );
|
||||
// don't let it be insanely wide
|
||||
iTextWidth = MIN( iTextWidth, XRES( 300 ) );
|
||||
int iIconWidth = m_pIcon->GetWide();
|
||||
int iSpacing = XRES( 10 );
|
||||
int iPanelWidth = iSpacing + iIconWidth + iSpacing + iTextWidth + iSpacing;
|
||||
int iPanelX = GetWide() - iPanelWidth;
|
||||
int iIconX = iPanelX + iSpacing;
|
||||
int iTextX = iIconX + iIconWidth + iSpacing;
|
||||
// resize all the elements
|
||||
SetXAndWide( m_pPanelBackground, iPanelX, iPanelWidth );
|
||||
SetXAndWide( m_pIcon, iIconX, iIconWidth );
|
||||
SetXAndWide( m_pLabelHeading, iTextX, iTextWidth );
|
||||
SetXAndWide( m_pLabelTitle, iTextX, iTextWidth );
|
||||
|
||||
m_queueNotification.Remove( m_queueNotification.Head() );
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
void CAchievementNotificationPanel::SetXAndWide( Panel *pPanel, int x, int wide )
|
||||
{
|
||||
int xCur, yCur;
|
||||
pPanel->GetPos( xCur, yCur );
|
||||
pPanel->SetPos( x, yCur );
|
||||
pPanel->SetWide( wide );
|
||||
}
|
||||
|
||||
CON_COMMAND_F( achievement_notification_test, "Test the hud notification UI", FCVAR_CHEAT | FCVAR_DEVELOPMENTONLY )
|
||||
{
|
||||
static int iCount=0;
|
||||
|
||||
CAchievementNotificationPanel *pPanel = GET_HUDELEMENT( CAchievementNotificationPanel );
|
||||
if ( pPanel )
|
||||
{
|
||||
pPanel->AddNotification( "HL2_KILL_ODESSAGUNSHIP", L"Achievement Progress", ( 0 == ( iCount % 2 ) ? L"Test Notification Message A (1/10)" :
|
||||
L"Test Message B" ) );
|
||||
}
|
||||
|
||||
#if 0
|
||||
IGameEvent *event = gameeventmanager->CreateEvent( "achievement_event" );
|
||||
if ( event )
|
||||
{
|
||||
const char *szTestStr[] = { "TF_GET_HEADSHOTS", "TF_PLAY_GAME_EVERYMAP", "TF_PLAY_GAME_EVERYCLASS", "TF_GET_HEALPOINTS" };
|
||||
event->SetString( "achievement_name", szTestStr[iCount%ARRAYSIZE(szTestStr)] );
|
||||
event->SetInt( "cur_val", ( iCount%9 ) + 1 );
|
||||
event->SetInt( "max_val", 10 );
|
||||
gameeventmanager->FireEvent( event );
|
||||
}
|
||||
#endif
|
||||
|
||||
iCount++;
|
||||
}
|
||||
@@ -0,0 +1,57 @@
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
// $NoKeywords: $
|
||||
//=============================================================================//
|
||||
|
||||
#ifndef ACHIEVEMENT_NOTIFICATION_PANEL_H
|
||||
#define ACHIEVEMENT_NOTIFICATION_PANEL_H
|
||||
#ifdef _WIN32
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
#include <vgui_controls/EditablePanel.h>
|
||||
#include "hudelement.h"
|
||||
|
||||
using namespace vgui;
|
||||
|
||||
class CAchievementNotificationPanel : public CHudElement, public EditablePanel
|
||||
{
|
||||
DECLARE_CLASS_SIMPLE( CAchievementNotificationPanel, EditablePanel );
|
||||
|
||||
public:
|
||||
CAchievementNotificationPanel( const char *pElementName );
|
||||
|
||||
virtual void Init();
|
||||
virtual void ApplySchemeSettings( IScheme *scheme );
|
||||
virtual bool ShouldDraw( void );
|
||||
virtual void PerformLayout( void );
|
||||
virtual void LevelInit( void ) { m_flHideTime = 0; }
|
||||
virtual void FireGameEvent( IGameEvent * event );
|
||||
virtual void OnTick( void );
|
||||
|
||||
void AddNotification( const char *szIconBaseName, const wchar_t *pHeading, const wchar_t *pTitle );
|
||||
|
||||
private:
|
||||
void ShowNextNotification();
|
||||
void SetXAndWide( Panel *pPanel, int x, int wide );
|
||||
|
||||
float m_flHideTime;
|
||||
|
||||
Label *m_pLabelHeading;
|
||||
Label *m_pLabelTitle;
|
||||
EditablePanel *m_pPanelBackground;
|
||||
ImagePanel *m_pIcon;
|
||||
|
||||
struct Notification_t
|
||||
{
|
||||
char szIconBaseName[255];
|
||||
wchar_t szHeading[255];
|
||||
wchar_t szTitle[255];
|
||||
};
|
||||
|
||||
CUtlLinkedList<Notification_t> m_queueNotification;
|
||||
};
|
||||
|
||||
#endif // ACHIEVEMENT_NOTIFICATION_PANEL_H
|
||||
@@ -0,0 +1,62 @@
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
// $NoKeywords: $
|
||||
//=============================================================================//
|
||||
#include "cbase.h"
|
||||
#include "proxyentity.h"
|
||||
#include "materialsystem/imaterial.h"
|
||||
#include "materialsystem/imaterialvar.h"
|
||||
|
||||
// memdbgon must be the last include file in a .cpp file!!!
|
||||
#include "tier0/memdbgon.h"
|
||||
|
||||
// $sineVar : name of variable that controls the alpha level (float)
|
||||
class CAlphaMaterialProxy : public CEntityMaterialProxy
|
||||
{
|
||||
public:
|
||||
CAlphaMaterialProxy();
|
||||
virtual ~CAlphaMaterialProxy();
|
||||
virtual bool Init( IMaterial *pMaterial, KeyValues *pKeyValues );
|
||||
virtual void OnBind( C_BaseEntity *pEntity );
|
||||
virtual IMaterial *GetMaterial();
|
||||
|
||||
private:
|
||||
IMaterialVar *m_AlphaVar;
|
||||
};
|
||||
|
||||
CAlphaMaterialProxy::CAlphaMaterialProxy()
|
||||
{
|
||||
m_AlphaVar = NULL;
|
||||
}
|
||||
|
||||
CAlphaMaterialProxy::~CAlphaMaterialProxy()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
bool CAlphaMaterialProxy::Init( IMaterial *pMaterial, KeyValues *pKeyValues )
|
||||
{
|
||||
bool foundVar;
|
||||
m_AlphaVar = pMaterial->FindVar( "$alpha", &foundVar, false );
|
||||
return foundVar;
|
||||
}
|
||||
|
||||
void CAlphaMaterialProxy::OnBind( C_BaseEntity *pEnt )
|
||||
{
|
||||
if (m_AlphaVar)
|
||||
{
|
||||
m_AlphaVar->SetFloatValue( pEnt->m_clrRender->a );
|
||||
}
|
||||
}
|
||||
|
||||
IMaterial *CAlphaMaterialProxy::GetMaterial()
|
||||
{
|
||||
if ( !m_AlphaVar )
|
||||
return NULL;
|
||||
|
||||
return m_AlphaVar->GetOwningMaterial();
|
||||
}
|
||||
|
||||
EXPOSE_INTERFACE( CAlphaMaterialProxy, IMaterialProxy, "Alpha" IMATERIAL_PROXY_INTERFACE_VERSION );
|
||||
@@ -0,0 +1,51 @@
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
// $NoKeywords: $
|
||||
//=============================================================================//
|
||||
#include "cbase.h"
|
||||
#include "baseanimatedtextureproxy.h"
|
||||
|
||||
// memdbgon must be the last include file in a .cpp file!!!
|
||||
#include "tier0/memdbgon.h"
|
||||
|
||||
class CAnimatedEntityTextureProxy : public CBaseAnimatedTextureProxy
|
||||
{
|
||||
public:
|
||||
CAnimatedEntityTextureProxy() {}
|
||||
virtual ~CAnimatedEntityTextureProxy() {}
|
||||
|
||||
virtual float GetAnimationStartTime( void* pBaseEntity );
|
||||
virtual void AnimationWrapped( void* pC_BaseEntity );
|
||||
|
||||
};
|
||||
|
||||
EXPOSE_INTERFACE( CAnimatedEntityTextureProxy, IMaterialProxy, "AnimatedEntityTexture" IMATERIAL_PROXY_INTERFACE_VERSION );
|
||||
|
||||
float CAnimatedEntityTextureProxy::GetAnimationStartTime( void* pArg )
|
||||
{
|
||||
IClientRenderable *pRend = (IClientRenderable *)pArg;
|
||||
if (!pRend)
|
||||
return 0.0f;
|
||||
|
||||
C_BaseEntity* pEntity = pRend->GetIClientUnknown()->GetBaseEntity();
|
||||
if (pEntity)
|
||||
{
|
||||
return pEntity->GetTextureAnimationStartTime();
|
||||
}
|
||||
return 0.0f;
|
||||
}
|
||||
|
||||
void CAnimatedEntityTextureProxy::AnimationWrapped( void* pArg )
|
||||
{
|
||||
IClientRenderable *pRend = (IClientRenderable *)pArg;
|
||||
if (!pRend)
|
||||
return;
|
||||
|
||||
C_BaseEntity* pEntity = pRend->GetIClientUnknown()->GetBaseEntity();
|
||||
if (pEntity)
|
||||
{
|
||||
pEntity->TextureAnimationWrapped();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,56 @@
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
//=============================================================================//
|
||||
|
||||
#include "cbase.h"
|
||||
#include "baseanimatedtextureproxy.h"
|
||||
|
||||
// memdbgon must be the last include file in a .cpp file!!!
|
||||
#include "tier0/memdbgon.h"
|
||||
|
||||
class CAnimatedOffsetTextureProxy : public CBaseAnimatedTextureProxy
|
||||
{
|
||||
public:
|
||||
CAnimatedOffsetTextureProxy() : m_flFrameOffset( 0.0f ) {}
|
||||
|
||||
virtual ~CAnimatedOffsetTextureProxy() {}
|
||||
|
||||
virtual float GetAnimationStartTime( void* pBaseEntity );
|
||||
virtual void OnBind( void *pBaseEntity );
|
||||
|
||||
protected:
|
||||
|
||||
float m_flFrameOffset;
|
||||
};
|
||||
|
||||
EXPOSE_INTERFACE( CAnimatedOffsetTextureProxy, IMaterialProxy, "AnimatedOffsetTexture" IMATERIAL_PROXY_INTERFACE_VERSION );
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
// Input : pArg -
|
||||
// Output : float
|
||||
//-----------------------------------------------------------------------------
|
||||
float CAnimatedOffsetTextureProxy::GetAnimationStartTime( void* pArg )
|
||||
{
|
||||
return m_flFrameOffset;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
// Input : *pBaseEntity -
|
||||
//-----------------------------------------------------------------------------
|
||||
void CAnimatedOffsetTextureProxy::OnBind( void *pBaseEntity )
|
||||
{
|
||||
C_BaseEntity* pEntity = (C_BaseEntity*)pBaseEntity;
|
||||
|
||||
if ( pEntity )
|
||||
{
|
||||
m_flFrameOffset = pEntity->GetTextureAnimationStartTime();
|
||||
}
|
||||
|
||||
// Call into the base class
|
||||
CBaseAnimatedTextureProxy::OnBind( pBaseEntity );
|
||||
}
|
||||
|
||||
@@ -0,0 +1,29 @@
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
// $NoKeywords: $
|
||||
//=============================================================================//
|
||||
#include "cbase.h"
|
||||
#include "baseanimatedtextureproxy.h"
|
||||
|
||||
// memdbgon must be the last include file in a .cpp file!!!
|
||||
#include "tier0/memdbgon.h"
|
||||
|
||||
class CAnimatedTextureProxy : public CBaseAnimatedTextureProxy
|
||||
{
|
||||
public:
|
||||
CAnimatedTextureProxy() {}
|
||||
virtual ~CAnimatedTextureProxy() {}
|
||||
virtual float GetAnimationStartTime( void* pBaseEntity );
|
||||
};
|
||||
|
||||
EXPOSE_INTERFACE( CAnimatedTextureProxy, IMaterialProxy, "AnimatedTexture" IMATERIAL_PROXY_INTERFACE_VERSION );
|
||||
|
||||
#pragma warning (disable : 4100)
|
||||
|
||||
float CAnimatedTextureProxy::GetAnimationStartTime( void* pBaseEntity )
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,213 @@
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
//=============================================================================//
|
||||
|
||||
#ifndef ANIMATIONLAYER_H
|
||||
#define ANIMATIONLAYER_H
|
||||
#ifdef _WIN32
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
|
||||
#include "rangecheckedvar.h"
|
||||
#include "lerp_functions.h"
|
||||
#include "networkvar.h"
|
||||
|
||||
class C_AnimationLayer
|
||||
{
|
||||
public:
|
||||
|
||||
// This allows the datatables to access private members.
|
||||
ALLOW_DATATABLES_PRIVATE_ACCESS();
|
||||
|
||||
C_AnimationLayer();
|
||||
void Reset();
|
||||
|
||||
void SetOrder( int order );
|
||||
|
||||
public:
|
||||
|
||||
bool IsActive( void );
|
||||
|
||||
CRangeCheckedVar<int, -1, 65535, 0> m_nSequence;
|
||||
CRangeCheckedVar<float, -2, 2, 0> m_flPrevCycle;
|
||||
CRangeCheckedVar<float, -5, 5, 0> m_flWeight;
|
||||
int m_nOrder;
|
||||
|
||||
// used for automatic crossfades between sequence changes
|
||||
CRangeCheckedVar<float, -50, 50, 1> m_flPlaybackRate;
|
||||
CRangeCheckedVar<float, -2, 2, 0> m_flCycle;
|
||||
|
||||
float GetFadeout( float flCurTime );
|
||||
|
||||
void BlendWeight();
|
||||
|
||||
float m_flLayerAnimtime;
|
||||
float m_flLayerFadeOuttime;
|
||||
|
||||
float m_flBlendIn;
|
||||
float m_flBlendOut;
|
||||
|
||||
bool m_bClientBlend;
|
||||
};
|
||||
#ifdef CLIENT_DLL
|
||||
#define CAnimationLayer C_AnimationLayer
|
||||
#endif
|
||||
|
||||
inline C_AnimationLayer::C_AnimationLayer()
|
||||
{
|
||||
Reset();
|
||||
}
|
||||
|
||||
inline void C_AnimationLayer::Reset()
|
||||
{
|
||||
m_nSequence = 0;
|
||||
m_flPrevCycle = 0;
|
||||
m_flWeight = 0;
|
||||
m_flPlaybackRate = 0;
|
||||
m_flCycle = 0;
|
||||
m_flLayerAnimtime = 0;
|
||||
m_flLayerFadeOuttime = 0;
|
||||
m_flBlendIn = 0;
|
||||
m_flBlendOut = 0;
|
||||
m_bClientBlend = false;
|
||||
}
|
||||
|
||||
|
||||
inline void C_AnimationLayer::SetOrder( int order )
|
||||
{
|
||||
m_nOrder = order;
|
||||
}
|
||||
|
||||
inline float C_AnimationLayer::GetFadeout( float flCurTime )
|
||||
{
|
||||
float s;
|
||||
|
||||
if (m_flLayerFadeOuttime <= 0.0f)
|
||||
{
|
||||
s = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
// blend in over 0.2 seconds
|
||||
s = 1.0 - (flCurTime - m_flLayerAnimtime) / m_flLayerFadeOuttime;
|
||||
if (s > 0 && s <= 1.0)
|
||||
{
|
||||
// do a nice spline curve
|
||||
s = 3 * s * s - 2 * s * s * s;
|
||||
}
|
||||
else if ( s > 1.0f )
|
||||
{
|
||||
// Shouldn't happen, but maybe curtime is behind animtime?
|
||||
s = 1.0f;
|
||||
}
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
|
||||
inline C_AnimationLayer LoopingLerp( float flPercent, C_AnimationLayer& from, C_AnimationLayer& to )
|
||||
{
|
||||
C_AnimationLayer output;
|
||||
|
||||
output.m_nSequence = to.m_nSequence;
|
||||
output.m_flCycle = LoopingLerp( flPercent, (float)from.m_flCycle, (float)to.m_flCycle );
|
||||
output.m_flPrevCycle = to.m_flPrevCycle;
|
||||
output.m_flWeight = Lerp( flPercent, from.m_flWeight, to.m_flWeight );
|
||||
output.m_nOrder = to.m_nOrder;
|
||||
|
||||
output.m_flLayerAnimtime = to.m_flLayerAnimtime;
|
||||
output.m_flLayerFadeOuttime = to.m_flLayerFadeOuttime;
|
||||
return output;
|
||||
}
|
||||
|
||||
inline C_AnimationLayer Lerp( float flPercent, const C_AnimationLayer& from, const C_AnimationLayer& to )
|
||||
{
|
||||
C_AnimationLayer output;
|
||||
|
||||
output.m_nSequence = to.m_nSequence;
|
||||
output.m_flCycle = Lerp( flPercent, from.m_flCycle, to.m_flCycle );
|
||||
output.m_flPrevCycle = to.m_flPrevCycle;
|
||||
output.m_flWeight = Lerp( flPercent, from.m_flWeight, to.m_flWeight );
|
||||
output.m_nOrder = to.m_nOrder;
|
||||
|
||||
output.m_flLayerAnimtime = to.m_flLayerAnimtime;
|
||||
output.m_flLayerFadeOuttime = to.m_flLayerFadeOuttime;
|
||||
return output;
|
||||
}
|
||||
|
||||
inline C_AnimationLayer LoopingLerp_Hermite( float flPercent, C_AnimationLayer& prev, C_AnimationLayer& from, C_AnimationLayer& to )
|
||||
{
|
||||
C_AnimationLayer output;
|
||||
|
||||
output.m_nSequence = to.m_nSequence;
|
||||
output.m_flCycle = LoopingLerp_Hermite( flPercent, (float)prev.m_flCycle, (float)from.m_flCycle, (float)to.m_flCycle );
|
||||
output.m_flPrevCycle = to.m_flPrevCycle;
|
||||
output.m_flWeight = Lerp( flPercent, from.m_flWeight, to.m_flWeight );
|
||||
output.m_nOrder = to.m_nOrder;
|
||||
|
||||
output.m_flLayerAnimtime = to.m_flLayerAnimtime;
|
||||
output.m_flLayerFadeOuttime = to.m_flLayerFadeOuttime;
|
||||
return output;
|
||||
}
|
||||
|
||||
// YWB: Specialization for interpolating euler angles via quaternions...
|
||||
inline C_AnimationLayer Lerp_Hermite( float flPercent, const C_AnimationLayer& prev, const C_AnimationLayer& from, const C_AnimationLayer& to )
|
||||
{
|
||||
C_AnimationLayer output;
|
||||
|
||||
output.m_nSequence = to.m_nSequence;
|
||||
output.m_flCycle = Lerp_Hermite( flPercent, prev.m_flCycle, from.m_flCycle, to.m_flCycle );
|
||||
output.m_flPrevCycle = to.m_flPrevCycle;
|
||||
output.m_flWeight = Lerp( flPercent, from.m_flWeight, to.m_flWeight );
|
||||
output.m_nOrder = to.m_nOrder;
|
||||
|
||||
output.m_flLayerAnimtime = to.m_flLayerAnimtime;
|
||||
output.m_flLayerFadeOuttime = to.m_flLayerFadeOuttime;
|
||||
return output;
|
||||
}
|
||||
|
||||
inline void Lerp_Clamp( C_AnimationLayer &val )
|
||||
{
|
||||
Lerp_Clamp( val.m_nSequence );
|
||||
Lerp_Clamp( val.m_flCycle );
|
||||
Lerp_Clamp( val.m_flPrevCycle );
|
||||
Lerp_Clamp( val.m_flWeight );
|
||||
Lerp_Clamp( val.m_nOrder );
|
||||
Lerp_Clamp( val.m_flLayerAnimtime );
|
||||
Lerp_Clamp( val.m_flLayerFadeOuttime );
|
||||
}
|
||||
|
||||
inline void C_AnimationLayer::BlendWeight()
|
||||
{
|
||||
if ( !m_bClientBlend )
|
||||
return;
|
||||
|
||||
m_flWeight = 1;
|
||||
|
||||
// blend in?
|
||||
if ( m_flBlendIn != 0.0f )
|
||||
{
|
||||
if (m_flCycle < m_flBlendIn)
|
||||
{
|
||||
m_flWeight = m_flCycle / m_flBlendIn;
|
||||
}
|
||||
}
|
||||
|
||||
// blend out?
|
||||
if ( m_flBlendOut != 0.0f )
|
||||
{
|
||||
if (m_flCycle > 1.0 - m_flBlendOut)
|
||||
{
|
||||
m_flWeight = (1.0 - m_flCycle) / m_flBlendOut;
|
||||
}
|
||||
}
|
||||
|
||||
m_flWeight = 3.0 * m_flWeight * m_flWeight - 2.0 * m_flWeight * m_flWeight * m_flWeight;
|
||||
if (m_nSequence == 0)
|
||||
m_flWeight = 0;
|
||||
}
|
||||
|
||||
#endif // ANIMATIONLAYER_H
|
||||
@@ -0,0 +1,148 @@
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
// $NoKeywords: $
|
||||
//=============================================================================//
|
||||
#include "cbase.h"
|
||||
#include "baseanimatedtextureproxy.h"
|
||||
#include "materialsystem/imaterial.h"
|
||||
#include "materialsystem/imaterialvar.h"
|
||||
#include "materialsystem/itexture.h"
|
||||
#include "tier1/KeyValues.h"
|
||||
#include "toolframework_client.h"
|
||||
#include "tier0/minidump.h"
|
||||
#include "tier0/stacktools.h"
|
||||
|
||||
// memdbgon must be the last include file in a .cpp file!!!
|
||||
#include "tier0/memdbgon.h"
|
||||
|
||||
// forward declarations
|
||||
void ToolFramework_RecordMaterialParams( IMaterial *pMaterial );
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Constructor, destructor:
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
CBaseAnimatedTextureProxy::CBaseAnimatedTextureProxy()
|
||||
{
|
||||
Cleanup();
|
||||
}
|
||||
|
||||
CBaseAnimatedTextureProxy::~CBaseAnimatedTextureProxy()
|
||||
{
|
||||
Cleanup();
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Initialization, shutdown
|
||||
//-----------------------------------------------------------------------------
|
||||
bool CBaseAnimatedTextureProxy::Init( IMaterial *pMaterial, KeyValues *pKeyValues )
|
||||
{
|
||||
char const* pAnimatedTextureVarName = pKeyValues->GetString( "animatedTextureVar" );
|
||||
|
||||
if( pAnimatedTextureVarName )
|
||||
{
|
||||
bool foundVar;
|
||||
|
||||
m_AnimatedTextureVar = pMaterial->FindVar( pAnimatedTextureVarName, &foundVar, false );
|
||||
if( foundVar )
|
||||
{
|
||||
char const* pAnimatedTextureFrameNumVarName = pKeyValues->GetString( "animatedTextureFrameNumVar" );
|
||||
|
||||
if( pAnimatedTextureFrameNumVarName )
|
||||
{
|
||||
m_AnimatedTextureFrameNumVar = pMaterial->FindVar( pAnimatedTextureFrameNumVarName, &foundVar, false );
|
||||
|
||||
if( foundVar )
|
||||
{
|
||||
m_FrameRate = pKeyValues->GetFloat( "animatedTextureFrameRate", 15 );
|
||||
m_WrapAnimation = !pKeyValues->GetInt( "animationNoWrap", 0 );
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Error - null out pointers.
|
||||
Cleanup();
|
||||
return false;
|
||||
}
|
||||
|
||||
void CBaseAnimatedTextureProxy::Cleanup()
|
||||
{
|
||||
m_AnimatedTextureVar = NULL;
|
||||
m_AnimatedTextureFrameNumVar = NULL;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Does the dirty deed
|
||||
//-----------------------------------------------------------------------------
|
||||
void CBaseAnimatedTextureProxy::OnBind( void *pEntity )
|
||||
{
|
||||
Assert ( m_AnimatedTextureVar );
|
||||
|
||||
if( m_AnimatedTextureVar->GetType() != MATERIAL_VAR_TYPE_TEXTURE )
|
||||
{
|
||||
return;
|
||||
}
|
||||
ITexture *pTexture;
|
||||
pTexture = m_AnimatedTextureVar->GetTextureValue();
|
||||
int numFrames = pTexture->GetNumAnimationFrames();
|
||||
|
||||
if ( numFrames <= 0 )
|
||||
{
|
||||
Assert( !"0 frames in material calling animated texture proxy" );
|
||||
return;
|
||||
}
|
||||
|
||||
// NOTE: Must not use relative time based methods here
|
||||
// because the bind proxy can be called many times per frame.
|
||||
// Prevent multiple Wrap callbacks to be sent for no wrap mode
|
||||
float startTime = GetAnimationStartTime(pEntity);
|
||||
float deltaTime = gpGlobals->curtime - startTime;
|
||||
float prevTime = deltaTime - gpGlobals->frametime;
|
||||
|
||||
// Clamp..
|
||||
if (deltaTime < 0.0f)
|
||||
deltaTime = 0.0f;
|
||||
if (prevTime < 0.0f)
|
||||
prevTime = 0.0f;
|
||||
|
||||
float frame = m_FrameRate * deltaTime;
|
||||
float prevFrame = m_FrameRate * prevTime;
|
||||
|
||||
int intFrame = ((int)frame) % numFrames;
|
||||
int intPrevFrame = ((int)prevFrame) % numFrames;
|
||||
|
||||
// Report wrap situation...
|
||||
if (intPrevFrame > intFrame)
|
||||
{
|
||||
if (m_WrapAnimation)
|
||||
{
|
||||
AnimationWrapped( pEntity );
|
||||
}
|
||||
else
|
||||
{
|
||||
// Only sent the wrapped message once.
|
||||
// when we're in non-wrapping mode
|
||||
if (prevFrame < numFrames)
|
||||
AnimationWrapped( pEntity );
|
||||
intFrame = numFrames - 1;
|
||||
}
|
||||
}
|
||||
|
||||
m_AnimatedTextureFrameNumVar->SetIntValue( intFrame );
|
||||
|
||||
if ( ToolsEnabled() )
|
||||
{
|
||||
ToolFramework_RecordMaterialParams( GetMaterial() );
|
||||
}
|
||||
}
|
||||
|
||||
IMaterial *CBaseAnimatedTextureProxy::GetMaterial()
|
||||
{
|
||||
return m_AnimatedTextureVar->GetOwningMaterial();
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
// $NoKeywords: $
|
||||
//=============================================================================//
|
||||
|
||||
#ifndef BASEANIMATEDTEXTUREPROXY
|
||||
#define BASEANIMATEDTEXTUREPROXY
|
||||
|
||||
#include "materialsystem/imaterialproxy.h"
|
||||
|
||||
class IMaterial;
|
||||
class IMaterialVar;
|
||||
|
||||
#pragma warning (disable : 4100)
|
||||
|
||||
class CBaseAnimatedTextureProxy : public IMaterialProxy
|
||||
{
|
||||
public:
|
||||
CBaseAnimatedTextureProxy();
|
||||
virtual ~CBaseAnimatedTextureProxy();
|
||||
|
||||
virtual bool Init( IMaterial *pMaterial, KeyValues *pKeyValues );
|
||||
virtual void OnBind( void *pC_BaseEntity );
|
||||
virtual void Release( void ) { delete this; }
|
||||
virtual IMaterial *GetMaterial();
|
||||
|
||||
protected:
|
||||
// derived classes must implement this; it returns the time
|
||||
// that the animation began
|
||||
virtual float GetAnimationStartTime( void* pBaseEntity ) = 0;
|
||||
|
||||
// Derived classes may implement this if they choose;
|
||||
// this method is called whenever the animation wraps...
|
||||
virtual void AnimationWrapped( void* pBaseEntity ) {}
|
||||
|
||||
protected:
|
||||
void Cleanup();
|
||||
|
||||
IMaterialVar *m_AnimatedTextureVar;
|
||||
IMaterialVar *m_AnimatedTextureFrameNumVar;
|
||||
float m_FrameRate;
|
||||
bool m_WrapAnimation;
|
||||
};
|
||||
|
||||
#endif // BASEANIMATEDTEXTUREPROXY
|
||||
@@ -0,0 +1,78 @@
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose: Implementation for CBaseClientRenderTargets class.
|
||||
// Provides Init functions for common render textures used by the engine.
|
||||
// Mod makers can inherit from this class, and call the Create functions for
|
||||
// only the render textures the want for their mod.
|
||||
//=============================================================================//
|
||||
|
||||
#include "cbase.h"
|
||||
#include "baseclientrendertargets.h" // header
|
||||
#include "materialsystem/imaterialsystemhardwareconfig.h" // Hardware config checks
|
||||
#include "tier0/icommandline.h"
|
||||
|
||||
ITexture* CBaseClientRenderTargets::CreateWaterReflectionTexture( IMaterialSystem* pMaterialSystem, int iSize )
|
||||
{
|
||||
return pMaterialSystem->CreateNamedRenderTargetTextureEx2(
|
||||
"_rt_WaterReflection",
|
||||
iSize, iSize, RT_SIZE_PICMIP,
|
||||
pMaterialSystem->GetBackBufferFormat(),
|
||||
MATERIAL_RT_DEPTH_SHARED,
|
||||
TEXTUREFLAGS_CLAMPS | TEXTUREFLAGS_CLAMPT,
|
||||
CREATERENDERTARGETFLAGS_HDR );
|
||||
}
|
||||
|
||||
ITexture* CBaseClientRenderTargets::CreateWaterRefractionTexture( IMaterialSystem* pMaterialSystem, int iSize )
|
||||
{
|
||||
return pMaterialSystem->CreateNamedRenderTargetTextureEx2(
|
||||
"_rt_WaterRefraction",
|
||||
iSize, iSize, RT_SIZE_PICMIP,
|
||||
// This is different than reflection because it has to have alpha for fog factor.
|
||||
IMAGE_FORMAT_RGBA8888,
|
||||
MATERIAL_RT_DEPTH_SHARED,
|
||||
TEXTUREFLAGS_CLAMPS | TEXTUREFLAGS_CLAMPT,
|
||||
CREATERENDERTARGETFLAGS_HDR );
|
||||
}
|
||||
|
||||
ITexture* CBaseClientRenderTargets::CreateCameraTexture( IMaterialSystem* pMaterialSystem, int iSize )
|
||||
{
|
||||
return pMaterialSystem->CreateNamedRenderTargetTextureEx2(
|
||||
"_rt_Camera",
|
||||
iSize, iSize, RT_SIZE_DEFAULT,
|
||||
pMaterialSystem->GetBackBufferFormat(),
|
||||
MATERIAL_RT_DEPTH_SHARED,
|
||||
0,
|
||||
CREATERENDERTARGETFLAGS_HDR );
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Called by the engine in material system init and shutdown.
|
||||
// Clients should override this in their inherited version, but the base
|
||||
// is to init all standard render targets for use.
|
||||
// Input : pMaterialSystem - the engine's material system (our singleton is not yet inited at the time this is called)
|
||||
// pHardwareConfig - the user hardware config, useful for conditional render target setup
|
||||
//-----------------------------------------------------------------------------
|
||||
void CBaseClientRenderTargets::InitClientRenderTargets( IMaterialSystem* pMaterialSystem, IMaterialSystemHardwareConfig* pHardwareConfig, int iWaterTextureSize, int iCameraTextureSize )
|
||||
{
|
||||
// Water effects
|
||||
m_WaterReflectionTexture.Init( CreateWaterReflectionTexture( pMaterialSystem, iWaterTextureSize ) );
|
||||
m_WaterRefractionTexture.Init( CreateWaterRefractionTexture( pMaterialSystem, iWaterTextureSize ) );
|
||||
|
||||
// Monitors
|
||||
m_CameraTexture.Init( CreateCameraTexture( pMaterialSystem, iCameraTextureSize ) );
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Shut down each CTextureReference we created in InitClientRenderTargets.
|
||||
// Called by the engine in material system shutdown.
|
||||
// Input : -
|
||||
//-----------------------------------------------------------------------------
|
||||
void CBaseClientRenderTargets::ShutdownClientRenderTargets()
|
||||
{
|
||||
// Water effects
|
||||
m_WaterReflectionTexture.Shutdown();
|
||||
m_WaterRefractionTexture.Shutdown();
|
||||
|
||||
// Monitors
|
||||
m_CameraTexture.Shutdown();
|
||||
}
|
||||
@@ -0,0 +1,64 @@
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose: Has init functions for all the standard render targets used by most games.
|
||||
// Mods who wish to make their own render targets can inherit from this class
|
||||
// and in the 'InitClientRenderTargets' interface called by the engine, set up
|
||||
// their own render targets as well as calling the init functions for various
|
||||
// common render targets provided by this class.
|
||||
//
|
||||
// Note: Unless the client defines a singleton interface by inheriting from
|
||||
// this class and exposing the singleton instance, these init and shutdown
|
||||
// functions WILL NOT be called by the engine.
|
||||
//
|
||||
//
|
||||
// $Workfile: $
|
||||
// $Date: $
|
||||
// $NoKeywords: $
|
||||
//=============================================================================//
|
||||
#ifndef CLIENTRENDERTARTETS_H_
|
||||
#define CLIENTRENDERTARTETS_H_
|
||||
#ifdef _WIN32
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
#include "game/client/iclientrendertargets.h" // base class with interfaces called by the engine
|
||||
#include "materialsystem/imaterialsystem.h" // for material system classes and interfaces
|
||||
|
||||
|
||||
// Externs
|
||||
class IMaterialSystem;
|
||||
class IMaterialSystemHardwareConfig;
|
||||
|
||||
class CBaseClientRenderTargets : public IClientRenderTargets
|
||||
{
|
||||
// no networked vars
|
||||
DECLARE_CLASS_GAMEROOT( CBaseClientRenderTargets, IClientRenderTargets );
|
||||
public:
|
||||
// Interface called by engine during material system startup.
|
||||
virtual void InitClientRenderTargets ( IMaterialSystem* pMaterialSystem, IMaterialSystemHardwareConfig* pHardwareConfig, int iWaterTextureSize = 1024, int iCameraTextureSize = 256 );
|
||||
// Shutdown all custom render targets here.
|
||||
virtual void ShutdownClientRenderTargets ( void );
|
||||
|
||||
protected:
|
||||
|
||||
// Standard render textures used by most mods-- Classes inheriting from
|
||||
// this can choose to init these or not depending on their needs.
|
||||
|
||||
// For reflective and refracting water
|
||||
CTextureReference m_WaterReflectionTexture;
|
||||
CTextureReference m_WaterRefractionTexture;
|
||||
|
||||
// Used for monitors
|
||||
CTextureReference m_CameraTexture;
|
||||
|
||||
// Used for the HUD in stereo and head tracking mode
|
||||
CTextureReference m_UITexture;
|
||||
|
||||
// Init functions for the common render targets
|
||||
ITexture* CreateWaterReflectionTexture( IMaterialSystem* pMaterialSystem, int iSize = 1024 );
|
||||
ITexture* CreateWaterRefractionTexture( IMaterialSystem* pMaterialSystem, int iSize = 1024 );
|
||||
ITexture* CreateCameraTexture( IMaterialSystem* pMaterialSystem, int iSize = 256 );
|
||||
|
||||
};
|
||||
|
||||
#endif // CLIENTRENDERTARTETS_H_
|
||||
@@ -0,0 +1,94 @@
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose: Base presence implementation for PC
|
||||
//
|
||||
//=====================================================================================//
|
||||
|
||||
#include "cbase.h"
|
||||
#include "basepresence.h"
|
||||
|
||||
// memdbgon must be the last include file in a .cpp file!!!
|
||||
#include "tier0/memdbgon.h"
|
||||
|
||||
// Default global singleton. Mods should override this.
|
||||
static CBasePresence s_basePresence;
|
||||
IPresence *presence = NULL;
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Steam version of Rich Presence is a WIP, so PC implementation is stubbed for now.
|
||||
//-----------------------------------------------------------------------------
|
||||
bool CBasePresence::Init( void )
|
||||
{
|
||||
if ( !presence )
|
||||
{
|
||||
// Mod didn't override, default to base implementation
|
||||
presence = &s_basePresence;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
void CBasePresence::Shutdown( void )
|
||||
{
|
||||
// TODO: Implement for PC
|
||||
}
|
||||
void CBasePresence::Update( float frametime )
|
||||
{
|
||||
// TODO: Implement for PC
|
||||
}
|
||||
void CBasePresence::UserSetContext( unsigned int nUserIndex, unsigned int nContextId, unsigned int nContextValue, bool bAsync )
|
||||
{
|
||||
// TODO: Implement for PC
|
||||
}
|
||||
void CBasePresence::UserSetProperty( unsigned int nUserIndex, unsigned int nPropertyId, unsigned int nBytes, const void *pvValue, bool bAsync )
|
||||
{
|
||||
// TODO: Implement for PC
|
||||
}
|
||||
void CBasePresence::SetupGameProperties( CUtlVector< XUSER_CONTEXT > &contexts, CUtlVector< XUSER_PROPERTY > &properties )
|
||||
{
|
||||
// TODO: Implement for PC
|
||||
}
|
||||
unsigned int CBasePresence::GetPresenceID( const char *pIDName )
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
const char *CBasePresence::GetPropertyIdString( const uint id )
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
void CBasePresence::GetPropertyDisplayString( uint id, uint value, char *pOutput, int nBytes )
|
||||
{
|
||||
}
|
||||
void CBasePresence::StartStatsReporting( HANDLE handle, bool bArbitrated )
|
||||
{
|
||||
}
|
||||
void CBasePresence::SetStat( uint iPropertyId, int iPropertyValue, int dataType )
|
||||
{
|
||||
}
|
||||
void CBasePresence::UploadStats()
|
||||
{
|
||||
}
|
||||
|
||||
//---------------------------------------------------------
|
||||
// Debug support
|
||||
//---------------------------------------------------------
|
||||
void CBasePresence::DebugUserSetContext( const CCommand &args )
|
||||
{
|
||||
if ( args.ArgC() == 3 )
|
||||
{
|
||||
UserSetContext( 0, atoi( args.Arg( 1 ) ), atoi( args.Arg( 2 ) ) );
|
||||
}
|
||||
else
|
||||
{
|
||||
Warning( "user_context <context id> <context value>\n" );
|
||||
}
|
||||
}
|
||||
void CBasePresence::DebugUserSetProperty( const CCommand &args )
|
||||
{
|
||||
if ( args.ArgC() == 3 )
|
||||
{
|
||||
UserSetProperty( 0, strtoul( args.Arg( 1 ), NULL, 0 ), sizeof(int), args.Arg( 2 ) );
|
||||
}
|
||||
else
|
||||
{
|
||||
Warning( "user_property <property id> <property value>\n" );
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose: Base implementation of the IPresence interface
|
||||
//
|
||||
//=============================================================================
|
||||
|
||||
#ifndef BASEPRESENCE_H
|
||||
#define BASEPRESENCE_H
|
||||
#ifdef _WIN32
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
#include "ipresence.h"
|
||||
#include "igamesystem.h"
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Common implementation for setting user contexts and properties.
|
||||
// Each client should inherit from this to implement mod-specific presence info.
|
||||
//-----------------------------------------------------------------------------
|
||||
class CBasePresence : public IPresence, public CAutoGameSystemPerFrame
|
||||
{
|
||||
public:
|
||||
// CBaseGameSystemPerFrame overrides
|
||||
virtual bool Init( void );
|
||||
virtual void Shutdown( void );
|
||||
virtual void Update( float frametime );
|
||||
virtual char const *Name( void ) { return "presence"; }
|
||||
|
||||
// IPresence Interface
|
||||
virtual void UserSetContext( unsigned int nUserIndex, unsigned int nContextId, unsigned int nContextValue, bool bAsync = false );
|
||||
virtual void UserSetProperty( unsigned int nUserIndex, unsigned int nPropertyId, unsigned int nBytes, const void *pvValue, bool bAsync = false );
|
||||
virtual void SetupGameProperties( CUtlVector< XUSER_CONTEXT > &contexts, CUtlVector< XUSER_PROPERTY > &properties );
|
||||
virtual uint GetPresenceID( const char *pIdName );
|
||||
virtual void GetPropertyDisplayString( uint id, uint value, char *pOutput, int nBytes );
|
||||
virtual const char *GetPropertyIdString( const uint id );
|
||||
|
||||
// Stats reporting
|
||||
virtual void StartStatsReporting( HANDLE handle, bool bArbitrated );
|
||||
virtual void SetStat( uint iPropertyId, int iPropertyValue, int dataType );
|
||||
virtual void UploadStats();
|
||||
|
||||
protected:
|
||||
bool m_bArbitrated;
|
||||
bool m_bReportingStats;
|
||||
HANDLE m_hSession;
|
||||
CUtlVector< XUSER_PROPERTY > m_PlayerStats;
|
||||
|
||||
//---------------------------------------------------------
|
||||
// Debug support
|
||||
//---------------------------------------------------------
|
||||
CON_COMMAND_MEMBER_F( CBasePresence, "user_context", DebugUserSetContext, "Set a Rich Presence Context: user_context <context id> <context value>", 0 )
|
||||
CON_COMMAND_MEMBER_F( CBasePresence, "user_property", DebugUserSetProperty, "Set a Rich Presence Property: user_property <property id>", 0 )
|
||||
};
|
||||
|
||||
#endif // BASEPRESENCE_H
|
||||
@@ -0,0 +1,167 @@
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose: Base rich presence implementation for Xbox360
|
||||
//
|
||||
//=====================================================================================//
|
||||
|
||||
#include "cbase.h"
|
||||
#include "basepresence.h"
|
||||
#include "cdll_client_int.h"
|
||||
#include "ixboxsystem.h"
|
||||
|
||||
// memdbgon must be the last include file in a .cpp file!!!
|
||||
#include "tier0/memdbgon.h"
|
||||
|
||||
// Default global instance. Mods should override this.
|
||||
static CBasePresence s_basePresence;
|
||||
IPresence *presence = NULL;
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Init
|
||||
//-----------------------------------------------------------------------------
|
||||
bool CBasePresence::Init( void )
|
||||
{
|
||||
if ( !presence )
|
||||
{
|
||||
// Mod didn't override, default to base implementation
|
||||
presence = &s_basePresence;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Shutdown
|
||||
//-----------------------------------------------------------------------------
|
||||
void CBasePresence::Shutdown( void )
|
||||
{
|
||||
// Do nothing
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Per-frame update
|
||||
//-----------------------------------------------------------------------------
|
||||
void CBasePresence::Update( float frametime )
|
||||
{
|
||||
// Do nothing
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Contexts are strings that describe the current state of the game.
|
||||
//-----------------------------------------------------------------------------
|
||||
void CBasePresence::UserSetContext( unsigned int nUserIndex, unsigned int nContextId, unsigned int nContextValue, bool bAsync )
|
||||
{
|
||||
if ( !xboxsystem->UserSetContext( nUserIndex, nContextId, nContextValue, bAsync ) )
|
||||
{
|
||||
Warning( "CBasePresence: UserSetContext failed.\n" );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Properties are (usually) numeric values that can be insterted into context strings.
|
||||
//-----------------------------------------------------------------------------
|
||||
void CBasePresence::UserSetProperty( unsigned int nUserIndex, unsigned int nPropertyId, unsigned int nBytes, const void *pvValue, bool bAsync )
|
||||
{
|
||||
if ( !xboxsystem->UserSetProperty( nUserIndex, nPropertyId, nBytes, pvValue, bAsync ) )
|
||||
{
|
||||
Warning( "CBasePresence: UserSetProperty failed.\n" );
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Get game session properties from matchmaking.
|
||||
//-----------------------------------------------------------------------------
|
||||
void CBasePresence::SetupGameProperties( CUtlVector< XUSER_CONTEXT > &contexts, CUtlVector< XUSER_PROPERTY > &properties )
|
||||
{
|
||||
Assert( 0 );
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Convert a string to a presence ID.
|
||||
//-----------------------------------------------------------------------------
|
||||
uint CBasePresence::GetPresenceID( const char *pIdName )
|
||||
{
|
||||
Assert( 0 );
|
||||
return 0;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Convert a presence ID to a string.
|
||||
//-----------------------------------------------------------------------------
|
||||
const char *CBasePresence::GetPropertyIdString( const uint id )
|
||||
{
|
||||
Assert( 0 );
|
||||
return NULL;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Get display string for a game property.
|
||||
//-----------------------------------------------------------------------------
|
||||
void CBasePresence::GetPropertyDisplayString( uint id, uint value, char *pOutput, int nBytes )
|
||||
{
|
||||
Assert( 0 );
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Set up for reporting stats to Live.
|
||||
//-----------------------------------------------------------------------------
|
||||
void CBasePresence::StartStatsReporting( HANDLE handle, bool bArbitrated )
|
||||
{
|
||||
m_bArbitrated = bArbitrated;
|
||||
m_hSession = handle;
|
||||
m_bReportingStats = true;
|
||||
m_PlayerStats.RemoveAll();
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Set a specific stat property.
|
||||
//-----------------------------------------------------------------------------
|
||||
void CBasePresence::SetStat( uint iPropertyId, int iPropertyValue, int dataType )
|
||||
{
|
||||
if ( m_bReportingStats )
|
||||
{
|
||||
XUSER_PROPERTY prop;
|
||||
prop.dwPropertyId = iPropertyId;
|
||||
prop.value.nData = iPropertyValue;
|
||||
prop.value.type = dataType;
|
||||
m_PlayerStats.AddToTail( prop );
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Upload the stats to Live.
|
||||
//-----------------------------------------------------------------------------
|
||||
void CBasePresence::UploadStats()
|
||||
{
|
||||
Assert( 0 );
|
||||
}
|
||||
|
||||
//---------------------------------------------------------
|
||||
// Debug support
|
||||
//---------------------------------------------------------
|
||||
void CBasePresence::DebugUserSetContext( const CCommand &args )
|
||||
{
|
||||
if ( args.ArgC() == 3 )
|
||||
{
|
||||
UserSetContext( XBX_GetPrimaryUserId(), atoi( args.Arg( 1 ) ), atoi( args.Arg( 2 ) ) );
|
||||
}
|
||||
else
|
||||
{
|
||||
Warning( "user_context <context id> <context value>\n" );
|
||||
}
|
||||
}
|
||||
void CBasePresence::DebugUserSetProperty( const CCommand &args )
|
||||
{
|
||||
if ( args.ArgC() == 3 )
|
||||
{
|
||||
int value = atoi( args.Arg( 2 ) );
|
||||
UserSetProperty( XBX_GetPrimaryUserId(), strtoul( args.Arg( 1 ), NULL, 0 ), sizeof(int), &value );
|
||||
}
|
||||
else
|
||||
{
|
||||
Warning( "user_property <property id> <property value>\n" );
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,173 @@
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
// $NoKeywords: $
|
||||
//===========================================================================//
|
||||
#if !defined( BEAMDRAW_H )
|
||||
#define BEAMDRAW_H
|
||||
#ifdef _WIN32
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
#include "materialsystem/imaterial.h"
|
||||
#include "materialsystem/imesh.h"
|
||||
#include "mathlib/vector.h"
|
||||
#include "tier2/beamsegdraw.h"
|
||||
#include "c_pixel_visibility.h"
|
||||
|
||||
#define NOISE_DIVISIONS 128
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Forward declarations
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
struct model_t;
|
||||
struct BeamTrail_t;
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Beams fill out this data structure
|
||||
// This is also used for rendering
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
class Beam_t : public CDefaultClientRenderable
|
||||
{
|
||||
public:
|
||||
Beam_t();
|
||||
|
||||
// Methods of IClientRenderable
|
||||
virtual const Vector& GetRenderOrigin( void );
|
||||
virtual const QAngle& GetRenderAngles( void );
|
||||
virtual const matrix3x4_t &RenderableToWorldTransform();
|
||||
virtual void GetRenderBounds( Vector& mins, Vector& maxs );
|
||||
virtual bool ShouldDraw( void );
|
||||
virtual bool IsTransparent( void );
|
||||
virtual int DrawModel( int flags );
|
||||
virtual void ComputeFxBlend( );
|
||||
virtual int GetFxBlend( );
|
||||
|
||||
// Resets the beam state
|
||||
void Reset();
|
||||
|
||||
// Method to computing the bounding box
|
||||
void ComputeBounds();
|
||||
|
||||
// Bounding box...
|
||||
Vector m_Mins;
|
||||
Vector m_Maxs;
|
||||
pixelvis_handle_t *m_queryHandleHalo;
|
||||
float m_haloProxySize;
|
||||
|
||||
// Data is below..
|
||||
|
||||
// Next beam in list
|
||||
Beam_t* next;
|
||||
|
||||
// Type of beam
|
||||
int type;
|
||||
int flags;
|
||||
|
||||
// Control points for the beam
|
||||
int numAttachments;
|
||||
Vector attachment[MAX_BEAM_ENTS];
|
||||
Vector delta;
|
||||
|
||||
// 0 .. 1 over lifetime of beam
|
||||
float t;
|
||||
float freq;
|
||||
|
||||
// Time when beam should die
|
||||
float die;
|
||||
float width;
|
||||
float endWidth;
|
||||
float fadeLength;
|
||||
float amplitude;
|
||||
float life;
|
||||
|
||||
// Color
|
||||
float r, g, b;
|
||||
float brightness;
|
||||
|
||||
// Speed
|
||||
float speed;
|
||||
|
||||
// Animation
|
||||
float frameRate;
|
||||
float frame;
|
||||
int segments;
|
||||
|
||||
// Attachment entities for the beam
|
||||
EHANDLE entity[MAX_BEAM_ENTS];
|
||||
int attachmentIndex[MAX_BEAM_ENTS];
|
||||
|
||||
// Model info
|
||||
int modelIndex;
|
||||
int haloIndex;
|
||||
|
||||
float haloScale;
|
||||
int frameCount;
|
||||
|
||||
float rgNoise[NOISE_DIVISIONS+1];
|
||||
|
||||
// Popcorn trail for beam follows to use
|
||||
BeamTrail_t* trail;
|
||||
|
||||
// for TE_BEAMRINGPOINT
|
||||
float start_radius;
|
||||
float end_radius;
|
||||
|
||||
// for FBEAM_ONLYNOISEONCE
|
||||
bool m_bCalculatedNoise;
|
||||
|
||||
float m_flHDRColorScale;
|
||||
|
||||
#ifdef PORTAL
|
||||
bool m_bDrawInMainRender;
|
||||
bool m_bDrawInPortalRender;
|
||||
#endif //#ifdef PORTAL
|
||||
};
|
||||
|
||||
|
||||
int ScreenTransform( const Vector& point, Vector& screen );
|
||||
|
||||
void DrawSegs( int noise_divisions, float *prgNoise, const model_t* spritemodel,
|
||||
float frame, int rendermode, const Vector& source, const Vector& delta,
|
||||
float startWidth, float endWidth, float scale, float freq, float speed, int segments,
|
||||
int flags, float* color, float fadeLength, float flHDRColorScale = 1.0f );
|
||||
void DrawTeslaSegs( int noise_divisions, float *prgNoise, const model_t* spritemodel,
|
||||
float frame, int rendermode, const Vector& source, const Vector& delta,
|
||||
float startWidth, float endWidth, float scale, float freq, float speed, int segments,
|
||||
int flags, float* color, float fadeLength, float flHDRColorScale = 1.0f );
|
||||
void DrawSplineSegs( int noise_divisions, float *prgNoise,
|
||||
const model_t* beammodel, const model_t* halomodel, float flHaloScale,
|
||||
float frame, int rendermode, int numAttachments, Vector* attachment,
|
||||
float startWidth, float endWidth, float scale, float freq, float speed, int segments,
|
||||
int flags, float* color, float fadeLength, float flHDRColorScale = 1.0f );
|
||||
void DrawHalo(IMaterial* pMaterial, const Vector& source, float scale, float const* color, float flHDRColorScale = 1.0f );
|
||||
void BeamDrawHalo( const model_t* spritemodel, float frame, int rendermode, const Vector& source,
|
||||
float scale, float* color, float flHDRColorScale = 1.0f );
|
||||
void DrawDisk( int noise_divisions, float *prgNoise, const model_t* spritemodel,
|
||||
float frame, int rendermode, const Vector& source, const Vector& delta,
|
||||
float width, float scale, float freq, float speed,
|
||||
int segments, float* color, float flHDRColorScale = 1.0f );
|
||||
void DrawCylinder( int noise_divisions, float *prgNoise, const model_t* spritemodel,
|
||||
float frame, int rendermode, const Vector& source,
|
||||
const Vector& delta, float width, float scale, float freq,
|
||||
float speed, int segments, float* color, float flHDRColorScale = 1.0f );
|
||||
void DrawRing( int noise_divisions, float *prgNoise, void (*pfnNoise)( float *noise, int divs, float scale ),
|
||||
const model_t* spritemodel, float frame, int rendermode,
|
||||
const Vector& source, const Vector& delta, float width, float amplitude,
|
||||
float freq, float speed, int segments, float* color, float flHDRColorScale = 1.0f );
|
||||
void DrawBeamFollow( const model_t* spritemodel, BeamTrail_t* pHead, int frame, int rendermode, Vector& delta,
|
||||
Vector& screen, Vector& screenLast, float die, const Vector& source,
|
||||
int flags, float width, float amplitude, float freq, float* color, float flHDRColorScale = 1.0f );
|
||||
|
||||
void DrawBeamQuadratic( const Vector &start, const Vector &control, const Vector &end, float width, const Vector &color, float scrollOffset, float flHDRColorScale = 1.0f );
|
||||
class CEngineSprite *Draw_SetSpriteTexture( const model_t *pSpriteModel, int frame, int rendermode );
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Assumes the material has already been bound
|
||||
//-----------------------------------------------------------------------------
|
||||
void DrawSprite( const Vector &vecOrigin, float flWidth, float flHeight, color32 color );
|
||||
|
||||
#endif // BEAMDRAW_H
|
||||
@@ -0,0 +1,288 @@
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
// $NoKeywords: $
|
||||
//
|
||||
//=============================================================================//
|
||||
|
||||
#include "cbase.h"
|
||||
#include "bone_merge_cache.h"
|
||||
#include "bone_setup.h"
|
||||
|
||||
// memdbgon must be the last include file in a .cpp file!!!
|
||||
#include "tier0/memdbgon.h"
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// CBoneMergeCache
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
CBoneMergeCache::CBoneMergeCache()
|
||||
{
|
||||
m_pOwner = NULL;
|
||||
m_pFollow = NULL;
|
||||
m_pFollowHdr = NULL;
|
||||
m_pFollowRenderHdr = NULL;
|
||||
m_pOwnerHdr = NULL;
|
||||
m_nFollowBoneSetupMask = 0;
|
||||
}
|
||||
|
||||
void CBoneMergeCache::Init( C_BaseAnimating *pOwner )
|
||||
{
|
||||
m_pOwner = pOwner;
|
||||
m_pFollow = NULL;
|
||||
m_pFollowHdr = NULL;
|
||||
m_pFollowRenderHdr = NULL;
|
||||
m_pOwnerHdr = NULL;
|
||||
m_nFollowBoneSetupMask = 0;
|
||||
}
|
||||
|
||||
void CBoneMergeCache::UpdateCache()
|
||||
{
|
||||
CStudioHdr *pOwnerHdr = m_pOwner ? m_pOwner->GetModelPtr() : NULL;
|
||||
if ( !pOwnerHdr )
|
||||
{
|
||||
if ( m_pOwnerHdr )
|
||||
{
|
||||
// Owner's model got swapped out
|
||||
m_MergedBones.Purge();
|
||||
m_BoneMergeBits.Purge();
|
||||
m_pFollow = NULL;
|
||||
m_pFollowHdr = NULL;
|
||||
m_pFollowRenderHdr = NULL;
|
||||
m_pOwnerHdr = NULL;
|
||||
m_nFollowBoneSetupMask = 0;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
C_BaseAnimating *pTestFollow = m_pOwner->FindFollowedEntity();
|
||||
CStudioHdr *pTestHdr = (pTestFollow ? pTestFollow->GetModelPtr() : NULL);
|
||||
const studiohdr_t *pTestStudioHDR = (pTestHdr ? pTestHdr->GetRenderHdr() : NULL);
|
||||
if ( pTestFollow != m_pFollow || pTestHdr != m_pFollowHdr || pTestStudioHDR != m_pFollowRenderHdr || pOwnerHdr != m_pOwnerHdr )
|
||||
{
|
||||
m_MergedBones.Purge();
|
||||
m_BoneMergeBits.Purge();
|
||||
|
||||
// Update the cache.
|
||||
if ( pTestFollow && pTestHdr && pOwnerHdr )
|
||||
{
|
||||
m_pFollow = pTestFollow;
|
||||
m_pFollowHdr = pTestHdr;
|
||||
m_pFollowRenderHdr = pTestStudioHDR;
|
||||
m_pOwnerHdr = pOwnerHdr;
|
||||
|
||||
m_BoneMergeBits.SetSize( pOwnerHdr->numbones() / 8 + 1 );
|
||||
memset( m_BoneMergeBits.Base(), 0, m_BoneMergeBits.Count() );
|
||||
|
||||
mstudiobone_t *pOwnerBones = m_pOwnerHdr->pBone( 0 );
|
||||
|
||||
m_nFollowBoneSetupMask = BONE_USED_BY_BONE_MERGE;
|
||||
for ( int i = 0; i < m_pOwnerHdr->numbones(); i++ )
|
||||
{
|
||||
int parentBoneIndex = Studio_BoneIndexByName( m_pFollowHdr, pOwnerBones[i].pszName() );
|
||||
if ( parentBoneIndex < 0 )
|
||||
continue;
|
||||
|
||||
// Add a merged bone here.
|
||||
CMergedBone mergedBone;
|
||||
mergedBone.m_iMyBone = i;
|
||||
mergedBone.m_iParentBone = parentBoneIndex;
|
||||
m_MergedBones.AddToTail( mergedBone );
|
||||
|
||||
m_BoneMergeBits[i>>3] |= ( 1 << ( i & 7 ) );
|
||||
|
||||
if ( ( m_pFollowHdr->boneFlags( parentBoneIndex ) & BONE_USED_BY_BONE_MERGE ) == 0 )
|
||||
{
|
||||
m_nFollowBoneSetupMask = BONE_USED_BY_ANYTHING;
|
||||
// Warning("Performance warning: Merge with '%s'. Mark bone '%s' in model '%s' as being used by bone merge in the .qc!\n",
|
||||
// pOwnerHdr->pszName(), m_pFollowHdr->pBone( parentBoneIndex )->pszName(), m_pFollowHdr->pszName() );
|
||||
}
|
||||
}
|
||||
|
||||
// No merged bones found? Slam the mask to 0
|
||||
if ( !m_MergedBones.Count() )
|
||||
{
|
||||
m_nFollowBoneSetupMask = 0;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
m_pFollow = NULL;
|
||||
m_pFollowHdr = NULL;
|
||||
m_pFollowRenderHdr = NULL;
|
||||
m_pOwnerHdr = NULL;
|
||||
m_nFollowBoneSetupMask = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#ifdef STAGING_ONLY
|
||||
ConVar r_captain_canteen_is_angry ( "r_captain_canteen_is_angry", "1" );
|
||||
#endif
|
||||
|
||||
void CBoneMergeCache::MergeMatchingBones( int boneMask )
|
||||
{
|
||||
UpdateCache();
|
||||
|
||||
// If this is set, then all the other cache data is set.
|
||||
if ( !m_pOwnerHdr || m_MergedBones.Count() == 0 )
|
||||
return;
|
||||
|
||||
// Have the entity we're following setup its bones.
|
||||
bool bWorked = m_pFollow->SetupBones( NULL, -1, m_nFollowBoneSetupMask, gpGlobals->curtime );
|
||||
// We suspect there's some cases where SetupBones couldn't do its thing, and then this causes Captain Canteen.
|
||||
Assert ( bWorked );
|
||||
if ( !bWorked )
|
||||
{
|
||||
// Usually this means your parent is invisible or gone or whatever.
|
||||
// This routine has no way to tell its caller not to draw itself unfortunately.
|
||||
// But we can shrink all the bones down to zero size.
|
||||
// But it might still spawn particle systems? :-(
|
||||
matrix3x4_t NewBone;
|
||||
MatrixScaleByZero ( NewBone );
|
||||
MatrixSetTranslation ( Vector ( 0.0f, 0.0f, 0.0f ), NewBone );
|
||||
#ifdef STAGING_ONLY
|
||||
if ( r_captain_canteen_is_angry.GetBool() )
|
||||
{
|
||||
// We actually want to see when Captain Canteen happened, and make it really obvious that (a) he was here and (b) this code would have fixed him.
|
||||
float HowAngry = 20.0f; // Leon's getting larger!
|
||||
MatrixSetColumn ( Vector ( HowAngry, 0.0f, 0.0f ), 0, NewBone );
|
||||
MatrixSetColumn ( Vector ( 0.0f, HowAngry, 0.0f ), 1, NewBone );
|
||||
MatrixSetColumn ( Vector ( 0.0f, 0.0f, HowAngry ), 2, NewBone );
|
||||
}
|
||||
#endif
|
||||
|
||||
for ( int i=0; i < m_MergedBones.Count(); i++ )
|
||||
{
|
||||
int iOwnerBone = m_MergedBones[i].m_iMyBone;
|
||||
|
||||
// Only update bones reference by the bone mask.
|
||||
if ( !( m_pOwnerHdr->boneFlags( iOwnerBone ) & boneMask ) )
|
||||
continue;
|
||||
|
||||
m_pOwner->GetBoneForWrite( iOwnerBone ) = NewBone;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Now copy the bone matrices.
|
||||
for ( int i=0; i < m_MergedBones.Count(); i++ )
|
||||
{
|
||||
int iOwnerBone = m_MergedBones[i].m_iMyBone;
|
||||
int iParentBone = m_MergedBones[i].m_iParentBone;
|
||||
|
||||
// Only update bones reference by the bone mask.
|
||||
if ( !( m_pOwnerHdr->boneFlags( iOwnerBone ) & boneMask ) )
|
||||
continue;
|
||||
|
||||
MatrixCopy( m_pFollow->GetBone( iParentBone ), m_pOwner->GetBoneForWrite( iOwnerBone ) );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// copy bones instead of matrices
|
||||
void CBoneMergeCache::CopyParentToChild( const Vector parentPos[], const Quaternion parentQ[], Vector childPos[], Quaternion childQ[], int boneMask )
|
||||
{
|
||||
UpdateCache();
|
||||
|
||||
// If this is set, then all the other cache data is set.
|
||||
if ( !m_pOwnerHdr || m_MergedBones.Count() == 0 )
|
||||
return;
|
||||
|
||||
// Now copy the bone matrices.
|
||||
for ( int i=0; i < m_MergedBones.Count(); i++ )
|
||||
{
|
||||
int iOwnerBone = m_MergedBones[i].m_iMyBone;
|
||||
int iParentBone = m_MergedBones[i].m_iParentBone;
|
||||
|
||||
if ( m_pOwnerHdr->boneParent( iOwnerBone ) == -1 || m_pFollowHdr->boneParent( iParentBone ) == -1 )
|
||||
continue;
|
||||
|
||||
// Only update bones reference by the bone mask.
|
||||
if ( !( m_pOwnerHdr->boneFlags( iOwnerBone ) & boneMask ) )
|
||||
continue;
|
||||
|
||||
childPos[ iOwnerBone ] = parentPos[ iParentBone ];
|
||||
childQ[ iOwnerBone ] = parentQ[ iParentBone ];
|
||||
}
|
||||
}
|
||||
|
||||
void CBoneMergeCache::CopyChildToParent( const Vector childPos[], const Quaternion childQ[], Vector parentPos[], Quaternion parentQ[], int boneMask )
|
||||
{
|
||||
UpdateCache();
|
||||
|
||||
// If this is set, then all the other cache data is set.
|
||||
if ( !m_pOwnerHdr || m_MergedBones.Count() == 0 )
|
||||
return;
|
||||
|
||||
// Now copy the bone matrices.
|
||||
for ( int i=0; i < m_MergedBones.Count(); i++ )
|
||||
{
|
||||
int iOwnerBone = m_MergedBones[i].m_iMyBone;
|
||||
int iParentBone = m_MergedBones[i].m_iParentBone;
|
||||
|
||||
if ( m_pOwnerHdr->boneParent( iOwnerBone ) == -1 || m_pFollowHdr->boneParent( iParentBone ) == -1 )
|
||||
continue;
|
||||
|
||||
// Only update bones reference by the bone mask.
|
||||
if ( !( m_pOwnerHdr->boneFlags( iOwnerBone ) & boneMask ) )
|
||||
continue;
|
||||
|
||||
parentPos[ iParentBone ] = childPos[ iOwnerBone ];
|
||||
parentQ[ iParentBone ] = childQ[ iOwnerBone ];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool CBoneMergeCache::GetAimEntOrigin( Vector *pAbsOrigin, QAngle *pAbsAngles )
|
||||
{
|
||||
UpdateCache();
|
||||
|
||||
// If this is set, then all the other cache data is set.
|
||||
if ( !m_pOwnerHdr || m_MergedBones.Count() == 0 )
|
||||
return false;
|
||||
|
||||
// We want the abs origin such that if we put the entity there, the first merged bone
|
||||
// will be aligned. This way the entity will be culled in the correct position.
|
||||
//
|
||||
// ie: mEntity * mBoneLocal = mFollowBone
|
||||
// so: mEntity = mFollowBone * Inverse( mBoneLocal )
|
||||
//
|
||||
// Note: the code below doesn't take animation into account. If the attached entity animates
|
||||
// all over the place, then this won't get the right results.
|
||||
|
||||
// Get mFollowBone.
|
||||
m_pFollow->SetupBones( NULL, -1, m_nFollowBoneSetupMask, gpGlobals->curtime );
|
||||
const matrix3x4_t &mFollowBone = m_pFollow->GetBone( m_MergedBones[0].m_iParentBone );
|
||||
|
||||
// Get Inverse( mBoneLocal )
|
||||
matrix3x4_t mBoneLocal, mBoneLocalInv;
|
||||
SetupSingleBoneMatrix( m_pOwnerHdr, m_pOwner->GetSequence(), 0, m_MergedBones[0].m_iMyBone, mBoneLocal );
|
||||
MatrixInvert( mBoneLocal, mBoneLocalInv );
|
||||
|
||||
// Now calculate mEntity = mFollowBone * Inverse( mBoneLocal )
|
||||
matrix3x4_t mEntity;
|
||||
ConcatTransforms( mFollowBone, mBoneLocalInv, mEntity );
|
||||
MatrixAngles( mEntity, *pAbsAngles, *pAbsOrigin );
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CBoneMergeCache::GetRootBone( matrix3x4_t &rootBone )
|
||||
{
|
||||
UpdateCache();
|
||||
|
||||
// If this is set, then all the other cache data is set.
|
||||
if ( !m_pOwnerHdr || m_MergedBones.Count() == 0 )
|
||||
return false;
|
||||
|
||||
// Get mFollowBone.
|
||||
m_pFollow->SetupBones( NULL, -1, m_nFollowBoneSetupMask, gpGlobals->curtime );
|
||||
rootBone = m_pFollow->GetBone( m_MergedBones[0].m_iParentBone );
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,85 @@
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
//=============================================================================//
|
||||
|
||||
#ifndef BONE_MERGE_CACHE_H
|
||||
#define BONE_MERGE_CACHE_H
|
||||
#ifdef _WIN32
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
|
||||
class C_BaseAnimating;
|
||||
class CStudioHdr;
|
||||
|
||||
|
||||
#include "mathlib/vector.h"
|
||||
|
||||
|
||||
class CBoneMergeCache
|
||||
{
|
||||
public:
|
||||
|
||||
CBoneMergeCache();
|
||||
|
||||
void Init( C_BaseAnimating *pOwner );
|
||||
|
||||
// Updates the lookups that let it merge bones quickly.
|
||||
void UpdateCache();
|
||||
|
||||
// This copies the transform from all bones in the followed entity that have
|
||||
// names that match our bones.
|
||||
void MergeMatchingBones( int boneMask );
|
||||
|
||||
// copy bones instead of matrices
|
||||
void CopyParentToChild( const Vector parentPos[], const Quaternion parentQ[], Vector childPos[], Quaternion childQ[], int boneMask );
|
||||
void CopyChildToParent( const Vector childPos[], const Quaternion childQ[], Vector parentPos[], Quaternion parentQ[], int boneMask );
|
||||
|
||||
// Returns true if the specified bone is one that gets merged in MergeMatchingBones.
|
||||
int IsBoneMerged( int iBone ) const;
|
||||
|
||||
// Gets the origin for the first merge bone on the parent.
|
||||
bool GetAimEntOrigin( Vector *pAbsOrigin, QAngle *pAbsAngles );
|
||||
|
||||
bool GetRootBone( matrix3x4_t &rootBone );
|
||||
|
||||
private:
|
||||
|
||||
// This is the entity that we're keeping the cache updated for.
|
||||
C_BaseAnimating *m_pOwner;
|
||||
|
||||
// All the cache data is based off these. When they change, the cache data is regenerated.
|
||||
// These are either all valid pointers or all NULL.
|
||||
C_BaseAnimating *m_pFollow;
|
||||
CStudioHdr *m_pFollowHdr;
|
||||
const studiohdr_t *m_pFollowRenderHdr;
|
||||
CStudioHdr *m_pOwnerHdr;
|
||||
|
||||
// This is the mask we need to use to set up bones on the followed entity to do the bone merge
|
||||
int m_nFollowBoneSetupMask;
|
||||
|
||||
// Cache data.
|
||||
class CMergedBone
|
||||
{
|
||||
public:
|
||||
unsigned short m_iMyBone;
|
||||
unsigned short m_iParentBone;
|
||||
};
|
||||
|
||||
CUtlVector<CMergedBone> m_MergedBones;
|
||||
CUtlVector<unsigned char> m_BoneMergeBits; // One bit for each bone. The bit is set if the bone gets merged.
|
||||
};
|
||||
|
||||
|
||||
inline int CBoneMergeCache::IsBoneMerged( int iBone ) const
|
||||
{
|
||||
if ( m_pOwnerHdr )
|
||||
return m_BoneMergeBits[iBone >> 3] & ( 1 << ( iBone & 7 ) );
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
#endif // BONE_MERGE_CACHE_H
|
||||
@@ -0,0 +1,71 @@
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
//=============================================================================
|
||||
|
||||
#ifndef BONETOWORLDARRAY_H
|
||||
#define BONETOWORLDARRAY_H
|
||||
|
||||
#include "tier0/tslist.h"
|
||||
|
||||
#if defined( _WIN32 )
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
#include "tier0/memdbgon.h" // for _aligned_malloc usage below
|
||||
//-----------------------------------------------------------------------------
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
template <int NUM_ARRAYS>
|
||||
class CBoneToWorldArrays
|
||||
{
|
||||
public:
|
||||
enum
|
||||
{
|
||||
ALIGNMENT = 128,
|
||||
};
|
||||
|
||||
CBoneToWorldArrays()
|
||||
{
|
||||
const int SIZE_ARRAY = AlignValue( sizeof(matrix3x4_t) * MAXSTUDIOBONES, ALIGNMENT );
|
||||
m_pBase = (matrix3x4_t *)_aligned_malloc( SIZE_ARRAY * NUM_ARRAYS, ALIGNMENT );
|
||||
for ( int i = 0; i < NUM_ARRAYS; i++ )
|
||||
{
|
||||
matrix3x4_t *pArray = (matrix3x4_t *)((byte *)m_pBase + SIZE_ARRAY * i);
|
||||
Assert( (size_t)pArray % ALIGNMENT == 0 );
|
||||
Free( pArray );
|
||||
}
|
||||
}
|
||||
|
||||
~CBoneToWorldArrays()
|
||||
{
|
||||
_aligned_free( m_pBase );
|
||||
}
|
||||
|
||||
int NumArrays()
|
||||
{
|
||||
return NUM_ARRAYS;
|
||||
}
|
||||
|
||||
matrix3x4_t *Alloc( bool bBlock = true )
|
||||
{
|
||||
TSLNodeBase_t *p;
|
||||
while ( ( p = m_Free.Pop() ) == NULL && bBlock )
|
||||
{
|
||||
ThreadPause();
|
||||
}
|
||||
return (matrix3x4_t *)p;
|
||||
}
|
||||
|
||||
void Free( matrix3x4_t *p )
|
||||
{
|
||||
m_Free.Push( (TSLNodeBase_t *) p );
|
||||
}
|
||||
|
||||
private:
|
||||
CTSListBase m_Free;
|
||||
matrix3x4_t *m_pBase;
|
||||
};
|
||||
|
||||
#endif // BONETOWORLDARRAY_H
|
||||
@@ -0,0 +1,170 @@
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose: Exposes bsp tools to game for e.g. workshop use
|
||||
//
|
||||
// $NoKeywords: $
|
||||
//===========================================================================//
|
||||
|
||||
#include "cbase.h"
|
||||
#include <tier2/tier2.h>
|
||||
#include "filesystem.h"
|
||||
#include "bsp_utils.h"
|
||||
#include "utlbuffer.h"
|
||||
#include "igamesystem.h"
|
||||
|
||||
// memdbgon must be the last include file in a .cpp file!!!
|
||||
#include "tier0/memdbgon.h"
|
||||
|
||||
bool BSP_SyncRepack( const char *pszInputMapFile,
|
||||
const char *pszOutputMapFile,
|
||||
IBSPPack::eRepackBSPFlags eRepackFlags )
|
||||
{
|
||||
// load the bsppack dll
|
||||
IBSPPack *libBSPPack = NULL;
|
||||
CSysModule *pModule = g_pFullFileSystem->LoadModule( "bsppack" );
|
||||
if ( pModule )
|
||||
{
|
||||
CreateInterfaceFn BSPPackFactory = Sys_GetFactory( pModule );
|
||||
if ( BSPPackFactory )
|
||||
{
|
||||
libBSPPack = ( IBSPPack * )BSPPackFactory( IBSPPACK_VERSION_STRING, NULL );
|
||||
}
|
||||
}
|
||||
if( !libBSPPack )
|
||||
{
|
||||
Warning( "Can't load bsppack library - unable to compress bsp\n" );
|
||||
return false;
|
||||
}
|
||||
|
||||
Msg( "Repacking %s -> %s\n", pszInputMapFile, pszOutputMapFile );
|
||||
|
||||
if ( !g_pFullFileSystem->FileExists( pszInputMapFile ) )
|
||||
{
|
||||
Warning( "Couldn't open input file %s - BSP recompress failed\n", pszInputMapFile );
|
||||
return false;
|
||||
}
|
||||
|
||||
CUtlBuffer inputBuffer;
|
||||
if ( !g_pFullFileSystem->ReadFile( pszInputMapFile, NULL, inputBuffer ) )
|
||||
{
|
||||
Warning( "Couldn't read file %s - BSP compression failed\n", pszInputMapFile );
|
||||
return false;
|
||||
}
|
||||
|
||||
CUtlBuffer outputBuffer;
|
||||
|
||||
if ( !libBSPPack->RepackBSP( inputBuffer, outputBuffer, eRepackFlags ) )
|
||||
{
|
||||
Warning( "Internal error compressing BSP\n" );
|
||||
return false;
|
||||
}
|
||||
|
||||
g_pFullFileSystem->WriteFile( pszOutputMapFile, NULL, outputBuffer );
|
||||
|
||||
Msg( "Successfully repacked %s as %s -- %u -> %u bytes\n",
|
||||
pszInputMapFile, pszOutputMapFile, inputBuffer.TellPut(), outputBuffer.TellPut() );
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// Helper to create a thread that calls SyncCompressMap, and clean it up when it exists
|
||||
void BSP_BackgroundRepack( const char *pszInputMapFile,
|
||||
const char *pszOutputMapFile,
|
||||
IBSPPack::eRepackBSPFlags eRepackFlags )
|
||||
{
|
||||
// Make this a gamesystem and thread, so it can check for completion each frame and clean itself up. Run() is the
|
||||
// background thread, Update() is the main thread tick.
|
||||
class BackgroundBSPRepackThread : public CThread, public CAutoGameSystemPerFrame
|
||||
{
|
||||
public:
|
||||
BackgroundBSPRepackThread( const char *pszInputFile, const char *pszOutputFile, IBSPPack::eRepackBSPFlags eRepackFlags )
|
||||
: m_strInput( pszInputFile )
|
||||
, m_strOutput( pszOutputFile )
|
||||
, m_eRepackFlags( eRepackFlags )
|
||||
{
|
||||
Start();
|
||||
}
|
||||
|
||||
// CThread job - returns 0 for success
|
||||
virtual int Run() OVERRIDE
|
||||
{
|
||||
return BSP_SyncRepack( m_strInput.Get(), m_strOutput.Get(), m_eRepackFlags ) ? 0 : 1;
|
||||
}
|
||||
|
||||
// GameSystem
|
||||
virtual const char* Name( void ) OVERRIDE { return "BackgroundBSPRepackThread"; }
|
||||
|
||||
// Runs on main thread
|
||||
void CheckFinished()
|
||||
{
|
||||
if ( !IsAlive() )
|
||||
{
|
||||
// Thread finished
|
||||
if ( GetResult() != 0 )
|
||||
{
|
||||
Warning( "Map compression thread failed :(\n" );
|
||||
}
|
||||
|
||||
// AutoGameSystem deregisters itself on destruction, we're done
|
||||
delete this;
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef CLIENT_DLL
|
||||
virtual void Update( float frametime ) OVERRIDE { CheckFinished(); }
|
||||
#else // GAME DLL
|
||||
virtual void FrameUpdatePostEntityThink() OVERRIDE { CheckFinished(); }
|
||||
#endif
|
||||
private:
|
||||
CUtlString m_strInput;
|
||||
CUtlString m_strOutput;
|
||||
IBSPPack::eRepackBSPFlags m_eRepackFlags;
|
||||
};
|
||||
|
||||
Msg( "Starting BSP repack job %s -> %s\n", pszInputMapFile, pszOutputMapFile );
|
||||
|
||||
// Deletes itself up when done
|
||||
new BackgroundBSPRepackThread( pszInputMapFile, pszOutputMapFile, eRepackFlags );
|
||||
}
|
||||
|
||||
CON_COMMAND( bsp_repack, "Repack and output a (re)compressed version of a bsp file" )
|
||||
{
|
||||
#ifdef GAME_DLL
|
||||
if ( !UTIL_IsCommandIssuedByServerAdmin() )
|
||||
return;
|
||||
#endif
|
||||
|
||||
// Handle -nocompress
|
||||
bool bCompress = true;
|
||||
const char *szInFilename = NULL;
|
||||
const char *szOutFilename = NULL;
|
||||
|
||||
if ( args.ArgC() == 4 && V_strcasecmp( args.Arg( 1 ), "-nocompress" ) == 0 )
|
||||
{
|
||||
bCompress = false;
|
||||
szInFilename = args.Arg( 2 );
|
||||
szOutFilename = args.Arg( 3 );
|
||||
}
|
||||
else if ( args.ArgC() == 3 )
|
||||
{
|
||||
szInFilename = args.Arg( 1 );
|
||||
szOutFilename = args.Arg( 2 );
|
||||
}
|
||||
|
||||
if ( !szInFilename || !szOutFilename || !strlen( szInFilename ) || !strlen( szOutFilename ) )
|
||||
{
|
||||
Msg( "Usage: bsp_repack [-nocompress] map.bsp output_map.bsp\n" );
|
||||
return;
|
||||
}
|
||||
|
||||
if ( bCompress )
|
||||
{
|
||||
// Use default compress flags
|
||||
BSP_BackgroundRepack( szInFilename, szOutFilename );
|
||||
}
|
||||
else
|
||||
{
|
||||
// No compression
|
||||
BSP_BackgroundRepack( szInFilename, szOutFilename, (IBSPPack::eRepackBSPFlags)0 );
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose: Exposes bsp tools to game for e.g. workshop use
|
||||
//
|
||||
// $NoKeywords: $
|
||||
//===========================================================================//
|
||||
|
||||
#include "../utils/common/bsplib.h"
|
||||
#include "ibsppack.h"
|
||||
|
||||
// Loads bsppack module (IBSPPack) and calls RepackBSP()
|
||||
bool BSP_SyncRepack( const char *pszInputMapFile,
|
||||
const char *pszOutputMapFile,
|
||||
IBSPPack::eRepackBSPFlags eRepackFlags = (IBSPPack::eRepackBSPFlags) ( IBSPPack::eRepackBSP_CompressLumps |
|
||||
IBSPPack::eRepackBSP_CompressPackfile ) );
|
||||
|
||||
// Helper to spawn a background thread that runs SyncRepack
|
||||
void BSP_BackgroundRepack( const char *pszInputMapFile,
|
||||
const char *pszOutputMapFile,
|
||||
IBSPPack::eRepackBSPFlags eRepackFlags = (IBSPPack::eRepackBSPFlags) ( IBSPPack::eRepackBSP_CompressLumps |
|
||||
IBSPPack::eRepackBSP_CompressPackfile ) );
|
||||
@@ -0,0 +1,169 @@
|
||||
//========= 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"
|
||||
|
||||
#if 0
|
||||
|
||||
class C_AI_BaseHumanoid : public C_AI_BaseNPC
|
||||
{
|
||||
public:
|
||||
DECLARE_CLASS( C_AI_BaseHumanoid, C_AI_BaseNPC );
|
||||
DECLARE_CLIENTCLASS();
|
||||
|
||||
C_AI_BaseHumanoid();
|
||||
|
||||
// model specific
|
||||
virtual bool Interpolate( float currentTime );
|
||||
virtual void StandardBlendingRules( CStudioHdr *pStudioHdr, Vector pos[], Quaternion q[], float currentTime, int boneMask );
|
||||
|
||||
float m_recanimtime[3];
|
||||
AnimationLayer_t m_Layer[4][3];
|
||||
};
|
||||
|
||||
|
||||
|
||||
C_AI_BaseHumanoid::C_AI_BaseHumanoid()
|
||||
{
|
||||
memset(m_recanimtime, 0, sizeof(m_recanimtime));
|
||||
memset(m_Layer, 0, sizeof(m_Layer));
|
||||
}
|
||||
|
||||
|
||||
BEGIN_RECV_TABLE_NOBASE(AnimationLayer_t, DT_Animationlayer)
|
||||
RecvPropInt(RECVINFO_NAME(nSequence,sequence)),
|
||||
RecvPropFloat(RECVINFO_NAME(flCycle,cycle)),
|
||||
RecvPropFloat(RECVINFO_NAME(flPlaybackrate,playbackrate)),
|
||||
RecvPropFloat(RECVINFO_NAME(flWeight,weight))
|
||||
END_RECV_TABLE()
|
||||
|
||||
|
||||
|
||||
IMPLEMENT_CLIENTCLASS_DT(C_AI_BaseHumanoid, DT_BaseHumanoid, CAI_BaseHumanoid)
|
||||
/*
|
||||
RecvPropDataTable(RECVINFO_DTNAME(m_Layer[0][2],m_Layer0),0, &REFERENCE_RECV_TABLE(DT_Animationlayer)),
|
||||
RecvPropDataTable(RECVINFO_DTNAME(m_Layer[1][2],m_Layer1),0, &REFERENCE_RECV_TABLE(DT_Animationlayer)),
|
||||
RecvPropDataTable(RECVINFO_DTNAME(m_Layer[2][2],m_Layer2),0, &REFERENCE_RECV_TABLE(DT_Animationlayer)),
|
||||
RecvPropDataTable(RECVINFO_DTNAME(m_Layer[3][2],m_Layer3),0, &REFERENCE_RECV_TABLE(DT_Animationlayer)),
|
||||
*/
|
||||
RecvPropInt(RECVINFO_NAME(m_Layer[0][2].nSequence,sequence0)),
|
||||
RecvPropFloat(RECVINFO_NAME(m_Layer[0][2].flCycle,cycle0)),
|
||||
RecvPropFloat(RECVINFO_NAME(m_Layer[0][2].flPlaybackrate,playbackrate0)),
|
||||
RecvPropFloat(RECVINFO_NAME(m_Layer[0][2].flWeight,weight0)),
|
||||
RecvPropInt(RECVINFO_NAME(m_Layer[1][2].nSequence,sequence1)),
|
||||
RecvPropFloat(RECVINFO_NAME(m_Layer[1][2].flCycle,cycle1)),
|
||||
RecvPropFloat(RECVINFO_NAME(m_Layer[1][2].flPlaybackrate,playbackrate1)),
|
||||
RecvPropFloat(RECVINFO_NAME(m_Layer[1][2].flWeight,weight1)),
|
||||
RecvPropInt(RECVINFO_NAME(m_Layer[2][2].nSequence,sequence2)),
|
||||
RecvPropFloat(RECVINFO_NAME(m_Layer[2][2].flCycle,cycle2)),
|
||||
RecvPropFloat(RECVINFO_NAME(m_Layer[2][2].flPlaybackrate,playbackrate2)),
|
||||
RecvPropFloat(RECVINFO_NAME(m_Layer[2][2].flWeight,weight2)),
|
||||
RecvPropInt(RECVINFO_NAME(m_Layer[3][2].nSequence,sequence3)),
|
||||
RecvPropFloat(RECVINFO_NAME(m_Layer[3][2].flCycle,cycle3)),
|
||||
RecvPropFloat(RECVINFO_NAME(m_Layer[3][2].flPlaybackrate,playbackrate3)),
|
||||
RecvPropFloat(RECVINFO_NAME(m_Layer[3][2].flWeight,weight3))
|
||||
END_RECV_TABLE()
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
void C_AI_BaseHumanoid::StandardBlendingRules( CStudioHdr *pStudioHdr, Vector pos[], Quaternion q[], float currentTime, int boneMask )
|
||||
{
|
||||
VPROF( "C_AI_BaseHumanoid::StandardBlendingRules" );
|
||||
|
||||
BaseClass::StandardBlendingRules( pStudioHdr, pos, q, currentTime, boneMask );
|
||||
|
||||
if ( !hdr )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
#if 0
|
||||
float poseparam[MAXSTUDIOPOSEPARAM];
|
||||
|
||||
if ( GetSequence() >= hdr->numseq )
|
||||
{
|
||||
SetSequence( 0 );
|
||||
}
|
||||
|
||||
// interpolate pose parameters
|
||||
for (int i = 0; i < hdr->numposeparameters; i++)
|
||||
{
|
||||
poseparam[ i ] = m_flPoseParameter[i];
|
||||
}
|
||||
|
||||
// build root animation
|
||||
float fCycle = GetCycle();
|
||||
CalcPose( hdr, NULL, pos, q, GetSequence(), fCycle, poseparam );
|
||||
|
||||
// debugoverlay->AddTextOverlay( GetAbsOrigin() + Vector( 0, 0, 64 ), 0, 0, "%30s %6.2f : %6.2f", hdr->pSeqdesc( GetSequence() )->pszLabel( ), fCycle, 1.0 );
|
||||
|
||||
MaintainSequenceTransitions( hdr, fCycle, poseparam, pos, q, boneMask );
|
||||
|
||||
#if 1
|
||||
for (i = 0; i < 4; i++)
|
||||
{
|
||||
if (m_Layer[i][2].nSequence != m_Layer[i][1].nSequence)
|
||||
{
|
||||
if (m_Layer[i][2].flWeight > 0.5) m_Layer[i][1].flWeight = 1.0; else m_Layer[i][1].flWeight = 0;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#if 1
|
||||
for (i = 0; i < 4; i++)
|
||||
{
|
||||
Vector pos2[MAXSTUDIOBONES];
|
||||
Quaternion q2[MAXSTUDIOBONES];
|
||||
float fWeight = m_Layer[i][1].flWeight * (1 - dadt) + m_Layer[i][2].flWeight * dadt;
|
||||
|
||||
/*
|
||||
debugoverlay->AddTextOverlay( GetAbsOrigin() + Vector( 0, 0, 64 ), -i - 1, 0,
|
||||
"%2d %6.2f %6.2f : %2d %6.2f %6.2f : %2d %6.2f %6.2f",
|
||||
m_Layer[i][0].nSequence, m_Layer[i][0].flCycle, m_Layer[i][0].flWeight,
|
||||
m_Layer[i][1].nSequence, m_Layer[i][1].flCycle, m_Layer[i][1].flWeight,
|
||||
m_Layer[i][2].nSequence, m_Layer[i][2].flCycle, m_Layer[i][2].flWeight );
|
||||
*/
|
||||
|
||||
if (fWeight > 0)
|
||||
{
|
||||
mstudioseqdesc_t *pseqdesc = hdr->pSeqdesc( m_Layer[i][2].nSequence );
|
||||
|
||||
float fCycle = m_Layer[i][2].flCycle;
|
||||
|
||||
// UNDONE: Do IK here.
|
||||
CalcPose( hdr, NULL, pos2, q2, m_Layer[i][2].nSequence, fCycle, poseparam );
|
||||
|
||||
if (fWeight > 1)
|
||||
fWeight = 1;
|
||||
SlerpBones( hdr, q, pos, pseqdesc, q2, pos2, fWeight );
|
||||
|
||||
engine->Con_NPrintf( 10 + i, "%30s %6.2f : %6.2f", pseqdesc->pszLabel(), fCycle, fWeight );
|
||||
}
|
||||
else
|
||||
{
|
||||
engine->Con_NPrintf( 10 + i, "%30s %6.2f : %6.2f", " ", 0, 0 );
|
||||
}
|
||||
|
||||
}
|
||||
#endif
|
||||
|
||||
CIKContext auto_ik;
|
||||
auto_ik.Init( hdr, GetRenderAngles(), GetRenderOrigin(), gpGlobals->curtime );
|
||||
CalcAutoplaySequences( hdr, &auto_ik, pos, q, poseparam, boneMask, currentTime );
|
||||
|
||||
float controllers[MAXSTUDIOBONECTRLS];
|
||||
GetBoneControllers(controllers);
|
||||
CalcBoneAdj( hdr, pos, q, controllers );
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,185 @@
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
// $NoKeywords: $
|
||||
//=============================================================================//
|
||||
#include "cbase.h"
|
||||
#include "c_ai_basenpc.h"
|
||||
#include "engine/ivdebugoverlay.h"
|
||||
|
||||
#if defined( HL2_DLL ) || defined( HL2_EPISODIC )
|
||||
#include "c_basehlplayer.h"
|
||||
#endif
|
||||
|
||||
#include "death_pose.h"
|
||||
|
||||
// memdbgon must be the last include file in a .cpp file!!!
|
||||
#include "tier0/memdbgon.h"
|
||||
|
||||
#define PING_MAX_TIME 2.0
|
||||
|
||||
IMPLEMENT_CLIENTCLASS_DT( C_AI_BaseNPC, DT_AI_BaseNPC, CAI_BaseNPC )
|
||||
RecvPropInt( RECVINFO( m_lifeState ) ),
|
||||
RecvPropBool( RECVINFO( m_bPerformAvoidance ) ),
|
||||
RecvPropBool( RECVINFO( m_bIsMoving ) ),
|
||||
RecvPropBool( RECVINFO( m_bFadeCorpse ) ),
|
||||
RecvPropInt( RECVINFO ( m_iDeathPose) ),
|
||||
RecvPropInt( RECVINFO( m_iDeathFrame) ),
|
||||
RecvPropInt( RECVINFO( m_iSpeedModRadius ) ),
|
||||
RecvPropInt( RECVINFO( m_iSpeedModSpeed ) ),
|
||||
RecvPropInt( RECVINFO( m_bSpeedModActive ) ),
|
||||
RecvPropBool( RECVINFO( m_bImportanRagdoll ) ),
|
||||
RecvPropFloat( RECVINFO( m_flTimePingEffect ) ),
|
||||
END_RECV_TABLE()
|
||||
|
||||
extern ConVar cl_npc_speedmod_intime;
|
||||
|
||||
bool NPC_IsImportantNPC( C_BaseAnimating *pAnimating )
|
||||
{
|
||||
C_AI_BaseNPC *pBaseNPC = dynamic_cast < C_AI_BaseNPC* > ( pAnimating );
|
||||
|
||||
if ( pBaseNPC == NULL )
|
||||
return false;
|
||||
|
||||
return pBaseNPC->ImportantRagdoll();
|
||||
}
|
||||
|
||||
C_AI_BaseNPC::C_AI_BaseNPC()
|
||||
{
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Makes ragdolls ignore npcclip brushes
|
||||
//-----------------------------------------------------------------------------
|
||||
unsigned int C_AI_BaseNPC::PhysicsSolidMaskForEntity( void ) const
|
||||
{
|
||||
// This allows ragdolls to move through npcclip brushes
|
||||
if ( !IsRagdoll() )
|
||||
{
|
||||
return MASK_NPCSOLID;
|
||||
}
|
||||
return MASK_SOLID;
|
||||
}
|
||||
|
||||
|
||||
void C_AI_BaseNPC::ClientThink( void )
|
||||
{
|
||||
BaseClass::ClientThink();
|
||||
|
||||
#ifdef HL2_DLL
|
||||
C_BaseHLPlayer *pPlayer = dynamic_cast<C_BaseHLPlayer*>( C_BasePlayer::GetLocalPlayer() );
|
||||
|
||||
if ( ShouldModifyPlayerSpeed() == true )
|
||||
{
|
||||
if ( pPlayer )
|
||||
{
|
||||
float flDist = (GetAbsOrigin() - pPlayer->GetAbsOrigin()).LengthSqr();
|
||||
|
||||
if ( flDist <= GetSpeedModifyRadius() )
|
||||
{
|
||||
if ( pPlayer->m_hClosestNPC )
|
||||
{
|
||||
if ( pPlayer->m_hClosestNPC != this )
|
||||
{
|
||||
float flDistOther = (pPlayer->m_hClosestNPC->GetAbsOrigin() - pPlayer->GetAbsOrigin()).Length();
|
||||
|
||||
//If I'm closer than the other NPC then replace it with myself.
|
||||
if ( flDist < flDistOther )
|
||||
{
|
||||
pPlayer->m_hClosestNPC = this;
|
||||
pPlayer->m_flSpeedModTime = gpGlobals->curtime + cl_npc_speedmod_intime.GetFloat();
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
pPlayer->m_hClosestNPC = this;
|
||||
pPlayer->m_flSpeedModTime = gpGlobals->curtime + cl_npc_speedmod_intime.GetFloat();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif // HL2_DLL
|
||||
|
||||
#ifdef HL2_EPISODIC
|
||||
C_BaseHLPlayer *pPlayer = dynamic_cast<C_BaseHLPlayer*>( C_BasePlayer::GetLocalPlayer() );
|
||||
|
||||
if ( pPlayer && m_flTimePingEffect > gpGlobals->curtime )
|
||||
{
|
||||
float fPingEffectTime = m_flTimePingEffect - gpGlobals->curtime;
|
||||
|
||||
if ( fPingEffectTime > 0.0f )
|
||||
{
|
||||
Vector vRight, vUp;
|
||||
Vector vMins, vMaxs;
|
||||
|
||||
float fFade;
|
||||
|
||||
if( fPingEffectTime <= 1.0f )
|
||||
{
|
||||
fFade = 1.0f - (1.0f - fPingEffectTime);
|
||||
}
|
||||
else
|
||||
{
|
||||
fFade = 1.0f;
|
||||
}
|
||||
|
||||
GetRenderBounds( vMins, vMaxs );
|
||||
AngleVectors (pPlayer->GetAbsAngles(), NULL, &vRight, &vUp );
|
||||
Vector p1 = GetAbsOrigin() + vRight * vMins.x + vUp * vMins.z;
|
||||
Vector p2 = GetAbsOrigin() + vRight * vMaxs.x + vUp * vMins.z;
|
||||
Vector p3 = GetAbsOrigin() + vUp * vMaxs.z;
|
||||
|
||||
int r = 0 * fFade;
|
||||
int g = 255 * fFade;
|
||||
int b = 0 * fFade;
|
||||
|
||||
if ( debugoverlay )
|
||||
{
|
||||
debugoverlay->AddLineOverlay( p1, p2, r, g, b, true, 0.05f );
|
||||
debugoverlay->AddLineOverlay( p2, p3, r, g, b, true, 0.05f );
|
||||
debugoverlay->AddLineOverlay( p3, p1, r, g, b, true, 0.05f );
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void C_AI_BaseNPC::OnDataChanged( DataUpdateType_t type )
|
||||
{
|
||||
BaseClass::OnDataChanged( type );
|
||||
|
||||
if ( ( ShouldModifyPlayerSpeed() == true ) || ( m_flTimePingEffect > gpGlobals->curtime ) )
|
||||
{
|
||||
SetNextClientThink( CLIENT_THINK_ALWAYS );
|
||||
}
|
||||
}
|
||||
|
||||
bool C_AI_BaseNPC::GetRagdollInitBoneArrays( matrix3x4_t *pDeltaBones0, matrix3x4_t *pDeltaBones1, matrix3x4_t *pCurrentBones, float boneDt )
|
||||
{
|
||||
bool bRet = true;
|
||||
|
||||
if ( !ForceSetupBonesAtTime( pDeltaBones0, gpGlobals->curtime - boneDt ) )
|
||||
bRet = false;
|
||||
|
||||
GetRagdollCurSequenceWithDeathPose( this, pDeltaBones1, gpGlobals->curtime, m_iDeathPose, m_iDeathFrame );
|
||||
float ragdollCreateTime = PhysGetSyncCreateTime();
|
||||
if ( ragdollCreateTime != gpGlobals->curtime )
|
||||
{
|
||||
// The next simulation frame begins before the end of this frame
|
||||
// so initialize the ragdoll at that time so that it will reach the current
|
||||
// position at curtime. Otherwise the ragdoll will simulate forward from curtime
|
||||
// and pop into the future a bit at this point of transition
|
||||
if ( !ForceSetupBonesAtTime( pCurrentBones, ragdollCreateTime ) )
|
||||
bRet = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
if ( !SetupBones( pCurrentBones, MAXSTUDIOBONES, BONE_USED_BY_ANYTHING, gpGlobals->curtime ) )
|
||||
bRet = false;
|
||||
}
|
||||
|
||||
return bRet;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,61 @@
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
// $NoKeywords: $
|
||||
//=============================================================================//
|
||||
|
||||
#ifndef C_AI_BASENPC_H
|
||||
#define C_AI_BASENPC_H
|
||||
#ifdef _WIN32
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
|
||||
#include "c_basecombatcharacter.h"
|
||||
|
||||
// NOTE: Moved all controller code into c_basestudiomodel
|
||||
class C_AI_BaseNPC : public C_BaseCombatCharacter
|
||||
{
|
||||
DECLARE_CLASS( C_AI_BaseNPC, C_BaseCombatCharacter );
|
||||
|
||||
public:
|
||||
DECLARE_CLIENTCLASS();
|
||||
|
||||
C_AI_BaseNPC();
|
||||
virtual unsigned int PhysicsSolidMaskForEntity( void ) const;
|
||||
virtual bool IsNPC( void ) { return true; }
|
||||
bool IsMoving( void ){ return m_bIsMoving; }
|
||||
bool ShouldAvoidObstacle( void ){ return m_bPerformAvoidance; }
|
||||
virtual bool AddRagdollToFadeQueue( void ) { return m_bFadeCorpse; }
|
||||
|
||||
virtual bool GetRagdollInitBoneArrays( matrix3x4_t *pDeltaBones0, matrix3x4_t *pDeltaBones1, matrix3x4_t *pCurrentBones, float boneDt ) OVERRIDE;
|
||||
|
||||
int GetDeathPose( void ) { return m_iDeathPose; }
|
||||
|
||||
bool ShouldModifyPlayerSpeed( void ) { return m_bSpeedModActive; }
|
||||
int GetSpeedModifyRadius( void ) { return m_iSpeedModRadius; }
|
||||
int GetSpeedModifySpeed( void ) { return m_iSpeedModSpeed; }
|
||||
|
||||
void ClientThink( void );
|
||||
void OnDataChanged( DataUpdateType_t type );
|
||||
bool ImportantRagdoll( void ) { return m_bImportanRagdoll; }
|
||||
|
||||
private:
|
||||
C_AI_BaseNPC( const C_AI_BaseNPC & ); // not defined, not accessible
|
||||
float m_flTimePingEffect;
|
||||
int m_iDeathPose;
|
||||
int m_iDeathFrame;
|
||||
|
||||
int m_iSpeedModRadius;
|
||||
int m_iSpeedModSpeed;
|
||||
|
||||
bool m_bPerformAvoidance;
|
||||
bool m_bIsMoving;
|
||||
bool m_bFadeCorpse;
|
||||
bool m_bSpeedModActive;
|
||||
bool m_bImportanRagdoll;
|
||||
};
|
||||
|
||||
|
||||
#endif // C_AI_BASENPC_H
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,818 @@
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
// $Workfile: $
|
||||
// $NoKeywords: $
|
||||
//=============================================================================//
|
||||
#ifndef C_BASEANIMATING_H
|
||||
#define C_BASEANIMATING_H
|
||||
|
||||
#ifdef _WIN32
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
#include "c_baseentity.h"
|
||||
#include "studio.h"
|
||||
#include "utlvector.h"
|
||||
#include "ragdoll.h"
|
||||
#include "mouthinfo.h"
|
||||
// Shared activities
|
||||
#include "ai_activity.h"
|
||||
#include "animationlayer.h"
|
||||
#include "sequence_Transitioner.h"
|
||||
#include "bone_accessor.h"
|
||||
#include "bone_merge_cache.h"
|
||||
#include "ragdoll_shared.h"
|
||||
#include "tier0/threadtools.h"
|
||||
#include "datacache/idatacache.h"
|
||||
|
||||
#define LIPSYNC_POSEPARAM_NAME "mouth"
|
||||
#define NUM_HITBOX_FIRES 10
|
||||
|
||||
/*
|
||||
class C_BaseClientShader
|
||||
{
|
||||
virtual void RenderMaterial( C_BaseEntity *pEntity, int count, const vec4_t *verts, const vec4_t *normals, const vec2_t *texcoords, vec4_t *lightvalues );
|
||||
};
|
||||
*/
|
||||
|
||||
class IRagdoll;
|
||||
class CIKContext;
|
||||
class CIKState;
|
||||
class ConVar;
|
||||
class C_RopeKeyframe;
|
||||
class CBoneBitList;
|
||||
class CBoneList;
|
||||
class KeyValues;
|
||||
class CJiggleBones;
|
||||
class IBoneSetup;
|
||||
FORWARD_DECLARE_HANDLE( memhandle_t );
|
||||
typedef unsigned short MDLHandle_t;
|
||||
|
||||
extern ConVar vcollide_wireframe;
|
||||
|
||||
|
||||
struct ClientModelRenderInfo_t : public ModelRenderInfo_t
|
||||
{
|
||||
// Added space for lighting origin override. Just allocated space, need to set base pointer
|
||||
matrix3x4_t lightingOffset;
|
||||
|
||||
// Added space for model to world matrix. Just allocated space, need to set base pointer
|
||||
matrix3x4_t modelToWorld;
|
||||
};
|
||||
|
||||
struct RagdollInfo_t
|
||||
{
|
||||
bool m_bActive;
|
||||
float m_flSaveTime;
|
||||
int m_nNumBones;
|
||||
Vector m_rgBonePos[MAXSTUDIOBONES];
|
||||
Quaternion m_rgBoneQuaternion[MAXSTUDIOBONES];
|
||||
};
|
||||
|
||||
|
||||
class CAttachmentData
|
||||
{
|
||||
public:
|
||||
matrix3x4_t m_AttachmentToWorld;
|
||||
QAngle m_angRotation;
|
||||
Vector m_vOriginVelocity;
|
||||
int m_nLastFramecount : 31;
|
||||
int m_bAnglesComputed : 1;
|
||||
};
|
||||
|
||||
|
||||
typedef unsigned int ClientSideAnimationListHandle_t;
|
||||
|
||||
#define INVALID_CLIENTSIDEANIMATION_LIST_HANDLE (ClientSideAnimationListHandle_t)~0
|
||||
|
||||
|
||||
class C_BaseAnimating : public C_BaseEntity, private IModelLoadCallback
|
||||
{
|
||||
public:
|
||||
DECLARE_CLASS( C_BaseAnimating, C_BaseEntity );
|
||||
DECLARE_CLIENTCLASS();
|
||||
DECLARE_PREDICTABLE();
|
||||
DECLARE_INTERPOLATION();
|
||||
|
||||
enum
|
||||
{
|
||||
NUM_POSEPAREMETERS = 24,
|
||||
NUM_BONECTRLS = 4
|
||||
};
|
||||
|
||||
C_BaseAnimating();
|
||||
~C_BaseAnimating();
|
||||
|
||||
virtual C_BaseAnimating* GetBaseAnimating() { return this; }
|
||||
|
||||
bool UsesPowerOfTwoFrameBufferTexture( void );
|
||||
|
||||
virtual bool Interpolate( float currentTime );
|
||||
virtual void Simulate();
|
||||
virtual void Release();
|
||||
|
||||
float GetAnimTimeInterval( void ) const;
|
||||
|
||||
virtual unsigned char GetClientSideFade( void );
|
||||
|
||||
// Get bone controller values.
|
||||
virtual void GetBoneControllers(float controllers[MAXSTUDIOBONECTRLS]);
|
||||
virtual float SetBoneController ( int iController, float flValue );
|
||||
|
||||
LocalFlexController_t GetNumFlexControllers( void );
|
||||
const char *GetFlexDescFacs( int iFlexDesc );
|
||||
const char *GetFlexControllerName( LocalFlexController_t iFlexController );
|
||||
const char *GetFlexControllerType( LocalFlexController_t iFlexController );
|
||||
|
||||
virtual void GetAimEntOrigin( IClientEntity *pAttachedTo, Vector *pAbsOrigin, QAngle *pAbsAngles );
|
||||
|
||||
// Computes a box that surrounds all hitboxes
|
||||
bool ComputeHitboxSurroundingBox( Vector *pVecWorldMins, Vector *pVecWorldMaxs );
|
||||
bool ComputeEntitySpaceHitboxSurroundingBox( Vector *pVecWorldMins, Vector *pVecWorldMaxs );
|
||||
|
||||
// Gets the hitbox-to-world transforms, returns false if there was a problem
|
||||
bool HitboxToWorldTransforms( matrix3x4_t *pHitboxToWorld[MAXSTUDIOBONES] );
|
||||
|
||||
// base model functionality
|
||||
float ClampCycle( float cycle, bool isLooping );
|
||||
virtual void GetPoseParameters( CStudioHdr *pStudioHdr, float poseParameter[MAXSTUDIOPOSEPARAM] );
|
||||
virtual void BuildTransformations( CStudioHdr *pStudioHdr, Vector *pos, Quaternion q[], const matrix3x4_t& cameraTransform, int boneMask, CBoneBitList &boneComputed );
|
||||
virtual void ApplyBoneMatrixTransform( matrix3x4_t& transform );
|
||||
virtual int VPhysicsGetObjectList( IPhysicsObject **pList, int listMax );
|
||||
|
||||
// model specific
|
||||
virtual bool SetupBones( matrix3x4_t *pBoneToWorldOut, int nMaxBones, int boneMask, float currentTime );
|
||||
virtual void UpdateIKLocks( float currentTime );
|
||||
virtual void CalculateIKLocks( float currentTime );
|
||||
virtual bool ShouldDraw();
|
||||
virtual void UpdateVisibility() OVERRIDE;
|
||||
virtual int DrawModel( int flags );
|
||||
virtual int InternalDrawModel( int flags );
|
||||
virtual bool OnInternalDrawModel( ClientModelRenderInfo_t *pInfo );
|
||||
virtual bool OnPostInternalDrawModel( ClientModelRenderInfo_t *pInfo );
|
||||
void DoInternalDrawModel( ClientModelRenderInfo_t *pInfo, DrawModelState_t *pState, matrix3x4_t *pBoneToWorldArray = NULL );
|
||||
|
||||
virtual IMaterial* GetEconWeaponMaterialOverride( int iTeam ) { return NULL; }
|
||||
|
||||
//
|
||||
virtual CMouthInfo *GetMouth();
|
||||
virtual void ControlMouth( CStudioHdr *pStudioHdr );
|
||||
|
||||
// override in sub-classes
|
||||
virtual void DoAnimationEvents( CStudioHdr *pStudio );
|
||||
virtual void FireEvent( const Vector& origin, const QAngle& angles, int event, const char *options );
|
||||
virtual void FireObsoleteEvent( const Vector& origin, const QAngle& angles, int event, const char *options );
|
||||
virtual const char* ModifyEventParticles( const char* token ) { return token; }
|
||||
|
||||
// Parses and distributes muzzle flash events
|
||||
virtual bool DispatchMuzzleEffect( const char *options, bool isFirstPerson );
|
||||
|
||||
// virtual void AllocateMaterials( void );
|
||||
// virtual void FreeMaterials( void );
|
||||
|
||||
virtual void ValidateModelIndex( void );
|
||||
virtual CStudioHdr *OnNewModel( void );
|
||||
CStudioHdr *GetModelPtr() const;
|
||||
void InvalidateMdlCache();
|
||||
|
||||
virtual void SetPredictable( bool state );
|
||||
void UseClientSideAnimation();
|
||||
|
||||
// C_BaseClientShader **p_ClientShaders;
|
||||
|
||||
virtual void StandardBlendingRules( CStudioHdr *pStudioHdr, Vector pos[], Quaternion q[], float currentTime, int boneMask );
|
||||
void UnragdollBlend( CStudioHdr *hdr, Vector pos[], Quaternion q[], float currentTime );
|
||||
|
||||
void MaintainSequenceTransitions( IBoneSetup &boneSetup, float flCycle, Vector pos[], Quaternion q[] );
|
||||
virtual void AccumulateLayers( IBoneSetup &boneSetup, Vector pos[], Quaternion q[], float currentTime );
|
||||
|
||||
virtual void ChildLayerBlend( Vector pos[], Quaternion q[], float currentTime, int boneMask );
|
||||
|
||||
// Attachments
|
||||
int LookupAttachment( const char *pAttachmentName );
|
||||
int LookupRandomAttachment( const char *pAttachmentNameSubstring );
|
||||
|
||||
int LookupPoseParameter( CStudioHdr *pStudioHdr, const char *szName );
|
||||
inline int LookupPoseParameter( const char *szName ) { return LookupPoseParameter(GetModelPtr(), szName); }
|
||||
|
||||
float SetPoseParameter( CStudioHdr *pStudioHdr, const char *szName, float flValue );
|
||||
inline float SetPoseParameter( const char *szName, float flValue ) { return SetPoseParameter( GetModelPtr(), szName, flValue ); }
|
||||
float SetPoseParameter( CStudioHdr *pStudioHdr, int iParameter, float flValue );
|
||||
inline float SetPoseParameter( int iParameter, float flValue ) { return SetPoseParameter( GetModelPtr(), iParameter, flValue ); }
|
||||
|
||||
float GetPoseParameter( int iPoseParameter );
|
||||
|
||||
bool GetPoseParameterRange( int iPoseParameter, float &minValue, float &maxValue );
|
||||
|
||||
int LookupBone( const char *szName );
|
||||
void GetBonePosition( int iBone, Vector &origin, QAngle &angles );
|
||||
void GetBoneTransform( int iBone, matrix3x4_t &pBoneToWorld );
|
||||
|
||||
//=============================================================================
|
||||
// HPE_BEGIN:
|
||||
// [menglish] Finds the bone associated with the given hitbox
|
||||
//=============================================================================
|
||||
|
||||
int GetHitboxBone( int hitboxIndex );
|
||||
|
||||
//=============================================================================
|
||||
// HPE_END
|
||||
//=============================================================================
|
||||
|
||||
// Bone attachments
|
||||
virtual void AttachEntityToBone( C_BaseAnimating* attachTarget, int boneIndexAttached=-1, Vector bonePosition=Vector(0,0,0), QAngle boneAngles=QAngle(0,0,0) );
|
||||
void AddBoneAttachment( C_BaseAnimating* newBoneAttachment );
|
||||
void RemoveBoneAttachment( C_BaseAnimating* boneAttachment );
|
||||
void RemoveBoneAttachments();
|
||||
void DestroyBoneAttachments();
|
||||
void MoveBoneAttachments( C_BaseAnimating* attachTarget );
|
||||
int GetNumBoneAttachments();
|
||||
C_BaseAnimating* GetBoneAttachment( int i );
|
||||
virtual void NotifyBoneAttached( C_BaseAnimating* attachTarget );
|
||||
virtual void UpdateBoneAttachments( void );
|
||||
|
||||
//bool solveIK(float a, float b, const Vector &Foot, const Vector &Knee1, Vector &Knee2);
|
||||
//void DebugIK( mstudioikchain_t *pikchain );
|
||||
|
||||
virtual void PreDataUpdate( DataUpdateType_t updateType );
|
||||
virtual void PostDataUpdate( DataUpdateType_t updateType );
|
||||
virtual int RestoreData( const char *context, int slot, int type );
|
||||
|
||||
virtual void NotifyShouldTransmit( ShouldTransmitState_t state );
|
||||
virtual void OnPreDataChanged( DataUpdateType_t updateType );
|
||||
virtual void OnDataChanged( DataUpdateType_t updateType );
|
||||
virtual void AddEntity( void );
|
||||
|
||||
// This can be used to force client side animation to be on. Only use if you know what you're doing!
|
||||
// Normally, the server entity should set this.
|
||||
void ForceClientSideAnimationOn();
|
||||
|
||||
void AddToClientSideAnimationList();
|
||||
void RemoveFromClientSideAnimationList( bool bBeingDestroyed = false );
|
||||
|
||||
virtual bool IsSelfAnimating();
|
||||
virtual void ResetLatched();
|
||||
|
||||
// implements these so ragdolls can handle frustum culling & leaf visibility
|
||||
virtual void GetRenderBounds( Vector& theMins, Vector& theMaxs );
|
||||
virtual const Vector& GetRenderOrigin( void );
|
||||
virtual const QAngle& GetRenderAngles( void );
|
||||
|
||||
virtual bool GetSoundSpatialization( SpatializationInfo_t& info );
|
||||
|
||||
// Attachments.
|
||||
bool GetAttachment( const char *szName, Vector &absOrigin );
|
||||
bool GetAttachment( const char *szName, Vector &absOrigin, QAngle &absAngles );
|
||||
|
||||
// Inherited from C_BaseEntity
|
||||
virtual bool GetAttachment( int number, Vector &origin );
|
||||
virtual bool GetAttachment( int number, Vector &origin, QAngle &angles );
|
||||
virtual bool GetAttachment( int number, matrix3x4_t &matrix );
|
||||
virtual bool GetAttachmentVelocity( int number, Vector &originVel, Quaternion &angleVel );
|
||||
|
||||
// Returns the attachment in local space
|
||||
bool GetAttachmentLocal( int iAttachment, matrix3x4_t &attachmentToLocal );
|
||||
bool GetAttachmentLocal( int iAttachment, Vector &origin, QAngle &angles );
|
||||
bool GetAttachmentLocal( int iAttachment, Vector &origin );
|
||||
|
||||
bool GetRootBone( matrix3x4_t &rootBone );
|
||||
|
||||
// Should this object cast render-to-texture shadows?
|
||||
virtual ShadowType_t ShadowCastType();
|
||||
|
||||
// Should we collide?
|
||||
virtual CollideType_t GetCollideType( void );
|
||||
|
||||
virtual bool TestCollision( const Ray_t &ray, unsigned int fContentsMask, trace_t& tr );
|
||||
virtual bool TestHitboxes( const Ray_t &ray, unsigned int fContentsMask, trace_t& tr );
|
||||
|
||||
// returns true if we're currently being ragdolled
|
||||
bool IsRagdoll() const;
|
||||
bool IsAboutToRagdoll() const;
|
||||
virtual C_BaseAnimating *BecomeRagdollOnClient();
|
||||
C_BaseAnimating *CreateRagdollCopy();
|
||||
bool InitAsClientRagdoll( const matrix3x4_t *pDeltaBones0, const matrix3x4_t *pDeltaBones1, const matrix3x4_t *pCurrentBonePosition, float boneDt, bool bFixedConstraints=false );
|
||||
void IgniteRagdoll( C_BaseAnimating *pSource );
|
||||
void TransferDissolveFrom( C_BaseAnimating *pSource );
|
||||
virtual void SaveRagdollInfo( int numbones, const matrix3x4_t &cameraTransform, CBoneAccessor &pBoneToWorld );
|
||||
virtual bool RetrieveRagdollInfo( Vector *pos, Quaternion *q );
|
||||
virtual void Clear( void );
|
||||
void ClearRagdoll();
|
||||
void CreateUnragdollInfo( C_BaseAnimating *pRagdoll );
|
||||
bool ForceSetupBonesAtTime( matrix3x4_t *pBonesOut, float flTime );
|
||||
virtual bool GetRagdollInitBoneArrays( matrix3x4_t *pDeltaBones0, matrix3x4_t *pDeltaBones1, matrix3x4_t *pCurrentBones, float boneDt );
|
||||
|
||||
// For shadows rendering the correct body + sequence...
|
||||
virtual int GetBody() { return m_nBody; }
|
||||
virtual int GetSkin() { return m_nSkin; }
|
||||
|
||||
bool IsOnFire() { return ( (GetFlags() & FL_ONFIRE) != 0 ); }
|
||||
|
||||
inline float GetPlaybackRate();
|
||||
inline void SetPlaybackRate( float rate );
|
||||
|
||||
void SetModelScale( float scale, float change_duration = 0.0f );
|
||||
float GetModelScale() const { return m_flModelScale; }
|
||||
inline bool IsModelScaleFractional() const; /// very fast way to ask if the model scale is < 1.0f (faster than if (GetModelScale() < 1.0f) )
|
||||
inline bool IsModelScaled() const;
|
||||
void UpdateModelScale( void );
|
||||
virtual void RefreshCollisionBounds( void );
|
||||
|
||||
int GetSequence();
|
||||
virtual void SetSequence(int nSequence);
|
||||
inline void ResetSequence(int nSequence);
|
||||
float GetSequenceGroundSpeed( CStudioHdr *pStudioHdr, int iSequence );
|
||||
inline float GetSequenceGroundSpeed( int iSequence ) { return GetSequenceGroundSpeed(GetModelPtr(), iSequence); }
|
||||
bool IsSequenceLooping( CStudioHdr *pStudioHdr, int iSequence );
|
||||
inline bool IsSequenceLooping( int iSequence ) { return IsSequenceLooping(GetModelPtr(),iSequence); }
|
||||
float GetSequenceMoveDist( CStudioHdr *pStudioHdr, int iSequence );
|
||||
void GetSequenceLinearMotion( int iSequence, Vector *pVec );
|
||||
void GetBlendedLinearVelocity( Vector *pVec );
|
||||
int LookupSequence ( const char *label );
|
||||
int LookupActivity( const char *label );
|
||||
char const *GetSequenceName( int iSequence );
|
||||
char const *GetSequenceActivityName( int iSequence );
|
||||
Activity GetSequenceActivity( int iSequence );
|
||||
KeyValues *GetSequenceKeyValues( int iSequence );
|
||||
virtual void StudioFrameAdvance(); // advance animation frame to some time in the future
|
||||
|
||||
// Clientside animation
|
||||
virtual float FrameAdvance( float flInterval = 0.0f );
|
||||
virtual float GetSequenceCycleRate( CStudioHdr *pStudioHdr, int iSequence );
|
||||
virtual void UpdateClientSideAnimation();
|
||||
void ClientSideAnimationChanged();
|
||||
virtual unsigned int ComputeClientSideAnimationFlags();
|
||||
|
||||
virtual void ResetClientsideFrame( void ) { SetCycle( 0 ); }
|
||||
|
||||
void SetCycle( float flCycle );
|
||||
float GetCycle() const;
|
||||
|
||||
void SetBodygroup( int iGroup, int iValue );
|
||||
int GetBodygroup( int iGroup );
|
||||
|
||||
const char *GetBodygroupName( int iGroup );
|
||||
int FindBodygroupByName( const char *name );
|
||||
int GetBodygroupCount( int iGroup );
|
||||
int GetNumBodyGroups( void );
|
||||
|
||||
class CBoneCache *GetBoneCache( CStudioHdr *pStudioHdr );
|
||||
void SetHitboxSet( int setnum );
|
||||
void SetHitboxSetByName( const char *setname );
|
||||
int GetHitboxSet( void );
|
||||
char const *GetHitboxSetName( void );
|
||||
int GetHitboxSetCount( void );
|
||||
void DrawClientHitboxes( float duration = 0.0f, bool monocolor = false );
|
||||
|
||||
C_BaseAnimating* FindFollowedEntity();
|
||||
|
||||
virtual bool IsActivityFinished( void ) { return m_bSequenceFinished; }
|
||||
inline bool IsSequenceFinished( void );
|
||||
inline bool SequenceLoops( void ) { return m_bSequenceLoops; }
|
||||
|
||||
// All view model attachments origins are stretched so you can place entities at them and
|
||||
// they will match up with where the attachment winds up being drawn on the view model, since
|
||||
// the view models are drawn with a different FOV.
|
||||
//
|
||||
// If you're drawing something inside of a view model's DrawModel() function, then you want the
|
||||
// original attachment origin instead of the adjusted one. To get that, call this on the
|
||||
// adjusted attachment origin.
|
||||
virtual void UncorrectViewModelAttachment( Vector &vOrigin ) {}
|
||||
|
||||
// Call this if SetupBones() has already been called this frame but you need to move the
|
||||
// entity and rerender.
|
||||
void InvalidateBoneCache();
|
||||
bool IsBoneCacheValid() const; // Returns true if the bone cache is considered good for this frame.
|
||||
void GetCachedBoneMatrix( int boneIndex, matrix3x4_t &out );
|
||||
|
||||
// Wrappers for CBoneAccessor.
|
||||
const matrix3x4_t& GetBone( int iBone ) const;
|
||||
matrix3x4_t& GetBoneForWrite( int iBone );
|
||||
|
||||
// Used for debugging. Will produce asserts if someone tries to setup bones or
|
||||
// attachments before it's allowed.
|
||||
// Use the "AutoAllowBoneAccess" class to auto push/pop bone access.
|
||||
// Use a distinct "tag" when pushing/popping - asserts when push/pop tags do not match.
|
||||
struct AutoAllowBoneAccess
|
||||
{
|
||||
AutoAllowBoneAccess( bool bAllowForNormalModels, bool bAllowForViewModels );
|
||||
~AutoAllowBoneAccess( void );
|
||||
};
|
||||
static void PushAllowBoneAccess( bool bAllowForNormalModels, bool bAllowForViewModels, char const *tagPush );
|
||||
static void PopBoneAccess( char const *tagPop );
|
||||
static void ThreadedBoneSetup();
|
||||
static void InitBoneSetupThreadPool();
|
||||
static void ShutdownBoneSetupThreadPool();
|
||||
|
||||
// Invalidate bone caches so all SetupBones() calls force bone transforms to be regenerated.
|
||||
static void InvalidateBoneCaches();
|
||||
|
||||
// Purpose: My physics object has been updated, react or extract data
|
||||
virtual void VPhysicsUpdate( IPhysicsObject *pPhysics );
|
||||
|
||||
void DisableMuzzleFlash(); // Turn off the muzzle flash (ie: signal that we handled the server's event).
|
||||
virtual void DoMuzzleFlash(); // Force a muzzle flash event. Note: this only QUEUES an event, so
|
||||
// ProcessMuzzleFlashEvent will get called later.
|
||||
bool ShouldMuzzleFlash() const; // Is the muzzle flash event on?
|
||||
|
||||
// This is called to do the actual muzzle flash effect.
|
||||
virtual void ProcessMuzzleFlashEvent();
|
||||
|
||||
// Update client side animations
|
||||
static void UpdateClientSideAnimations();
|
||||
|
||||
// Load the model's keyvalues section and create effects listed inside it
|
||||
void InitModelEffects( void );
|
||||
|
||||
// Sometimes the server wants to update the client's cycle to get the two to run in sync (for proper hit detection)
|
||||
virtual void SetServerIntendedCycle( float intended ) { (void)intended; }
|
||||
virtual float GetServerIntendedCycle( void ) { return -1.0f; }
|
||||
|
||||
// For prediction
|
||||
int SelectWeightedSequence ( int activity );
|
||||
int SelectWeightedSequenceFromModifiers( Activity activity, CUtlSymbol *pActivityModifiers, int iModifierCount );
|
||||
void ResetSequenceInfo( void );
|
||||
float SequenceDuration( void );
|
||||
float SequenceDuration( CStudioHdr *pStudioHdr, int iSequence );
|
||||
inline float SequenceDuration( int iSequence ) { return SequenceDuration(GetModelPtr(), iSequence); }
|
||||
int FindTransitionSequence( int iCurrentSequence, int iGoalSequence, int *piDir );
|
||||
|
||||
void RagdollMoved( void );
|
||||
|
||||
virtual void GetToolRecordingState( KeyValues *msg );
|
||||
virtual void CleanupToolRecordingState( KeyValues *msg );
|
||||
|
||||
void SetReceivedSequence( void );
|
||||
virtual bool ShouldResetSequenceOnNewModel( void );
|
||||
|
||||
virtual bool IsViewModel() const;
|
||||
virtual void UpdateOnRemove( void );
|
||||
|
||||
protected:
|
||||
// View models scale their attachment positions to account for FOV. To get the unmodified
|
||||
// attachment position (like if you're rendering something else during the view model's DrawModel call),
|
||||
// use TransformViewModelAttachmentToWorld.
|
||||
virtual void FormatViewModelAttachment( int nAttachment, matrix3x4_t &attachmentToWorld ) {}
|
||||
|
||||
// View models say yes to this.
|
||||
bool IsBoneAccessAllowed() const;
|
||||
CMouthInfo& MouthInfo();
|
||||
|
||||
// Models used in a ModelPanel say yes to this
|
||||
virtual bool IsMenuModel() const;
|
||||
|
||||
// Allow studio models to tell C_BaseEntity what their m_nBody value is
|
||||
virtual int GetStudioBody( void ) { return m_nBody; }
|
||||
|
||||
virtual bool CalcAttachments();
|
||||
|
||||
private:
|
||||
// This method should return true if the bones have changed + SetupBones needs to be called
|
||||
virtual float LastBoneChangedTime() { return FLT_MAX; }
|
||||
|
||||
CBoneList* RecordBones( CStudioHdr *hdr, matrix3x4_t *pBoneState );
|
||||
|
||||
bool PutAttachment( int number, const matrix3x4_t &attachmentToWorld );
|
||||
void TermRopes();
|
||||
|
||||
void DelayedInitModelEffects( void );
|
||||
|
||||
void UpdateRelevantInterpolatedVars();
|
||||
void AddBaseAnimatingInterpolatedVars();
|
||||
void RemoveBaseAnimatingInterpolatedVars();
|
||||
|
||||
public:
|
||||
CRagdoll *m_pRagdoll;
|
||||
|
||||
// Texture group to use
|
||||
int m_nSkin;
|
||||
|
||||
// Object bodygroup
|
||||
int m_nBody;
|
||||
|
||||
// Hitbox set to use (default 0)
|
||||
int m_nHitboxSet;
|
||||
|
||||
CSequenceTransitioner m_SequenceTransitioner;
|
||||
|
||||
protected:
|
||||
CIKContext *m_pIk;
|
||||
|
||||
int m_iEyeAttachment;
|
||||
|
||||
// Animation playback framerate
|
||||
float m_flPlaybackRate;
|
||||
|
||||
// Decomposed ragdoll info
|
||||
bool m_bStoreRagdollInfo;
|
||||
RagdollInfo_t *m_pRagdollInfo;
|
||||
Vector m_vecForce;
|
||||
int m_nForceBone;
|
||||
|
||||
// Is bone cache valid
|
||||
// bone transformation matrix
|
||||
unsigned long m_iMostRecentModelBoneCounter;
|
||||
unsigned long m_iMostRecentBoneSetupRequest;
|
||||
int m_iPrevBoneMask;
|
||||
int m_iAccumulatedBoneMask;
|
||||
|
||||
CBoneAccessor m_BoneAccessor;
|
||||
CThreadFastMutex m_BoneSetupLock;
|
||||
|
||||
ClientSideAnimationListHandle_t m_ClientSideAnimationListHandle;
|
||||
|
||||
// Client-side animation
|
||||
bool m_bClientSideFrameReset;
|
||||
|
||||
// Bone attachments. Used for attaching one BaseAnimating to another's bones.
|
||||
// Client side only.
|
||||
CUtlVector<CHandle<C_BaseAnimating> > m_BoneAttachments;
|
||||
int m_boneIndexAttached;
|
||||
Vector m_bonePosition;
|
||||
QAngle m_boneAngles;
|
||||
CHandle<C_BaseAnimating> m_pAttachedTo;
|
||||
|
||||
protected:
|
||||
|
||||
float m_fadeMinDist;
|
||||
float m_fadeMaxDist;
|
||||
float m_flFadeScale;
|
||||
|
||||
private:
|
||||
|
||||
float m_flGroundSpeed; // computed linear movement rate for current sequence
|
||||
float m_flLastEventCheck; // cycle index of when events were last checked
|
||||
bool m_bSequenceFinished;// flag set when StudioAdvanceFrame moves across a frame boundry
|
||||
bool m_bSequenceLoops; // true if the sequence loops
|
||||
|
||||
// Mouth lipsync/envelope following values
|
||||
CMouthInfo m_mouth;
|
||||
|
||||
CNetworkVar( float, m_flModelScale );
|
||||
|
||||
// Animation blending factors
|
||||
float m_flPoseParameter[MAXSTUDIOPOSEPARAM];
|
||||
CInterpolatedVarArray< float, MAXSTUDIOPOSEPARAM > m_iv_flPoseParameter;
|
||||
float m_flOldPoseParameters[MAXSTUDIOPOSEPARAM];
|
||||
|
||||
int m_nPrevSequence;
|
||||
int m_nRestoreSequence;
|
||||
|
||||
// Ropes that got spawned when the model was created.
|
||||
CUtlLinkedList<C_RopeKeyframe*,unsigned short> m_Ropes;
|
||||
|
||||
// event processing info
|
||||
float m_flPrevEventCycle;
|
||||
int m_nEventSequence;
|
||||
|
||||
float m_flEncodedController[MAXSTUDIOBONECTRLS];
|
||||
CInterpolatedVarArray< float, MAXSTUDIOBONECTRLS > m_iv_flEncodedController;
|
||||
float m_flOldEncodedController[MAXSTUDIOBONECTRLS];
|
||||
|
||||
// Clientside animation
|
||||
bool m_bClientSideAnimation;
|
||||
bool m_bLastClientSideFrameReset;
|
||||
|
||||
int m_nNewSequenceParity;
|
||||
int m_nResetEventsParity;
|
||||
|
||||
int m_nPrevNewSequenceParity;
|
||||
int m_nPrevResetEventsParity;
|
||||
|
||||
bool m_builtRagdoll;
|
||||
Vector m_vecPreRagdollMins;
|
||||
Vector m_vecPreRagdollMaxs;
|
||||
|
||||
// Current animation sequence
|
||||
int m_nSequence;
|
||||
bool m_bReceivedSequence;
|
||||
|
||||
// Current cycle location from server
|
||||
protected:
|
||||
float m_flCycle;
|
||||
CInterpolatedVar< float > m_iv_flCycle;
|
||||
float m_flOldCycle;
|
||||
bool m_bNoModelParticles;
|
||||
|
||||
private:
|
||||
float m_flOldModelScale;
|
||||
int m_nOldSequence;
|
||||
CBoneMergeCache *m_pBoneMergeCache; // This caches the strcmp lookups that it has to do
|
||||
// when merg
|
||||
|
||||
CUtlVector< matrix3x4_t > m_CachedBoneData; // never access this directly. Use m_BoneAccessor.
|
||||
memhandle_t m_hitboxBoneCacheHandle;
|
||||
float m_flLastBoneSetupTime;
|
||||
CJiggleBones *m_pJiggleBones;
|
||||
|
||||
// Calculated attachment points
|
||||
CUtlVector<CAttachmentData> m_Attachments;
|
||||
|
||||
bool SetupBones_AttachmentHelper( CStudioHdr *pStudioHdr );
|
||||
|
||||
EHANDLE m_hLightingOrigin;
|
||||
EHANDLE m_hLightingOriginRelative;
|
||||
|
||||
// These are compared against each other to determine if the entity should muzzle flash.
|
||||
CNetworkVar( unsigned char, m_nMuzzleFlashParity );
|
||||
unsigned char m_nOldMuzzleFlashParity;
|
||||
|
||||
bool m_bInitModelEffects;
|
||||
bool m_bDelayInitModelEffects;
|
||||
|
||||
// Dynamic models
|
||||
bool m_bDynamicModelAllowed;
|
||||
bool m_bDynamicModelPending;
|
||||
bool m_bResetSequenceInfoOnLoad;
|
||||
CRefCountedModelIndex m_AutoRefModelIndex;
|
||||
public:
|
||||
void EnableDynamicModels() { m_bDynamicModelAllowed = true; }
|
||||
bool IsDynamicModelLoading() const { return m_bDynamicModelPending; }
|
||||
private:
|
||||
virtual void OnModelLoadComplete( const model_t* pModel );
|
||||
|
||||
private:
|
||||
void LockStudioHdr();
|
||||
void UnlockStudioHdr();
|
||||
mutable CStudioHdr *m_pStudioHdr;
|
||||
mutable MDLHandle_t m_hStudioHdr;
|
||||
CThreadFastMutex m_StudioHdrInitLock;
|
||||
bool m_bHasAttachedParticles;
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
RAGDOLL_FRICTION_OFF = -2,
|
||||
RAGDOLL_FRICTION_NONE,
|
||||
RAGDOLL_FRICTION_IN,
|
||||
RAGDOLL_FRICTION_HOLD,
|
||||
RAGDOLL_FRICTION_OUT,
|
||||
};
|
||||
|
||||
class C_ClientRagdoll : public C_BaseAnimating, public IPVSNotify
|
||||
{
|
||||
|
||||
public:
|
||||
C_ClientRagdoll( bool bRestoring = true );
|
||||
DECLARE_CLASS( C_ClientRagdoll, C_BaseAnimating );
|
||||
DECLARE_DATADESC();
|
||||
|
||||
// inherited from IPVSNotify
|
||||
virtual void OnPVSStatusChanged( bool bInPVS );
|
||||
|
||||
virtual void Release( void );
|
||||
virtual void SetupWeights( const matrix3x4_t *pBoneToWorld, int nFlexWeightCount, float *pFlexWeights, float *pFlexDelayedWeights );
|
||||
virtual void ImpactTrace( trace_t *pTrace, int iDamageType, const char *pCustomImpactName );
|
||||
void ClientThink( void );
|
||||
void ReleaseRagdoll( void ) { m_bReleaseRagdoll = true; }
|
||||
bool ShouldSavePhysics( void ) { return true; }
|
||||
virtual void OnSave();
|
||||
virtual void OnRestore();
|
||||
virtual int ObjectCaps( void ) { return BaseClass::ObjectCaps() | FCAP_SAVE_NON_NETWORKABLE; }
|
||||
virtual IPVSNotify* GetPVSNotifyInterface() { return this; }
|
||||
|
||||
void HandleAnimatedFriction( void );
|
||||
virtual void SUB_Remove( void );
|
||||
|
||||
void FadeOut( void );
|
||||
virtual float LastBoneChangedTime();
|
||||
|
||||
bool m_bFadeOut;
|
||||
bool m_bImportant;
|
||||
float m_flEffectTime;
|
||||
|
||||
private:
|
||||
int m_iCurrentFriction;
|
||||
int m_iMinFriction;
|
||||
int m_iMaxFriction;
|
||||
float m_flFrictionModTime;
|
||||
float m_flFrictionTime;
|
||||
|
||||
int m_iFrictionAnimState;
|
||||
bool m_bReleaseRagdoll;
|
||||
|
||||
bool m_bFadingOut;
|
||||
|
||||
float m_flScaleEnd[NUM_HITBOX_FIRES];
|
||||
float m_flScaleTimeStart[NUM_HITBOX_FIRES];
|
||||
float m_flScaleTimeEnd[NUM_HITBOX_FIRES];
|
||||
};
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Serves the 90% case of calling SetSequence / ResetSequenceInfo.
|
||||
//-----------------------------------------------------------------------------
|
||||
inline void C_BaseAnimating::ResetSequence(int nSequence)
|
||||
{
|
||||
SetSequence( nSequence );
|
||||
ResetSequenceInfo();
|
||||
}
|
||||
|
||||
inline float C_BaseAnimating::GetPlaybackRate()
|
||||
{
|
||||
return m_flPlaybackRate;
|
||||
}
|
||||
|
||||
inline void C_BaseAnimating::SetPlaybackRate( float rate )
|
||||
{
|
||||
m_flPlaybackRate = rate;
|
||||
}
|
||||
|
||||
inline const matrix3x4_t& C_BaseAnimating::GetBone( int iBone ) const
|
||||
{
|
||||
return m_BoneAccessor.GetBone( iBone );
|
||||
}
|
||||
|
||||
inline matrix3x4_t& C_BaseAnimating::GetBoneForWrite( int iBone )
|
||||
{
|
||||
return m_BoneAccessor.GetBoneForWrite( iBone );
|
||||
}
|
||||
|
||||
|
||||
inline bool C_BaseAnimating::ShouldMuzzleFlash() const
|
||||
{
|
||||
return m_nOldMuzzleFlashParity != m_nMuzzleFlashParity;
|
||||
}
|
||||
|
||||
inline float C_BaseAnimating::GetCycle() const
|
||||
{
|
||||
return m_flCycle;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: return a pointer to an updated studiomdl cache cache
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
inline CStudioHdr *C_BaseAnimating::GetModelPtr() const
|
||||
{
|
||||
if ( IsDynamicModelLoading() )
|
||||
return NULL;
|
||||
|
||||
#ifdef _DEBUG
|
||||
// GetModelPtr() is often called before OnNewModel() so go ahead and set it up first chance.
|
||||
// static IDataCacheSection *pModelCache = datacache->FindSection( "ModelData" );
|
||||
// AssertOnce( pModelCache->IsFrameLocking() );
|
||||
#endif
|
||||
if ( !m_pStudioHdr )
|
||||
{
|
||||
const_cast<C_BaseAnimating *>(this)->LockStudioHdr();
|
||||
}
|
||||
Assert( m_pStudioHdr ? m_pStudioHdr->GetRenderHdr() == mdlcache->GetStudioHdr(m_hStudioHdr) : m_hStudioHdr == MDLHANDLE_INVALID );
|
||||
return m_pStudioHdr;
|
||||
}
|
||||
|
||||
|
||||
inline void C_BaseAnimating::InvalidateMdlCache()
|
||||
{
|
||||
UnlockStudioHdr();
|
||||
}
|
||||
|
||||
inline bool C_BaseAnimating::IsModelScaleFractional() const
|
||||
{
|
||||
return ( m_flModelScale < 1.0f );
|
||||
}
|
||||
|
||||
inline bool C_BaseAnimating::IsModelScaled() const
|
||||
{
|
||||
return ( m_flModelScale > 1.0f+FLT_EPSILON || m_flModelScale < 1.0f-FLT_EPSILON );
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Sequence access
|
||||
//-----------------------------------------------------------------------------
|
||||
inline int C_BaseAnimating::GetSequence()
|
||||
{
|
||||
return m_nSequence;
|
||||
}
|
||||
|
||||
inline bool C_BaseAnimating::IsSequenceFinished( void )
|
||||
{
|
||||
return m_bSequenceFinished;
|
||||
}
|
||||
|
||||
inline float C_BaseAnimating::SequenceDuration( void )
|
||||
{
|
||||
return SequenceDuration( GetSequence() );
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Mouth
|
||||
//-----------------------------------------------------------------------------
|
||||
inline CMouthInfo& C_BaseAnimating::MouthInfo()
|
||||
{
|
||||
return m_mouth;
|
||||
}
|
||||
|
||||
|
||||
// FIXME: move these to somewhere that makes sense
|
||||
void GetColumn( matrix3x4_t& src, int column, Vector &dest );
|
||||
void SetColumn( Vector &src, int column, matrix3x4_t& dest );
|
||||
|
||||
EXTERN_RECV_TABLE(DT_BaseAnimating);
|
||||
|
||||
|
||||
extern void DevMsgRT( PRINTF_FORMAT_STRING char const* pMsg, ... );
|
||||
|
||||
#endif // C_BASEANIMATING_H
|
||||
@@ -0,0 +1,566 @@
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
// $NoKeywords: $
|
||||
//=============================================================================//
|
||||
|
||||
#include "cbase.h"
|
||||
#include "c_baseanimatingoverlay.h"
|
||||
#include "bone_setup.h"
|
||||
#include "tier0/vprof.h"
|
||||
#include "engine/ivdebugoverlay.h"
|
||||
#include "datacache/imdlcache.h"
|
||||
#include "eventlist.h"
|
||||
|
||||
#include "dt_utlvector_recv.h"
|
||||
|
||||
// memdbgon must be the last include file in a .cpp file!!!
|
||||
#include "tier0/memdbgon.h"
|
||||
|
||||
extern ConVar r_sequence_debug;
|
||||
|
||||
C_BaseAnimatingOverlay::C_BaseAnimatingOverlay()
|
||||
{
|
||||
// FIXME: where does this initialization go now?
|
||||
//for ( int i=0; i < MAX_OVERLAYS; i++ )
|
||||
//{
|
||||
// memset( &m_Layer[i], 0, sizeof(m_Layer[0]) );
|
||||
// m_Layer[i].m_nOrder = MAX_OVERLAYS;
|
||||
//}
|
||||
|
||||
// FIXME: where does this initialization go now?
|
||||
// AddVar( m_Layer, &m_iv_AnimOverlay, LATCH_ANIMATION_VAR );
|
||||
}
|
||||
|
||||
#undef CBaseAnimatingOverlay
|
||||
|
||||
|
||||
|
||||
BEGIN_RECV_TABLE_NOBASE(CAnimationLayer, DT_Animationlayer)
|
||||
RecvPropInt( RECVINFO_NAME(m_nSequence, m_nSequence)),
|
||||
RecvPropFloat( RECVINFO_NAME(m_flCycle, m_flCycle)),
|
||||
RecvPropFloat( RECVINFO_NAME(m_flPrevCycle, m_flPrevCycle)),
|
||||
RecvPropFloat( RECVINFO_NAME(m_flWeight, m_flWeight)),
|
||||
RecvPropInt( RECVINFO_NAME(m_nOrder, m_nOrder))
|
||||
END_RECV_TABLE()
|
||||
|
||||
const char *s_m_iv_AnimOverlayNames[C_BaseAnimatingOverlay::MAX_OVERLAYS] =
|
||||
{
|
||||
"C_BaseAnimatingOverlay::m_iv_AnimOverlay00",
|
||||
"C_BaseAnimatingOverlay::m_iv_AnimOverlay01",
|
||||
"C_BaseAnimatingOverlay::m_iv_AnimOverlay02",
|
||||
"C_BaseAnimatingOverlay::m_iv_AnimOverlay03",
|
||||
"C_BaseAnimatingOverlay::m_iv_AnimOverlay04",
|
||||
"C_BaseAnimatingOverlay::m_iv_AnimOverlay05",
|
||||
"C_BaseAnimatingOverlay::m_iv_AnimOverlay06",
|
||||
"C_BaseAnimatingOverlay::m_iv_AnimOverlay07",
|
||||
"C_BaseAnimatingOverlay::m_iv_AnimOverlay08",
|
||||
"C_BaseAnimatingOverlay::m_iv_AnimOverlay09",
|
||||
"C_BaseAnimatingOverlay::m_iv_AnimOverlay10",
|
||||
"C_BaseAnimatingOverlay::m_iv_AnimOverlay11",
|
||||
"C_BaseAnimatingOverlay::m_iv_AnimOverlay12",
|
||||
"C_BaseAnimatingOverlay::m_iv_AnimOverlay13",
|
||||
"C_BaseAnimatingOverlay::m_iv_AnimOverlay14"
|
||||
};
|
||||
|
||||
void ResizeAnimationLayerCallback( void *pStruct, int offsetToUtlVector, int len )
|
||||
{
|
||||
C_BaseAnimatingOverlay *pEnt = (C_BaseAnimatingOverlay*)pStruct;
|
||||
CUtlVector < C_AnimationLayer > *pVec = &pEnt->m_AnimOverlay;
|
||||
CUtlVector< CInterpolatedVar< C_AnimationLayer > > *pVecIV = &pEnt->m_iv_AnimOverlay;
|
||||
|
||||
Assert( (char*)pVec - (char*)pEnt == offsetToUtlVector );
|
||||
Assert( pVec->Count() == pVecIV->Count() );
|
||||
Assert( pVec->Count() <= C_BaseAnimatingOverlay::MAX_OVERLAYS );
|
||||
|
||||
int diff = len - pVec->Count();
|
||||
|
||||
|
||||
|
||||
if ( diff == 0 )
|
||||
return;
|
||||
|
||||
// remove all entries
|
||||
for ( int i=0; i < pVec->Count(); i++ )
|
||||
{
|
||||
pEnt->RemoveVar( &pVec->Element( i ) );
|
||||
}
|
||||
|
||||
// adjust vector sizes
|
||||
if ( diff > 0 )
|
||||
{
|
||||
pVec->AddMultipleToTail( diff );
|
||||
pVecIV->AddMultipleToTail( diff );
|
||||
}
|
||||
else
|
||||
{
|
||||
pVec->RemoveMultiple( len, -diff );
|
||||
pVecIV->RemoveMultiple( len, -diff );
|
||||
}
|
||||
|
||||
// Rebind all the variables in the ent's list.
|
||||
for ( int i=0; i < len; i++ )
|
||||
{
|
||||
IInterpolatedVar *pWatcher = &pVecIV->Element( i );
|
||||
pWatcher->SetDebugName( s_m_iv_AnimOverlayNames[i] );
|
||||
pEnt->AddVar( &pVec->Element( i ), pWatcher, LATCH_ANIMATION_VAR, true );
|
||||
}
|
||||
// FIXME: need to set historical values of nOrder in pVecIV to MAX_OVERLAY
|
||||
|
||||
}
|
||||
|
||||
|
||||
BEGIN_RECV_TABLE_NOBASE( C_BaseAnimatingOverlay, DT_OverlayVars )
|
||||
RecvPropUtlVector(
|
||||
RECVINFO_UTLVECTOR_SIZEFN( m_AnimOverlay, ResizeAnimationLayerCallback ),
|
||||
C_BaseAnimatingOverlay::MAX_OVERLAYS,
|
||||
RecvPropDataTable(NULL, 0, 0, &REFERENCE_RECV_TABLE( DT_Animationlayer ) ) )
|
||||
END_RECV_TABLE()
|
||||
|
||||
|
||||
IMPLEMENT_CLIENTCLASS_DT( C_BaseAnimatingOverlay, DT_BaseAnimatingOverlay, CBaseAnimatingOverlay )
|
||||
RecvPropDataTable( "overlay_vars", 0, 0, &REFERENCE_RECV_TABLE( DT_OverlayVars ) )
|
||||
END_RECV_TABLE()
|
||||
|
||||
BEGIN_PREDICTION_DATA( C_BaseAnimatingOverlay )
|
||||
|
||||
/*
|
||||
DEFINE_FIELD( C_BaseAnimatingOverlay, m_Layer[0][2].m_nSequence, FIELD_INTEGER ),
|
||||
DEFINE_FIELD( C_BaseAnimatingOverlay, m_Layer[0][2].m_flCycle, FIELD_FLOAT ),
|
||||
DEFINE_FIELD( C_BaseAnimatingOverlay, m_Layer[0][2].m_flPlaybackRate, FIELD_FLOAT),
|
||||
DEFINE_FIELD( C_BaseAnimatingOverlay, m_Layer[0][2].m_flWeight, FIELD_FLOAT),
|
||||
DEFINE_FIELD( C_BaseAnimatingOverlay, m_Layer[1][2].m_nSequence, FIELD_INTEGER ),
|
||||
DEFINE_FIELD( C_BaseAnimatingOverlay, m_Layer[1][2].m_flCycle, FIELD_FLOAT ),
|
||||
DEFINE_FIELD( C_BaseAnimatingOverlay, m_Layer[1][2].m_flPlaybackRate, FIELD_FLOAT),
|
||||
DEFINE_FIELD( C_BaseAnimatingOverlay, m_Layer[1][2].m_flWeight, FIELD_FLOAT),
|
||||
DEFINE_FIELD( C_BaseAnimatingOverlay, m_Layer[2][2].m_nSequence, FIELD_INTEGER ),
|
||||
DEFINE_FIELD( C_BaseAnimatingOverlay, m_Layer[2][2].m_flCycle, FIELD_FLOAT ),
|
||||
DEFINE_FIELD( C_BaseAnimatingOverlay, m_Layer[2][2].m_flPlaybackRate, FIELD_FLOAT),
|
||||
DEFINE_FIELD( C_BaseAnimatingOverlay, m_Layer[2][2].m_flWeight, FIELD_FLOAT),
|
||||
DEFINE_FIELD( C_BaseAnimatingOverlay, m_Layer[3][2].m_nSequence, FIELD_INTEGER ),
|
||||
DEFINE_FIELD( C_BaseAnimatingOverlay, m_Layer[3][2].m_flCycle, FIELD_FLOAT ),
|
||||
DEFINE_FIELD( C_BaseAnimatingOverlay, m_Layer[3][2].m_flPlaybackRate, FIELD_FLOAT),
|
||||
DEFINE_FIELD( C_BaseAnimatingOverlay, m_Layer[3][2].m_flWeight, FIELD_FLOAT),
|
||||
*/
|
||||
|
||||
END_PREDICTION_DATA()
|
||||
|
||||
C_AnimationLayer* C_BaseAnimatingOverlay::GetAnimOverlay( int i )
|
||||
{
|
||||
Assert( i >= 0 && i < MAX_OVERLAYS );
|
||||
return &m_AnimOverlay[i];
|
||||
}
|
||||
|
||||
|
||||
void C_BaseAnimatingOverlay::SetNumAnimOverlays( int num )
|
||||
{
|
||||
if ( m_AnimOverlay.Count() < num )
|
||||
{
|
||||
m_AnimOverlay.AddMultipleToTail( num - m_AnimOverlay.Count() );
|
||||
}
|
||||
else if ( m_AnimOverlay.Count() > num )
|
||||
{
|
||||
m_AnimOverlay.RemoveMultiple( num, m_AnimOverlay.Count() - num );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int C_BaseAnimatingOverlay::GetNumAnimOverlays() const
|
||||
{
|
||||
return m_AnimOverlay.Count();
|
||||
}
|
||||
|
||||
|
||||
void C_BaseAnimatingOverlay::GetRenderBounds( Vector& theMins, Vector& theMaxs )
|
||||
{
|
||||
BaseClass::GetRenderBounds( theMins, theMaxs );
|
||||
|
||||
if ( !IsRagdoll() )
|
||||
{
|
||||
CStudioHdr *pStudioHdr = GetModelPtr();
|
||||
if ( !pStudioHdr || !pStudioHdr->SequencesAvailable() )
|
||||
return;
|
||||
|
||||
int nSequences = pStudioHdr->GetNumSeq();
|
||||
|
||||
int i;
|
||||
for (i = 0; i < m_AnimOverlay.Count(); i++)
|
||||
{
|
||||
if (m_AnimOverlay[i].m_flWeight > 0.0)
|
||||
{
|
||||
if ( m_AnimOverlay[i].m_nSequence >= nSequences )
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
mstudioseqdesc_t &seqdesc = pStudioHdr->pSeqdesc( m_AnimOverlay[i].m_nSequence );
|
||||
VectorMin( seqdesc.bbmin, theMins, theMins );
|
||||
VectorMax( seqdesc.bbmax, theMaxs, theMaxs );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
void C_BaseAnimatingOverlay::CheckForLayerChanges( CStudioHdr *hdr, float currentTime )
|
||||
{
|
||||
bool bLayersChanged = false;
|
||||
|
||||
// FIXME: damn, there has to be a better way than this.
|
||||
int i;
|
||||
for (i = 0; i < m_iv_AnimOverlay.Count(); i++)
|
||||
{
|
||||
CDisableRangeChecks disableRangeChecks;
|
||||
|
||||
int iHead, iPrev1, iPrev2;
|
||||
m_iv_AnimOverlay[i].GetInterpolationInfo( currentTime, &iHead, &iPrev1, &iPrev2 );
|
||||
|
||||
// fake up previous cycle values.
|
||||
float t0;
|
||||
C_AnimationLayer *pHead = m_iv_AnimOverlay[i].GetHistoryValue( iHead, t0 );
|
||||
// reset previous
|
||||
float t1;
|
||||
C_AnimationLayer *pPrev1 = m_iv_AnimOverlay[i].GetHistoryValue( iPrev1, t1 );
|
||||
// reset previous previous
|
||||
float t2;
|
||||
C_AnimationLayer *pPrev2 = m_iv_AnimOverlay[i].GetHistoryValue( iPrev2, t2 );
|
||||
|
||||
if ( pHead && pPrev1 && pHead->m_nSequence != pPrev1->m_nSequence )
|
||||
{
|
||||
bLayersChanged = true;
|
||||
#if 1 // _DEBUG
|
||||
if (/* Q_stristr( hdr->pszName(), r_sequence_debug.GetString()) != NULL || */ r_sequence_debug.GetInt() == entindex())
|
||||
{
|
||||
DevMsgRT( "(%7.4f : %30s : %5.3f : %4.2f : %1d)\n", t0, hdr->pSeqdesc( pHead->m_nSequence ).pszLabel(), (float)pHead->m_flCycle, (float)pHead->m_flWeight, i );
|
||||
DevMsgRT( "(%7.4f : %30s : %5.3f : %4.2f : %1d)\n", t1, hdr->pSeqdesc( pPrev1->m_nSequence ).pszLabel(), (float)pPrev1->m_flCycle, (float)pPrev1->m_flWeight, i );
|
||||
if (pPrev2)
|
||||
DevMsgRT( "(%7.4f : %30s : %5.3f : %4.2f : %1d)\n", t2, hdr->pSeqdesc( pPrev2->m_nSequence ).pszLabel(), (float)pPrev2->m_flCycle, (float)pPrev2->m_flWeight, i );
|
||||
}
|
||||
#endif
|
||||
|
||||
if (pPrev1)
|
||||
{
|
||||
pPrev1->m_nSequence = pHead->m_nSequence;
|
||||
pPrev1->m_flCycle = pHead->m_flPrevCycle;
|
||||
pPrev1->m_flWeight = pHead->m_flWeight;
|
||||
}
|
||||
|
||||
if (pPrev2)
|
||||
{
|
||||
float num = 0;
|
||||
if ( fabs( t0 - t1 ) > 0.001f )
|
||||
num = (t2 - t1) / (t0 - t1);
|
||||
|
||||
pPrev2->m_nSequence = pHead->m_nSequence;
|
||||
float flTemp;
|
||||
if (IsSequenceLooping( hdr, pHead->m_nSequence ))
|
||||
{
|
||||
flTemp = LoopingLerp( num, (float)pHead->m_flPrevCycle, (float)pHead->m_flCycle );
|
||||
}
|
||||
else
|
||||
{
|
||||
flTemp = Lerp( num, (float)pHead->m_flPrevCycle, (float)pHead->m_flCycle );
|
||||
}
|
||||
pPrev2->m_flCycle = flTemp;
|
||||
pPrev2->m_flWeight = pHead->m_flWeight;
|
||||
}
|
||||
|
||||
/*
|
||||
if (stricmp( r_seq_overlay_debug.GetString(), hdr->name ) == 0)
|
||||
{
|
||||
DevMsgRT( "(%30s %6.2f : %6.2f : %6.2f)\n", hdr->pSeqdesc( pHead->nSequence ).pszLabel(), (float)pPrev2->m_flCycle, (float)pPrev1->m_flCycle, (float)pHead->m_flCycle );
|
||||
}
|
||||
*/
|
||||
|
||||
m_iv_AnimOverlay[i].SetLooping( IsSequenceLooping( hdr, pHead->m_nSequence ) );
|
||||
m_iv_AnimOverlay[i].Interpolate( currentTime );
|
||||
|
||||
// reset event indexes
|
||||
m_flOverlayPrevEventCycle[i] = pHead->m_flPrevCycle - 0.01;
|
||||
}
|
||||
}
|
||||
|
||||
if (bLayersChanged)
|
||||
{
|
||||
// render bounds may have changed
|
||||
UpdateVisibility();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
void C_BaseAnimatingOverlay::AccumulateLayers( IBoneSetup &boneSetup, Vector pos[], Quaternion q[], float currentTime )
|
||||
{
|
||||
BaseClass::AccumulateLayers( boneSetup, pos, q, currentTime );
|
||||
int i;
|
||||
|
||||
// resort the layers
|
||||
int layer[MAX_OVERLAYS];
|
||||
for (i = 0; i < MAX_OVERLAYS; i++)
|
||||
{
|
||||
layer[i] = MAX_OVERLAYS;
|
||||
}
|
||||
for (i = 0; i < m_AnimOverlay.Count(); i++)
|
||||
{
|
||||
if (m_AnimOverlay[i].m_nOrder < MAX_OVERLAYS)
|
||||
{
|
||||
/*
|
||||
Assert( layer[m_AnimOverlay[i].m_nOrder] == MAX_OVERLAYS );
|
||||
layer[m_AnimOverlay[i].m_nOrder] = i;
|
||||
*/
|
||||
// hacky code until initialization of new layers is finished
|
||||
if (layer[m_AnimOverlay[i].m_nOrder] != MAX_OVERLAYS)
|
||||
{
|
||||
m_AnimOverlay[i].m_nOrder = MAX_OVERLAYS;
|
||||
}
|
||||
else
|
||||
{
|
||||
layer[m_AnimOverlay[i].m_nOrder] = i;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
CheckForLayerChanges( boneSetup.GetStudioHdr(), currentTime );
|
||||
|
||||
int nSequences = boneSetup.GetStudioHdr()->GetNumSeq();
|
||||
|
||||
// add in the overlay layers
|
||||
int j;
|
||||
for (j = 0; j < MAX_OVERLAYS; j++)
|
||||
{
|
||||
i = layer[ j ];
|
||||
if (i < m_AnimOverlay.Count())
|
||||
{
|
||||
if ( m_AnimOverlay[i].m_nSequence >= nSequences )
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
/*
|
||||
DevMsgRT( 1 , "%.3f %.3f %.3f\n", currentTime, fWeight, dadt );
|
||||
debugoverlay->AddTextOverlay( GetAbsOrigin() + Vector( 0, 0, 64 ), -j - 1, 0,
|
||||
"%2d(%s) : %6.2f : %6.2f",
|
||||
m_AnimOverlay[i].m_nSequence,
|
||||
hdr->pSeqdesc( m_AnimOverlay[i].m_nSequence )->pszLabel(),
|
||||
m_AnimOverlay[i].m_flCycle,
|
||||
m_AnimOverlay[i].m_flWeight
|
||||
);
|
||||
*/
|
||||
|
||||
m_AnimOverlay[i].BlendWeight();
|
||||
|
||||
float fWeight = m_AnimOverlay[i].m_flWeight;
|
||||
|
||||
if (fWeight > 0)
|
||||
{
|
||||
// check to see if the sequence changed
|
||||
// FIXME: move this to somewhere more reasonable
|
||||
// do a nice spline interpolation of the values
|
||||
// if ( m_AnimOverlay[i].m_nSequence != m_iv_AnimOverlay.GetPrev( i )->nSequence )
|
||||
float fCycle = m_AnimOverlay[ i ].m_flCycle;
|
||||
|
||||
fCycle = ClampCycle( fCycle, IsSequenceLooping( m_AnimOverlay[i].m_nSequence ) );
|
||||
|
||||
if (fWeight > 1)
|
||||
fWeight = 1;
|
||||
|
||||
boneSetup.AccumulatePose( pos, q, m_AnimOverlay[i].m_nSequence, fCycle, fWeight, currentTime, m_pIk );
|
||||
|
||||
#if 1 // _DEBUG
|
||||
if (/* Q_stristr( hdr->pszName(), r_sequence_debug.GetString()) != NULL || */ r_sequence_debug.GetInt() == entindex())
|
||||
{
|
||||
if (1)
|
||||
{
|
||||
DevMsgRT( "%8.4f : %30s : %5.3f : %4.2f : %1d\n", currentTime, boneSetup.GetStudioHdr()->pSeqdesc( m_AnimOverlay[i].m_nSequence ).pszLabel(), fCycle, fWeight, i );
|
||||
}
|
||||
else
|
||||
{
|
||||
int iHead, iPrev1, iPrev2;
|
||||
m_iv_AnimOverlay[i].GetInterpolationInfo( currentTime, &iHead, &iPrev1, &iPrev2 );
|
||||
|
||||
// fake up previous cycle values.
|
||||
float t0;
|
||||
C_AnimationLayer *pHead = m_iv_AnimOverlay[i].GetHistoryValue( iHead, t0 );
|
||||
// reset previous
|
||||
float t1;
|
||||
C_AnimationLayer *pPrev1 = m_iv_AnimOverlay[i].GetHistoryValue( iPrev1, t1 );
|
||||
// reset previous previous
|
||||
float t2;
|
||||
C_AnimationLayer *pPrev2 = m_iv_AnimOverlay[i].GetHistoryValue( iPrev2, t2 );
|
||||
|
||||
if ( pHead && pPrev1 && pPrev2 )
|
||||
{
|
||||
DevMsgRT( "%6.2f : %30s %6.2f (%6.2f:%6.2f:%6.2f) : %6.2f (%6.2f:%6.2f:%6.2f) : %1d\n", currentTime, boneSetup.GetStudioHdr()->pSeqdesc( m_AnimOverlay[i].m_nSequence ).pszLabel(),
|
||||
fCycle, (float)pPrev2->m_flCycle, (float)pPrev1->m_flCycle, (float)pHead->m_flCycle,
|
||||
fWeight, (float)pPrev2->m_flWeight, (float)pPrev1->m_flWeight, (float)pHead->m_flWeight,
|
||||
i );
|
||||
}
|
||||
else
|
||||
{
|
||||
DevMsgRT( "%6.2f : %30s %6.2f : %6.2f : %1d\n", currentTime, boneSetup.GetStudioHdr()->pSeqdesc( m_AnimOverlay[i].m_nSequence ).pszLabel(), fCycle, fWeight, i );
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
//#define DEBUG_TF2_OVERLAYS
|
||||
#if defined( DEBUG_TF2_OVERLAYS )
|
||||
engine->Con_NPrintf( 10 + j, "%30s %6.2f : %6.2f : %1d", boneSetup.GetStudioHdr()->pSeqdesc( m_AnimOverlay[i].m_nSequence ).pszLabel(), fCycle, fWeight, i );
|
||||
}
|
||||
else
|
||||
{
|
||||
engine->Con_NPrintf( 10 + j, "%30s %6.2f : %6.2f : %1d", " ", 0.f, 0.f, i );
|
||||
#endif
|
||||
}
|
||||
}
|
||||
#if defined( DEBUG_TF2_OVERLAYS )
|
||||
else
|
||||
{
|
||||
engine->Con_NPrintf( 10 + j, "%30s %6.2f : %6.2f : %1d", " ", 0.f, 0.f, i );
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
void C_BaseAnimatingOverlay::DoAnimationEvents( CStudioHdr *pStudioHdr )
|
||||
{
|
||||
if ( !pStudioHdr || !pStudioHdr->SequencesAvailable() )
|
||||
return;
|
||||
|
||||
MDLCACHE_CRITICAL_SECTION();
|
||||
|
||||
int nSequences = pStudioHdr->GetNumSeq();
|
||||
|
||||
BaseClass::DoAnimationEvents( pStudioHdr );
|
||||
|
||||
bool watch = false; // Q_strstr( hdr->name, "rifle" ) ? true : false;
|
||||
|
||||
CheckForLayerChanges( pStudioHdr, gpGlobals->curtime ); // !!!
|
||||
|
||||
int j;
|
||||
for (j = 0; j < m_AnimOverlay.Count(); j++)
|
||||
{
|
||||
if ( m_AnimOverlay[j].m_nSequence >= nSequences )
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
mstudioseqdesc_t &seqdesc = pStudioHdr->pSeqdesc( m_AnimOverlay[j].m_nSequence );
|
||||
if ( seqdesc.numevents == 0 )
|
||||
continue;
|
||||
|
||||
// stalled?
|
||||
if (m_AnimOverlay[j].m_flCycle == m_flOverlayPrevEventCycle[j])
|
||||
continue;
|
||||
|
||||
bool bLoopingSequence = IsSequenceLooping( m_AnimOverlay[j].m_nSequence );
|
||||
|
||||
bool bLooped = false;
|
||||
|
||||
//in client code, m_flOverlayPrevEventCycle is set to -1 when we first start an overlay, looping or not
|
||||
if ( bLoopingSequence &&
|
||||
m_flOverlayPrevEventCycle[j] > 0.0f &&
|
||||
m_AnimOverlay[j].m_flCycle <= m_flOverlayPrevEventCycle[j] )
|
||||
{
|
||||
if (m_flOverlayPrevEventCycle[j] - m_AnimOverlay[j].m_flCycle > 0.5)
|
||||
{
|
||||
bLooped = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
// things have backed up, which is bad since it'll probably result in a hitch in the animation playback
|
||||
// but, don't play events again for the same time slice
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
mstudioevent_t *pevent = seqdesc.pEvent( 0 );
|
||||
|
||||
// This makes sure events that occur at the end of a sequence occur are
|
||||
// sent before events that occur at the beginning of a sequence.
|
||||
if (bLooped)
|
||||
{
|
||||
for (int i = 0; i < (int)seqdesc.numevents; i++)
|
||||
{
|
||||
// ignore all non-client-side events
|
||||
if ( pevent[i].type & AE_TYPE_NEWEVENTSYSTEM )
|
||||
{
|
||||
if ( !( pevent[i].type & AE_TYPE_CLIENT ) )
|
||||
continue;
|
||||
}
|
||||
else if ( pevent[i].event < 5000 ) //Adrian - Support the old event system
|
||||
continue;
|
||||
|
||||
if ( pevent[i].cycle <= m_flOverlayPrevEventCycle[j] )
|
||||
continue;
|
||||
|
||||
if ( watch )
|
||||
{
|
||||
Msg( "%i FE %i Looped cycle %f, prev %f ev %f (time %.3f)\n",
|
||||
gpGlobals->tickcount,
|
||||
pevent[i].event,
|
||||
pevent[i].cycle,
|
||||
m_flOverlayPrevEventCycle[j],
|
||||
(float)m_AnimOverlay[j].m_flCycle,
|
||||
gpGlobals->curtime );
|
||||
}
|
||||
|
||||
|
||||
FireEvent( GetAbsOrigin(), GetAbsAngles(), pevent[ i ].event, pevent[ i ].pszOptions() );
|
||||
}
|
||||
|
||||
// Necessary to get the next loop working
|
||||
m_flOverlayPrevEventCycle[j] = -0.01;
|
||||
}
|
||||
|
||||
for (int i = 0; i < (int)seqdesc.numevents; i++)
|
||||
{
|
||||
if ( pevent[i].type & AE_TYPE_NEWEVENTSYSTEM )
|
||||
{
|
||||
if ( !( pevent[i].type & AE_TYPE_CLIENT ) )
|
||||
continue;
|
||||
}
|
||||
else if ( pevent[i].event < 5000 ) //Adrian - Support the old event system
|
||||
continue;
|
||||
|
||||
if ( (pevent[i].cycle > m_flOverlayPrevEventCycle[j] && pevent[i].cycle <= m_AnimOverlay[j].m_flCycle) )
|
||||
{
|
||||
if ( watch )
|
||||
{
|
||||
Msg( "%i (seq: %d) FE %i Normal cycle %f, prev %f ev %f (time %.3f)\n",
|
||||
gpGlobals->tickcount,
|
||||
m_AnimOverlay[j].m_nSequence.GetRaw(),
|
||||
pevent[i].event,
|
||||
pevent[i].cycle,
|
||||
m_flOverlayPrevEventCycle[j],
|
||||
(float)m_AnimOverlay[j].m_flCycle,
|
||||
gpGlobals->curtime );
|
||||
}
|
||||
|
||||
FireEvent( GetAbsOrigin(), GetAbsAngles(), pevent[ i ].event, pevent[ i ].pszOptions() );
|
||||
}
|
||||
}
|
||||
|
||||
m_flOverlayPrevEventCycle[j] = m_AnimOverlay[j].m_flCycle;
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
CStudioHdr *C_BaseAnimatingOverlay::OnNewModel()
|
||||
{
|
||||
CStudioHdr *hdr = BaseClass::OnNewModel();
|
||||
|
||||
// Clear out animation layers
|
||||
for ( int i=0; i < m_AnimOverlay.Count(); i++ )
|
||||
{
|
||||
m_AnimOverlay[i].Reset();
|
||||
m_AnimOverlay[i].m_nOrder = MAX_OVERLAYS;
|
||||
}
|
||||
|
||||
return hdr;
|
||||
}
|
||||
@@ -0,0 +1,67 @@
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
// $NoKeywords: $
|
||||
//
|
||||
//=============================================================================//
|
||||
|
||||
#ifndef C_BASEANIMATINGOVERLAY_H
|
||||
#define C_BASEANIMATINGOVERLAY_H
|
||||
#pragma once
|
||||
|
||||
#include "c_baseanimating.h"
|
||||
|
||||
// For shared code.
|
||||
#define CBaseAnimatingOverlay C_BaseAnimatingOverlay
|
||||
|
||||
|
||||
class C_BaseAnimatingOverlay : public C_BaseAnimating
|
||||
{
|
||||
public:
|
||||
DECLARE_CLASS( C_BaseAnimatingOverlay, C_BaseAnimating );
|
||||
DECLARE_CLIENTCLASS();
|
||||
DECLARE_PREDICTABLE();
|
||||
DECLARE_INTERPOLATION();
|
||||
|
||||
|
||||
C_BaseAnimatingOverlay();
|
||||
|
||||
virtual CStudioHdr *OnNewModel();
|
||||
|
||||
C_AnimationLayer* GetAnimOverlay( int i );
|
||||
void SetNumAnimOverlays( int num ); // This makes sure there is space for this # of layers.
|
||||
int GetNumAnimOverlays() const;
|
||||
|
||||
virtual void GetRenderBounds( Vector& theMins, Vector& theMaxs );
|
||||
|
||||
void CheckForLayerChanges( CStudioHdr *hdr, float currentTime );
|
||||
|
||||
// model specific
|
||||
virtual void AccumulateLayers( IBoneSetup &boneSetup, Vector pos[], Quaternion q[], float currentTime );
|
||||
virtual void DoAnimationEvents( CStudioHdr *pStudioHdr );
|
||||
|
||||
enum
|
||||
{
|
||||
MAX_OVERLAYS = 15,
|
||||
};
|
||||
|
||||
CUtlVector < C_AnimationLayer > m_AnimOverlay;
|
||||
|
||||
CUtlVector < CInterpolatedVar< C_AnimationLayer > > m_iv_AnimOverlay;
|
||||
|
||||
float m_flOverlayPrevEventCycle[ MAX_OVERLAYS ];
|
||||
|
||||
private:
|
||||
C_BaseAnimatingOverlay( const C_BaseAnimatingOverlay & ); // not defined, not accessible
|
||||
};
|
||||
|
||||
|
||||
EXTERN_RECV_TABLE(DT_BaseAnimatingOverlay);
|
||||
|
||||
|
||||
#endif // C_BASEANIMATINGOVERLAY_H
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,197 @@
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose: Client's C_BaseCombatCharacter entity
|
||||
//
|
||||
// $Workfile: $
|
||||
// $Date: $
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
// $Log: $
|
||||
//
|
||||
// $NoKeywords: $
|
||||
//=============================================================================//
|
||||
#include "cbase.h"
|
||||
#include "c_basecombatcharacter.h"
|
||||
|
||||
// memdbgon must be the last include file in a .cpp file!!!
|
||||
#include "tier0/memdbgon.h"
|
||||
|
||||
#if defined( CBaseCombatCharacter )
|
||||
#undef CBaseCombatCharacter
|
||||
#endif
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
C_BaseCombatCharacter::C_BaseCombatCharacter()
|
||||
{
|
||||
for ( int i=0; i < m_iAmmo.Count(); i++ )
|
||||
{
|
||||
m_iAmmo.Set( i, 0 );
|
||||
}
|
||||
|
||||
#ifdef GLOWS_ENABLE
|
||||
m_pGlowEffect = NULL;
|
||||
m_bGlowEnabled = false;
|
||||
m_bOldGlowEnabled = false;
|
||||
m_bClientSideGlowEnabled = false;
|
||||
#endif // GLOWS_ENABLE
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
C_BaseCombatCharacter::~C_BaseCombatCharacter()
|
||||
{
|
||||
#ifdef GLOWS_ENABLE
|
||||
DestroyGlowEffect();
|
||||
#endif // GLOWS_ENABLE
|
||||
}
|
||||
|
||||
/*
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Returns the amount of ammunition of the specified type the character's carrying
|
||||
//-----------------------------------------------------------------------------
|
||||
int C_BaseCombatCharacter::GetAmmoCount( char *szName ) const
|
||||
{
|
||||
return GetAmmoCount( g_pGameRules->GetAmmoDef()->Index(szName) );
|
||||
}
|
||||
*/
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
void C_BaseCombatCharacter::OnPreDataChanged( DataUpdateType_t updateType )
|
||||
{
|
||||
BaseClass::OnPreDataChanged( updateType );
|
||||
|
||||
#ifdef GLOWS_ENABLE
|
||||
m_bOldGlowEnabled = m_bGlowEnabled;
|
||||
#endif // GLOWS_ENABLE
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
void C_BaseCombatCharacter::OnDataChanged( DataUpdateType_t updateType )
|
||||
{
|
||||
BaseClass::OnDataChanged( updateType );
|
||||
|
||||
#ifdef GLOWS_ENABLE
|
||||
if ( m_bOldGlowEnabled != m_bGlowEnabled )
|
||||
{
|
||||
UpdateGlowEffect();
|
||||
}
|
||||
#endif // GLOWS_ENABLE
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Overload our muzzle flash and send it to any actively held weapon
|
||||
//-----------------------------------------------------------------------------
|
||||
void C_BaseCombatCharacter::DoMuzzleFlash()
|
||||
{
|
||||
// Our weapon takes our muzzle flash command
|
||||
C_BaseCombatWeapon *pWeapon = GetActiveWeapon();
|
||||
if ( pWeapon )
|
||||
{
|
||||
pWeapon->DoMuzzleFlash();
|
||||
//NOTENOTE: We do not chain to the base here
|
||||
}
|
||||
else
|
||||
{
|
||||
BaseClass::DoMuzzleFlash();
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef GLOWS_ENABLE
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
void C_BaseCombatCharacter::GetGlowEffectColor( float *r, float *g, float *b )
|
||||
{
|
||||
*r = 0.76f;
|
||||
*g = 0.76f;
|
||||
*b = 0.76f;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
/*
|
||||
void C_BaseCombatCharacter::EnableGlowEffect( float r, float g, float b )
|
||||
{
|
||||
// destroy the existing effect
|
||||
if ( m_pGlowEffect )
|
||||
{
|
||||
DestroyGlowEffect();
|
||||
}
|
||||
|
||||
m_pGlowEffect = new CGlowObject( this, Vector( r, g, b ), 1.0, true );
|
||||
}
|
||||
*/
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
void C_BaseCombatCharacter::UpdateGlowEffect( void )
|
||||
{
|
||||
// destroy the existing effect
|
||||
if ( m_pGlowEffect )
|
||||
{
|
||||
DestroyGlowEffect();
|
||||
}
|
||||
|
||||
// create a new effect
|
||||
if ( m_bGlowEnabled || m_bClientSideGlowEnabled )
|
||||
{
|
||||
float r, g, b;
|
||||
GetGlowEffectColor( &r, &g, &b );
|
||||
|
||||
m_pGlowEffect = new CGlowObject( this, Vector( r, g, b ), 1.0, true );
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
void C_BaseCombatCharacter::DestroyGlowEffect( void )
|
||||
{
|
||||
if ( m_pGlowEffect )
|
||||
{
|
||||
delete m_pGlowEffect;
|
||||
m_pGlowEffect = NULL;
|
||||
}
|
||||
}
|
||||
#endif // GLOWS_ENABLE
|
||||
|
||||
IMPLEMENT_CLIENTCLASS(C_BaseCombatCharacter, DT_BaseCombatCharacter, CBaseCombatCharacter);
|
||||
|
||||
// Only send active weapon index to local player
|
||||
BEGIN_RECV_TABLE_NOBASE( C_BaseCombatCharacter, DT_BCCLocalPlayerExclusive )
|
||||
RecvPropTime( RECVINFO( m_flNextAttack ) ),
|
||||
END_RECV_TABLE();
|
||||
|
||||
|
||||
BEGIN_RECV_TABLE(C_BaseCombatCharacter, DT_BaseCombatCharacter)
|
||||
RecvPropDataTable( "bcc_localdata", 0, 0, &REFERENCE_RECV_TABLE(DT_BCCLocalPlayerExclusive) ),
|
||||
RecvPropEHandle( RECVINFO( m_hActiveWeapon ) ),
|
||||
RecvPropArray3( RECVINFO_ARRAY(m_hMyWeapons), RecvPropEHandle( RECVINFO( m_hMyWeapons[0] ) ) ),
|
||||
#ifdef GLOWS_ENABLE
|
||||
RecvPropBool( RECVINFO( m_bGlowEnabled ) ),
|
||||
#endif // GLOWS_ENABLE
|
||||
|
||||
#ifdef INVASION_CLIENT_DLL
|
||||
RecvPropInt( RECVINFO( m_iPowerups ) ),
|
||||
#endif
|
||||
|
||||
END_RECV_TABLE()
|
||||
|
||||
|
||||
BEGIN_PREDICTION_DATA( C_BaseCombatCharacter )
|
||||
|
||||
DEFINE_PRED_ARRAY( m_iAmmo, FIELD_INTEGER, MAX_AMMO_TYPES, FTYPEDESC_INSENDTABLE ),
|
||||
DEFINE_PRED_FIELD( m_flNextAttack, FIELD_FLOAT, FTYPEDESC_INSENDTABLE ),
|
||||
DEFINE_PRED_FIELD( m_hActiveWeapon, FIELD_EHANDLE, FTYPEDESC_INSENDTABLE ),
|
||||
DEFINE_PRED_ARRAY( m_hMyWeapons, FIELD_EHANDLE, MAX_WEAPONS, FTYPEDESC_INSENDTABLE ),
|
||||
|
||||
END_PREDICTION_DATA()
|
||||
@@ -0,0 +1,199 @@
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose: Defines the client-side representation of CBaseCombatCharacter.
|
||||
//
|
||||
// $NoKeywords: $
|
||||
//=============================================================================//
|
||||
|
||||
#ifndef C_BASECOMBATCHARACTER_H
|
||||
#define C_BASECOMBATCHARACTER_H
|
||||
|
||||
#ifdef _WIN32
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
#include "shareddefs.h"
|
||||
#include "c_baseflex.h"
|
||||
#ifdef GLOWS_ENABLE
|
||||
#include "glow_outline_effect.h"
|
||||
#endif // GLOWS_ENABLE
|
||||
|
||||
class C_BaseCombatWeapon;
|
||||
class C_WeaponCombatShield;
|
||||
|
||||
#define BCC_DEFAULT_LOOK_TOWARDS_TOLERANCE 0.9f
|
||||
|
||||
class C_BaseCombatCharacter : public C_BaseFlex
|
||||
{
|
||||
DECLARE_CLASS( C_BaseCombatCharacter, C_BaseFlex );
|
||||
public:
|
||||
DECLARE_CLIENTCLASS();
|
||||
DECLARE_PREDICTABLE();
|
||||
|
||||
C_BaseCombatCharacter( void );
|
||||
virtual ~C_BaseCombatCharacter( void );
|
||||
|
||||
virtual void OnPreDataChanged( DataUpdateType_t updateType );
|
||||
virtual void OnDataChanged( DataUpdateType_t updateType );
|
||||
|
||||
virtual bool IsBaseCombatCharacter( void ) { return true; };
|
||||
virtual C_BaseCombatCharacter *MyCombatCharacterPointer( void ) { return this; }
|
||||
|
||||
// -----------------------
|
||||
// Vision
|
||||
// -----------------------
|
||||
enum FieldOfViewCheckType { USE_FOV, DISREGARD_FOV };
|
||||
bool IsAbleToSee( const CBaseEntity *entity, FieldOfViewCheckType checkFOV ); // Visible starts with line of sight, and adds all the extra game checks like fog, smoke, camo...
|
||||
bool IsAbleToSee( C_BaseCombatCharacter *pBCC, FieldOfViewCheckType checkFOV ); // Visible starts with line of sight, and adds all the extra game checks like fog, smoke, camo...
|
||||
|
||||
virtual bool IsLookingTowards( const CBaseEntity *target, float cosTolerance = BCC_DEFAULT_LOOK_TOWARDS_TOLERANCE ) const; // return true if our view direction is pointing at the given target, within the cosine of the angular tolerance. LINE OF SIGHT IS NOT CHECKED.
|
||||
virtual bool IsLookingTowards( const Vector &target, float cosTolerance = BCC_DEFAULT_LOOK_TOWARDS_TOLERANCE ) const; // return true if our view direction is pointing at the given target, within the cosine of the angular tolerance. LINE OF SIGHT IS NOT CHECKED.
|
||||
|
||||
virtual bool IsInFieldOfView( CBaseEntity *entity ) const; // Calls IsLookingAt with the current field of view.
|
||||
virtual bool IsInFieldOfView( const Vector &pos ) const;
|
||||
|
||||
enum LineOfSightCheckType
|
||||
{
|
||||
IGNORE_NOTHING,
|
||||
IGNORE_ACTORS
|
||||
};
|
||||
virtual bool IsLineOfSightClear( CBaseEntity *entity, LineOfSightCheckType checkType = IGNORE_NOTHING ) const;// strictly LOS check with no other considerations
|
||||
virtual bool IsLineOfSightClear( const Vector &pos, LineOfSightCheckType checkType = IGNORE_NOTHING, CBaseEntity *entityToIgnore = NULL ) const;
|
||||
|
||||
|
||||
// -----------------------
|
||||
// Ammo
|
||||
// -----------------------
|
||||
void RemoveAmmo( int iCount, int iAmmoIndex );
|
||||
void RemoveAmmo( int iCount, const char *szName );
|
||||
void RemoveAllAmmo( );
|
||||
int GetAmmoCount( int iAmmoIndex ) const;
|
||||
int GetAmmoCount( char *szName ) const;
|
||||
|
||||
C_BaseCombatWeapon* Weapon_OwnsThisType( const char *pszWeapon, int iSubType = 0 ) const; // True if already owns a weapon of this class
|
||||
virtual bool Weapon_Switch( C_BaseCombatWeapon *pWeapon, int viewmodelindex = 0 );
|
||||
virtual bool Weapon_CanSwitchTo(C_BaseCombatWeapon *pWeapon);
|
||||
|
||||
// I can't use my current weapon anymore. Switch me to the next best weapon.
|
||||
bool SwitchToNextBestWeapon(C_BaseCombatWeapon *pCurrent);
|
||||
|
||||
virtual C_BaseCombatWeapon *GetActiveWeapon( void ) const;
|
||||
int WeaponCount() const;
|
||||
C_BaseCombatWeapon *GetWeapon( int i ) const;
|
||||
|
||||
// This is a sort of hack back-door only used by physgun!
|
||||
void SetAmmoCount( int iCount, int iAmmoIndex );
|
||||
|
||||
float GetNextAttack() const { return m_flNextAttack; }
|
||||
void SetNextAttack( float flWait ) { m_flNextAttack = flWait; }
|
||||
|
||||
virtual int BloodColor();
|
||||
|
||||
// Blood color (see BLOOD_COLOR_* macros in baseentity.h)
|
||||
void SetBloodColor( int nBloodColor );
|
||||
|
||||
virtual void DoMuzzleFlash();
|
||||
|
||||
#ifdef GLOWS_ENABLE
|
||||
CGlowObject *GetGlowObject( void ){ return m_pGlowEffect; }
|
||||
virtual void GetGlowEffectColor( float *r, float *g, float *b );
|
||||
// void EnableGlowEffect( float r, float g, float b );
|
||||
|
||||
void SetClientSideGlowEnabled( bool bEnabled ){ m_bClientSideGlowEnabled = bEnabled; UpdateGlowEffect(); }
|
||||
bool IsClientSideGlowEnabled( void ){ return m_bClientSideGlowEnabled; }
|
||||
#endif // GLOWS_ENABLE
|
||||
|
||||
public:
|
||||
|
||||
float m_flNextAttack;
|
||||
|
||||
protected:
|
||||
|
||||
#ifdef GLOWS_ENABLE
|
||||
virtual void UpdateGlowEffect( void );
|
||||
virtual void DestroyGlowEffect( void );
|
||||
#endif // GLOWS_ENABLE
|
||||
|
||||
int m_bloodColor; // color of blood particless
|
||||
|
||||
private:
|
||||
bool ComputeLOS( const Vector &vecEyePosition, const Vector &vecTarget ) const;
|
||||
|
||||
CNetworkArray( int, m_iAmmo, MAX_AMMO_TYPES );
|
||||
|
||||
CHandle<C_BaseCombatWeapon> m_hMyWeapons[MAX_WEAPONS];
|
||||
CHandle< C_BaseCombatWeapon > m_hActiveWeapon;
|
||||
|
||||
#ifdef GLOWS_ENABLE
|
||||
bool m_bClientSideGlowEnabled; // client-side only value used for spectator
|
||||
bool m_bGlowEnabled; // networked value
|
||||
bool m_bOldGlowEnabled;
|
||||
CGlowObject *m_pGlowEffect;
|
||||
#endif // GLOWS_ENABLE
|
||||
|
||||
private:
|
||||
C_BaseCombatCharacter( const C_BaseCombatCharacter & ); // not defined, not accessible
|
||||
|
||||
|
||||
//-----------------------
|
||||
#ifdef INVASION_CLIENT_DLL
|
||||
public:
|
||||
virtual void Release( void );
|
||||
virtual void SetDormant( bool bDormant );
|
||||
virtual void OnPreDataChanged( DataUpdateType_t updateType );
|
||||
virtual void OnDataChanged( DataUpdateType_t updateType );
|
||||
virtual void ClientThink( void );
|
||||
|
||||
// TF2 Powerups
|
||||
virtual bool CanBePoweredUp( void ) { return true; }
|
||||
bool HasPowerup( int iPowerup ) { return ( m_iPowerups & (1 << iPowerup) ) != 0; };
|
||||
virtual void PowerupStart( int iPowerup, bool bInitial );
|
||||
virtual void PowerupEnd( int iPowerup );
|
||||
void RemoveAllPowerups( void );
|
||||
|
||||
// Powerup effects
|
||||
void AddEMPEffect( float flSize );
|
||||
void AddBuffEffect( float flSize );
|
||||
|
||||
C_WeaponCombatShield *GetShield( void );
|
||||
|
||||
public:
|
||||
int m_iPowerups;
|
||||
int m_iPrevPowerups;
|
||||
#endif
|
||||
|
||||
};
|
||||
|
||||
inline C_BaseCombatCharacter *ToBaseCombatCharacter( C_BaseEntity *pEntity )
|
||||
{
|
||||
if ( !pEntity || !pEntity->IsBaseCombatCharacter() )
|
||||
return NULL;
|
||||
|
||||
#if _DEBUG
|
||||
return dynamic_cast<C_BaseCombatCharacter *>( pEntity );
|
||||
#else
|
||||
return static_cast<C_BaseCombatCharacter *>( pEntity );
|
||||
#endif
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
inline int C_BaseCombatCharacter::WeaponCount() const
|
||||
{
|
||||
return MAX_WEAPONS;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
// Input : i -
|
||||
//-----------------------------------------------------------------------------
|
||||
inline C_BaseCombatWeapon *C_BaseCombatCharacter::GetWeapon( int i ) const
|
||||
{
|
||||
Assert( (i >= 0) && (i < MAX_WEAPONS) );
|
||||
return m_hMyWeapons[i].Get();
|
||||
}
|
||||
|
||||
EXTERN_RECV_TABLE(DT_BaseCombatCharacter);
|
||||
|
||||
#endif // C_BASECOMBATCHARACTER_H
|
||||
@@ -0,0 +1,557 @@
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose: Client side implementation of CBaseCombatWeapon.
|
||||
//
|
||||
// $NoKeywords: $
|
||||
//=============================================================================//
|
||||
#include "cbase.h"
|
||||
#include "history_resource.h"
|
||||
#include "iclientmode.h"
|
||||
#include "iinput.h"
|
||||
#include "weapon_selection.h"
|
||||
#include "hud_crosshair.h"
|
||||
#include "engine/ivmodelinfo.h"
|
||||
#include "tier0/vprof.h"
|
||||
#include "hltvcamera.h"
|
||||
#include "tier1/KeyValues.h"
|
||||
#include "toolframework/itoolframework.h"
|
||||
#include "toolframework_client.h"
|
||||
|
||||
// memdbgon must be the last include file in a .cpp file!!!
|
||||
#include "tier0/memdbgon.h"
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Gets the local client's active weapon, if any.
|
||||
//-----------------------------------------------------------------------------
|
||||
C_BaseCombatWeapon *GetActiveWeapon( void )
|
||||
{
|
||||
C_BasePlayer *player = C_BasePlayer::GetLocalPlayer();
|
||||
|
||||
if ( !player )
|
||||
return NULL;
|
||||
|
||||
return player->GetActiveWeapon();
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
void C_BaseCombatWeapon::SetDormant( bool bDormant )
|
||||
{
|
||||
// If I'm going from active to dormant and I'm carried by another player, holster me.
|
||||
if ( !IsDormant() && bDormant && GetOwner() && !IsCarriedByLocalPlayer() )
|
||||
{
|
||||
Holster( NULL );
|
||||
}
|
||||
|
||||
BaseClass::SetDormant( bDormant );
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
void C_BaseCombatWeapon::NotifyShouldTransmit( ShouldTransmitState_t state )
|
||||
{
|
||||
BaseClass::NotifyShouldTransmit(state);
|
||||
|
||||
if (state == SHOULDTRANSMIT_END)
|
||||
{
|
||||
if (m_iState == WEAPON_IS_ACTIVE)
|
||||
{
|
||||
m_iState = WEAPON_IS_CARRIED_BY_PLAYER;
|
||||
}
|
||||
}
|
||||
else if( state == SHOULDTRANSMIT_START )
|
||||
{
|
||||
if( m_iState == WEAPON_IS_CARRIED_BY_PLAYER )
|
||||
{
|
||||
if( GetOwner() && GetOwner()->GetActiveWeapon() == this )
|
||||
{
|
||||
// Restore the Activeness of the weapon if we client-twiddled it off in the first case above.
|
||||
m_iState = WEAPON_IS_ACTIVE;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: To wrap PORTAL mod specific functionality into one place
|
||||
//-----------------------------------------------------------------------------
|
||||
static inline bool ShouldDrawLocalPlayerViewModel( void )
|
||||
{
|
||||
#if defined( PORTAL )
|
||||
return false;
|
||||
#else
|
||||
return !C_BasePlayer::ShouldDrawLocalPlayer();
|
||||
#endif
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
void C_BaseCombatWeapon::OnRestore()
|
||||
{
|
||||
BaseClass::OnRestore();
|
||||
|
||||
// if the player is holding this weapon,
|
||||
// mark it as just restored so it won't show as a new pickup
|
||||
if (GetOwner() == C_BasePlayer::GetLocalPlayer())
|
||||
{
|
||||
m_bJustRestored = true;
|
||||
}
|
||||
}
|
||||
|
||||
int C_BaseCombatWeapon::GetWorldModelIndex( void )
|
||||
{
|
||||
if ( GameRules() )
|
||||
{
|
||||
const char *pBaseName = modelinfo->GetModelName( modelinfo->GetModel( m_iWorldModelIndex ) );
|
||||
const char *pTranslatedName = GameRules()->TranslateEffectForVisionFilter( "weapons", pBaseName );
|
||||
|
||||
if ( pTranslatedName != pBaseName )
|
||||
{
|
||||
return modelinfo->GetModelIndex( pTranslatedName );
|
||||
}
|
||||
}
|
||||
|
||||
return m_iWorldModelIndex;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
// Input : bnewentity -
|
||||
//-----------------------------------------------------------------------------
|
||||
void C_BaseCombatWeapon::OnDataChanged( DataUpdateType_t updateType )
|
||||
{
|
||||
BaseClass::OnDataChanged(updateType);
|
||||
|
||||
CHandle< C_BaseCombatWeapon > handle = this;
|
||||
|
||||
// If it's being carried by the *local* player, on the first update,
|
||||
// find the registered weapon for this ID
|
||||
|
||||
C_BasePlayer *pPlayer = C_BasePlayer::GetLocalPlayer();
|
||||
C_BaseCombatCharacter *pOwner = GetOwner();
|
||||
|
||||
// check if weapon is carried by local player
|
||||
bool bIsLocalPlayer = pPlayer && pPlayer == pOwner;
|
||||
if ( bIsLocalPlayer && ShouldDrawLocalPlayerViewModel() ) // TODO: figure out the purpose of the ShouldDrawLocalPlayer() test.
|
||||
{
|
||||
// If I was just picked up, or created & immediately carried, add myself to this client's list of weapons
|
||||
if ( (m_iState != WEAPON_NOT_CARRIED ) && (m_iOldState == WEAPON_NOT_CARRIED) )
|
||||
{
|
||||
// Tell the HUD this weapon's been picked up
|
||||
if ( ShouldDrawPickup() )
|
||||
{
|
||||
CBaseHudWeaponSelection *pHudSelection = GetHudWeaponSelection();
|
||||
if ( pHudSelection )
|
||||
{
|
||||
pHudSelection->OnWeaponPickup( this );
|
||||
}
|
||||
|
||||
pPlayer->EmitSound( "Player.PickupWeapon" );
|
||||
}
|
||||
}
|
||||
}
|
||||
else // weapon carried by other player or not at all
|
||||
{
|
||||
int overrideModelIndex = CalcOverrideModelIndex();
|
||||
if( overrideModelIndex != -1 && overrideModelIndex != GetModelIndex() )
|
||||
{
|
||||
SetModelIndex( overrideModelIndex );
|
||||
}
|
||||
}
|
||||
|
||||
if ( updateType == DATA_UPDATE_CREATED )
|
||||
{
|
||||
UpdateVisibility();
|
||||
}
|
||||
|
||||
m_iOldState = m_iState;
|
||||
|
||||
m_bJustRestored = false;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Is anyone carrying it?
|
||||
//-----------------------------------------------------------------------------
|
||||
bool C_BaseCombatWeapon::IsBeingCarried() const
|
||||
{
|
||||
return ( m_hOwner.Get() != NULL );
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Is the carrier alive?
|
||||
//-----------------------------------------------------------------------------
|
||||
bool C_BaseCombatWeapon::IsCarrierAlive() const
|
||||
{
|
||||
if ( !m_hOwner.Get() )
|
||||
return false;
|
||||
|
||||
return m_hOwner.Get()->GetHealth() > 0;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Should this object cast shadows?
|
||||
//-----------------------------------------------------------------------------
|
||||
ShadowType_t C_BaseCombatWeapon::ShadowCastType()
|
||||
{
|
||||
if ( IsEffectActive( /*EF_NODRAW |*/ EF_NOSHADOW ) )
|
||||
return SHADOWS_NONE;
|
||||
|
||||
if (!IsBeingCarried())
|
||||
return SHADOWS_RENDER_TO_TEXTURE;
|
||||
|
||||
if (IsCarriedByLocalPlayer() && !C_BasePlayer::ShouldDrawLocalPlayer())
|
||||
return SHADOWS_NONE;
|
||||
|
||||
return SHADOWS_RENDER_TO_TEXTURE;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: This weapon is the active weapon, and it should now draw anything
|
||||
// it wants to. This gets called every frame.
|
||||
//-----------------------------------------------------------------------------
|
||||
void C_BaseCombatWeapon::Redraw()
|
||||
{
|
||||
if ( g_pClientMode->ShouldDrawCrosshair() )
|
||||
{
|
||||
DrawCrosshair();
|
||||
}
|
||||
|
||||
// ammo drawing has been moved into hud_ammo.cpp
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Draw the weapon's crosshair
|
||||
//-----------------------------------------------------------------------------
|
||||
void C_BaseCombatWeapon::DrawCrosshair()
|
||||
{
|
||||
C_BasePlayer *player = C_BasePlayer::GetLocalPlayer();
|
||||
if ( !player )
|
||||
return;
|
||||
|
||||
Color clr = gHUD.m_clrNormal;
|
||||
/*
|
||||
|
||||
// TEST: if the thing under your crosshair is on a different team, light the crosshair with a different color.
|
||||
Vector vShootPos, vShootAngles;
|
||||
GetShootPosition( vShootPos, vShootAngles );
|
||||
|
||||
Vector vForward;
|
||||
AngleVectors( vShootAngles, &vForward );
|
||||
|
||||
|
||||
// Change the color depending on if we're looking at a friend or an enemy.
|
||||
CPartitionFilterListMask filter( PARTITION_ALL_CLIENT_EDICTS );
|
||||
trace_t tr;
|
||||
traceline->TraceLine( vShootPos, vShootPos + vForward * 10000, COLLISION_GROUP_NONE, MASK_SHOT, &tr, true, ~0, &filter );
|
||||
|
||||
if ( tr.index != 0 && tr.index != INVALID_CLIENTENTITY_HANDLE )
|
||||
{
|
||||
C_BaseEntity *pEnt = ClientEntityList().GetBaseEntityFromHandle( tr.index );
|
||||
if ( pEnt )
|
||||
{
|
||||
if ( pEnt->GetTeamNumber() != player->GetTeamNumber() )
|
||||
{
|
||||
g = b = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
CHudCrosshair *pCrosshair = GET_HUDELEMENT( CHudCrosshair );
|
||||
if ( !pCrosshair )
|
||||
return;
|
||||
|
||||
// Find out if this weapon's auto-aimed onto a target
|
||||
bool bOnTarget = ( m_iState == WEAPON_IS_ONTARGET );
|
||||
|
||||
if ( player->GetFOV() >= 90 )
|
||||
{
|
||||
// normal crosshairs
|
||||
if ( bOnTarget && GetWpnData().iconAutoaim )
|
||||
{
|
||||
clr[3] = 255;
|
||||
|
||||
pCrosshair->SetCrosshair( GetWpnData().iconAutoaim, clr );
|
||||
}
|
||||
else if ( GetWpnData().iconCrosshair )
|
||||
{
|
||||
clr[3] = 255;
|
||||
pCrosshair->SetCrosshair( GetWpnData().iconCrosshair, clr );
|
||||
}
|
||||
else
|
||||
{
|
||||
pCrosshair->ResetCrosshair();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Color white( 255, 255, 255, 255 );
|
||||
|
||||
// zoomed crosshairs
|
||||
if (bOnTarget && GetWpnData().iconZoomedAutoaim)
|
||||
pCrosshair->SetCrosshair(GetWpnData().iconZoomedAutoaim, white);
|
||||
else if ( GetWpnData().iconZoomedCrosshair )
|
||||
pCrosshair->SetCrosshair( GetWpnData().iconZoomedCrosshair, white );
|
||||
else
|
||||
pCrosshair->ResetCrosshair();
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: This weapon is the active weapon, and the viewmodel for it was just drawn.
|
||||
//-----------------------------------------------------------------------------
|
||||
void C_BaseCombatWeapon::ViewModelDrawn( C_BaseViewModel *pViewModel )
|
||||
{
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Returns true if this client's carrying this weapon
|
||||
//-----------------------------------------------------------------------------
|
||||
bool C_BaseCombatWeapon::IsCarriedByLocalPlayer( void )
|
||||
{
|
||||
if ( !GetOwner() )
|
||||
return false;
|
||||
|
||||
return ( GetOwner() == C_BasePlayer::GetLocalPlayer() );
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Returns true if this client is carrying this weapon and is
|
||||
// using the view models
|
||||
//-----------------------------------------------------------------------------
|
||||
bool C_BaseCombatWeapon::ShouldDrawUsingViewModel( void )
|
||||
{
|
||||
return IsCarriedByLocalPlayer() && !C_BasePlayer::ShouldDrawLocalPlayer();
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Returns true if this weapon is the local client's currently wielded weapon
|
||||
//-----------------------------------------------------------------------------
|
||||
bool C_BaseCombatWeapon::IsActiveByLocalPlayer( void )
|
||||
{
|
||||
if ( IsCarriedByLocalPlayer() )
|
||||
{
|
||||
return (m_iState == WEAPON_IS_ACTIVE);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool C_BaseCombatWeapon::GetShootPosition( Vector &vOrigin, QAngle &vAngles )
|
||||
{
|
||||
// Get the entity because the weapon doesn't have the right angles.
|
||||
C_BaseCombatCharacter *pEnt = ToBaseCombatCharacter( GetOwner() );
|
||||
if ( pEnt )
|
||||
{
|
||||
if ( pEnt == C_BasePlayer::GetLocalPlayer() )
|
||||
{
|
||||
vAngles = pEnt->EyeAngles();
|
||||
}
|
||||
else
|
||||
{
|
||||
vAngles = pEnt->GetRenderAngles();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
vAngles.Init();
|
||||
}
|
||||
|
||||
QAngle vDummy;
|
||||
if ( IsActiveByLocalPlayer() && ShouldDrawLocalPlayerViewModel() )
|
||||
{
|
||||
C_BasePlayer *player = ToBasePlayer( pEnt );
|
||||
C_BaseViewModel *vm = player ? player->GetViewModel( 0 ) : NULL;
|
||||
if ( vm )
|
||||
{
|
||||
int iAttachment = vm->LookupAttachment( "muzzle" );
|
||||
if ( vm->GetAttachment( iAttachment, vOrigin, vDummy ) )
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Thirdperson
|
||||
int iAttachment = LookupAttachment( "muzzle" );
|
||||
if ( GetAttachment( iAttachment, vOrigin, vDummy ) )
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
vOrigin = GetRenderOrigin();
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
// Output : Returns true on success, false on failure.
|
||||
//-----------------------------------------------------------------------------
|
||||
bool C_BaseCombatWeapon::ShouldDraw( void )
|
||||
{
|
||||
if ( m_iWorldModelIndex == 0 )
|
||||
return false;
|
||||
|
||||
// FIXME: All weapons with owners are set to transmit in CBaseCombatWeapon::UpdateTransmitState,
|
||||
// even if they have EF_NODRAW set, so we have to check this here. Ideally they would never
|
||||
// transmit except for the weapons owned by the local player.
|
||||
if ( IsEffectActive( EF_NODRAW ) )
|
||||
return false;
|
||||
|
||||
C_BaseCombatCharacter *pOwner = GetOwner();
|
||||
|
||||
// weapon has no owner, always draw it
|
||||
if ( !pOwner )
|
||||
return true;
|
||||
|
||||
bool bIsActive = ( m_iState == WEAPON_IS_ACTIVE );
|
||||
|
||||
C_BasePlayer *pLocalPlayer = C_BasePlayer::GetLocalPlayer();
|
||||
|
||||
// carried by local player?
|
||||
if ( pOwner == pLocalPlayer )
|
||||
{
|
||||
// Only ever show the active weapon
|
||||
if ( !bIsActive )
|
||||
return false;
|
||||
|
||||
if ( !pOwner->ShouldDraw() )
|
||||
{
|
||||
// Our owner is invisible.
|
||||
// This also tests whether the player is zoomed in, in which case you don't want to draw the weapon.
|
||||
return false;
|
||||
}
|
||||
|
||||
// 3rd person mode?
|
||||
if ( !ShouldDrawLocalPlayerViewModel() )
|
||||
return true;
|
||||
|
||||
// don't draw active weapon if not in some kind of 3rd person mode, the viewmodel will do that
|
||||
return false;
|
||||
}
|
||||
|
||||
// If it's a player, then only show active weapons
|
||||
if ( pOwner->IsPlayer() )
|
||||
{
|
||||
// Show it if it's active...
|
||||
return bIsActive;
|
||||
}
|
||||
|
||||
// FIXME: We may want to only show active weapons on NPCs
|
||||
// These are carried by AIs; always show them
|
||||
return true;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Return true if a weapon-pickup icon should be displayed when this weapon is received
|
||||
//-----------------------------------------------------------------------------
|
||||
bool C_BaseCombatWeapon::ShouldDrawPickup( void )
|
||||
{
|
||||
if ( GetWeaponFlags() & ITEM_FLAG_NOITEMPICKUP )
|
||||
return false;
|
||||
|
||||
if ( m_bJustRestored )
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Render the weapon. Draw the Viewmodel if the weapon's being carried
|
||||
// by this player, otherwise draw the worldmodel.
|
||||
//-----------------------------------------------------------------------------
|
||||
int C_BaseCombatWeapon::DrawModel( int flags )
|
||||
{
|
||||
VPROF_BUDGET( "C_BaseCombatWeapon::DrawModel", VPROF_BUDGETGROUP_MODEL_RENDERING );
|
||||
if ( !m_bReadyToDraw )
|
||||
return 0;
|
||||
|
||||
if ( !IsVisible() )
|
||||
return 0;
|
||||
|
||||
// check if local player chases owner of this weapon in first person
|
||||
C_BasePlayer *localplayer = C_BasePlayer::GetLocalPlayer();
|
||||
|
||||
if ( localplayer && localplayer->IsObserver() && GetOwner() )
|
||||
{
|
||||
// don't draw weapon if chasing this guy as spectator
|
||||
// we don't check that in ShouldDraw() since this may change
|
||||
// without notification
|
||||
|
||||
if ( localplayer->GetObserverMode() == OBS_MODE_IN_EYE &&
|
||||
localplayer->GetObserverTarget() == GetOwner() )
|
||||
return false;
|
||||
}
|
||||
|
||||
return BaseClass::DrawModel( flags );
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Allows the client-side entity to override what the network tells it to use for
|
||||
// a model. This is used for third person mode, specifically in HL2 where the
|
||||
// the weapon timings are on the view model and not the world model. That means the
|
||||
// server needs to use the view model, but the client wants to use the world model.
|
||||
//-----------------------------------------------------------------------------
|
||||
int C_BaseCombatWeapon::CalcOverrideModelIndex()
|
||||
{
|
||||
C_BasePlayer *localplayer = C_BasePlayer::GetLocalPlayer();
|
||||
if ( localplayer &&
|
||||
localplayer == GetOwner() &&
|
||||
ShouldDrawLocalPlayerViewModel() )
|
||||
{
|
||||
return BaseClass::CalcOverrideModelIndex();
|
||||
}
|
||||
else
|
||||
{
|
||||
return GetWorldModelIndex();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// tool recording
|
||||
//-----------------------------------------------------------------------------
|
||||
void C_BaseCombatWeapon::GetToolRecordingState( KeyValues *msg )
|
||||
{
|
||||
if ( !ToolsEnabled() )
|
||||
return;
|
||||
|
||||
int nModelIndex = GetModelIndex();
|
||||
int nWorldModelIndex = GetWorldModelIndex();
|
||||
if ( nModelIndex != nWorldModelIndex )
|
||||
{
|
||||
SetModelIndex( nWorldModelIndex );
|
||||
}
|
||||
|
||||
BaseClass::GetToolRecordingState( msg );
|
||||
|
||||
if ( m_iState == WEAPON_NOT_CARRIED )
|
||||
{
|
||||
BaseEntityRecordingState_t *pBaseEntity = (BaseEntityRecordingState_t*)msg->GetPtr( "baseentity" );
|
||||
pBaseEntity->m_nOwner = -1;
|
||||
}
|
||||
else
|
||||
{
|
||||
msg->SetInt( "worldmodel", 1 );
|
||||
if ( m_iState == WEAPON_IS_ACTIVE )
|
||||
{
|
||||
BaseEntityRecordingState_t *pBaseEntity = (BaseEntityRecordingState_t*)msg->GetPtr( "baseentity" );
|
||||
pBaseEntity->m_bVisible = true;
|
||||
}
|
||||
}
|
||||
|
||||
if ( nModelIndex != nWorldModelIndex )
|
||||
{
|
||||
SetModelIndex( nModelIndex );
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose: Client's CBaseCombatWeapon entity
|
||||
//
|
||||
// $Workfile: $
|
||||
// $Date: $
|
||||
// $NoKeywords: $
|
||||
//=============================================================================//
|
||||
#ifndef C_BASECOMBATWEAPON_H
|
||||
#define C_BASECOMBATWEAPON_H
|
||||
|
||||
#ifdef _WIN32
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
#include "basecombatweapon_shared.h"
|
||||
#include "weapons_resource.h"
|
||||
|
||||
class CViewSetup;
|
||||
class C_BaseViewModel;
|
||||
|
||||
// Accessors for local weapons
|
||||
C_BaseCombatWeapon *GetActiveWeapon( void );
|
||||
|
||||
|
||||
#endif // C_BASECOMBATWEAPON
|
||||
@@ -0,0 +1,28 @@
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
// $NoKeywords: $
|
||||
//=============================================================================//
|
||||
#include "cbase.h"
|
||||
#include "c_basedoor.h"
|
||||
|
||||
// memdbgon must be the last include file in a .cpp file!!!
|
||||
#include "tier0/memdbgon.h"
|
||||
|
||||
#ifdef CBaseDoor
|
||||
#undef CBaseDoor
|
||||
#endif
|
||||
|
||||
IMPLEMENT_CLIENTCLASS_DT(C_BaseDoor, DT_BaseDoor, CBaseDoor)
|
||||
RecvPropFloat(RECVINFO(m_flWaveHeight)),
|
||||
END_RECV_TABLE()
|
||||
|
||||
C_BaseDoor::C_BaseDoor( void )
|
||||
{
|
||||
m_flWaveHeight = 0.0f;
|
||||
}
|
||||
|
||||
C_BaseDoor::~C_BaseDoor( void )
|
||||
{
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
// $NoKeywords: $
|
||||
//=============================================================================//
|
||||
#if !defined( C_BASEDOOR_H )
|
||||
#define C_BASEDOOR_H
|
||||
#ifdef _WIN32
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
#include "c_baseentity.h"
|
||||
|
||||
#if defined( CLIENT_DLL )
|
||||
#define CBaseDoor C_BaseDoor
|
||||
#endif
|
||||
|
||||
class C_BaseDoor : public C_BaseEntity
|
||||
{
|
||||
public:
|
||||
DECLARE_CLASS( C_BaseDoor, C_BaseEntity );
|
||||
DECLARE_CLIENTCLASS();
|
||||
|
||||
C_BaseDoor( void );
|
||||
~C_BaseDoor( void );
|
||||
|
||||
public:
|
||||
float m_flWaveHeight;
|
||||
};
|
||||
|
||||
#endif // C_BASEDOOR_H
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,341 @@
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
// $NoKeywords: $
|
||||
//
|
||||
//===========================================================================//
|
||||
// Client-side CBasePlayer
|
||||
|
||||
#ifndef C_STUDIOFLEX_H
|
||||
#define C_STUDIOFLEX_H
|
||||
#pragma once
|
||||
|
||||
|
||||
#include "c_baseanimating.h"
|
||||
#include "c_baseanimatingoverlay.h"
|
||||
#include "sceneentity_shared.h"
|
||||
|
||||
#include "utlvector.h"
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Item in list of loaded scene files
|
||||
//-----------------------------------------------------------------------------
|
||||
class CFlexSceneFile
|
||||
{
|
||||
public:
|
||||
enum
|
||||
{
|
||||
MAX_FLEX_FILENAME = 128,
|
||||
};
|
||||
|
||||
char filename[ MAX_FLEX_FILENAME ];
|
||||
void *buffer;
|
||||
};
|
||||
|
||||
// For phoneme emphasis track
|
||||
struct Emphasized_Phoneme;
|
||||
class CSentence;
|
||||
|
||||
enum
|
||||
{
|
||||
PHONEME_CLASS_WEAK = 0,
|
||||
PHONEME_CLASS_NORMAL,
|
||||
PHONEME_CLASS_STRONG,
|
||||
|
||||
NUM_PHONEME_CLASSES
|
||||
};
|
||||
|
||||
// Mapping for each loaded scene file used by this actor
|
||||
struct FS_LocalToGlobal_t
|
||||
{
|
||||
explicit FS_LocalToGlobal_t() :
|
||||
m_Key( 0 ),
|
||||
m_nCount( 0 ),
|
||||
m_Mapping( 0 )
|
||||
{
|
||||
}
|
||||
|
||||
explicit FS_LocalToGlobal_t( const flexsettinghdr_t *key ) :
|
||||
m_Key( key ),
|
||||
m_nCount( 0 ),
|
||||
m_Mapping( 0 )
|
||||
{
|
||||
}
|
||||
|
||||
void SetCount( int count )
|
||||
{
|
||||
Assert( !m_Mapping );
|
||||
Assert( count > 0 );
|
||||
m_nCount = count;
|
||||
m_Mapping = new int[ m_nCount ];
|
||||
Q_memset( m_Mapping, 0, m_nCount * sizeof( int ) );
|
||||
}
|
||||
|
||||
FS_LocalToGlobal_t( const FS_LocalToGlobal_t& src )
|
||||
{
|
||||
m_Key = src.m_Key;
|
||||
delete m_Mapping;
|
||||
m_Mapping = new int[ src.m_nCount ];
|
||||
Q_memcpy( m_Mapping, src.m_Mapping, src.m_nCount * sizeof( int ) );
|
||||
|
||||
m_nCount = src.m_nCount;
|
||||
}
|
||||
|
||||
~FS_LocalToGlobal_t()
|
||||
{
|
||||
delete m_Mapping;
|
||||
m_nCount = 0;
|
||||
m_Mapping = 0;
|
||||
}
|
||||
|
||||
const flexsettinghdr_t *m_Key;
|
||||
int m_nCount;
|
||||
int *m_Mapping;
|
||||
};
|
||||
|
||||
bool FlexSettingLessFunc( const FS_LocalToGlobal_t& lhs, const FS_LocalToGlobal_t& rhs );
|
||||
|
||||
class IHasLocalToGlobalFlexSettings
|
||||
{
|
||||
public:
|
||||
virtual void EnsureTranslations( const flexsettinghdr_t *pSettinghdr ) = 0;
|
||||
};
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
struct Emphasized_Phoneme
|
||||
{
|
||||
// Global fields, setup at start
|
||||
char classname[ 64 ];
|
||||
bool required;
|
||||
// Global fields setup first time tracks played
|
||||
bool basechecked;
|
||||
const flexsettinghdr_t *base;
|
||||
const flexsetting_t *exp;
|
||||
|
||||
// Local fields, processed for each sentence
|
||||
bool valid;
|
||||
float amount;
|
||||
};
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
class C_BaseFlex : public C_BaseAnimatingOverlay, public IHasLocalToGlobalFlexSettings
|
||||
{
|
||||
DECLARE_CLASS( C_BaseFlex, C_BaseAnimatingOverlay );
|
||||
public:
|
||||
DECLARE_CLIENTCLASS();
|
||||
DECLARE_PREDICTABLE();
|
||||
DECLARE_INTERPOLATION();
|
||||
|
||||
C_BaseFlex();
|
||||
virtual ~C_BaseFlex();
|
||||
|
||||
virtual void Spawn();
|
||||
|
||||
virtual void InitPhonemeMappings();
|
||||
|
||||
void SetupMappings( char const *pchFileRoot );
|
||||
|
||||
virtual CStudioHdr *OnNewModel( void );
|
||||
|
||||
virtual void StandardBlendingRules( CStudioHdr *hdr, Vector pos[], Quaternion q[], float currentTime, int boneMask );
|
||||
|
||||
virtual void OnThreadedDrawSetup();
|
||||
|
||||
// model specific
|
||||
virtual void BuildTransformations( CStudioHdr *pStudioHdr, Vector *pos, Quaternion q[], const matrix3x4_t& cameraTransform, int boneMask, CBoneBitList &boneComputed );
|
||||
static void LinkToGlobalFlexControllers( CStudioHdr *hdr );
|
||||
virtual void SetupWeights( const matrix3x4_t *pBoneToWorld, int nFlexWeightCount, float *pFlexWeights, float *pFlexDelayedWeights );
|
||||
virtual bool SetupGlobalWeights( const matrix3x4_t *pBoneToWorld, int nFlexWeightCount, float *pFlexWeights, float *pFlexDelayedWeights );
|
||||
static void RunFlexDelay( int nFlexWeightCount, float *pFlexWeights, float *pFlexDelayedWeights, float &flFlexDelayTime );
|
||||
virtual void SetupLocalWeights( const matrix3x4_t *pBoneToWorld, int nFlexWeightCount, float *pFlexWeights, float *pFlexDelayedWeights );
|
||||
virtual bool UsesFlexDelayedWeights();
|
||||
|
||||
static void RunFlexRules( CStudioHdr *pStudioHdr, float *dest );
|
||||
|
||||
virtual Vector SetViewTarget( CStudioHdr *pStudioHdr );
|
||||
|
||||
virtual bool GetSoundSpatialization( SpatializationInfo_t& info );
|
||||
|
||||
virtual void GetToolRecordingState( KeyValues *msg );
|
||||
|
||||
// Called at the lowest level to actually apply a flex animation
|
||||
void AddFlexAnimation( CSceneEventInfo *info );
|
||||
|
||||
void SetFlexWeight( LocalFlexController_t index, float value );
|
||||
float GetFlexWeight( LocalFlexController_t index );
|
||||
|
||||
// Look up flex controller index by global name
|
||||
LocalFlexController_t FindFlexController( const char *szName );
|
||||
|
||||
public:
|
||||
Vector m_viewtarget;
|
||||
CInterpolatedVar< Vector > m_iv_viewtarget;
|
||||
// indexed by model local flexcontroller
|
||||
float m_flexWeight[MAXSTUDIOFLEXCTRL];
|
||||
CInterpolatedVarArray< float, MAXSTUDIOFLEXCTRL > m_iv_flexWeight;
|
||||
|
||||
int m_blinktoggle;
|
||||
|
||||
static int AddGlobalFlexController( const char *szName );
|
||||
static char const *GetGlobalFlexControllerName( int idx );
|
||||
|
||||
// bah, this should be unified with all prev/current stuff.
|
||||
|
||||
public:
|
||||
|
||||
// Keep track of what scenes are being played
|
||||
void StartChoreoScene( CChoreoScene *scene );
|
||||
void RemoveChoreoScene( CChoreoScene *scene );
|
||||
|
||||
// Start the specifics of an scene event
|
||||
virtual bool StartSceneEvent( CSceneEventInfo *info, CChoreoScene *scene, CChoreoEvent *event, CChoreoActor *actor, C_BaseEntity *pTarget );
|
||||
|
||||
// Manipulation of events for the object
|
||||
// Should be called by think function to process all scene events
|
||||
// The default implementation resets m_flexWeight array and calls
|
||||
// AddSceneEvents
|
||||
virtual void ProcessSceneEvents( bool bFlexEvents );
|
||||
|
||||
// Assumes m_flexWeight array has been set up, this adds the actual currently playing
|
||||
// expressions to the flex weights and adds other scene events as needed
|
||||
virtual bool ProcessSceneEvent( bool bFlexEvents, CSceneEventInfo *info, CChoreoScene *scene, CChoreoEvent *event );
|
||||
|
||||
virtual bool ProcessSequenceSceneEvent( CSceneEventInfo *info, CChoreoScene *scene, CChoreoEvent *event );
|
||||
|
||||
// Remove all playing events
|
||||
void ClearSceneEvents( CChoreoScene *scene, bool canceled );
|
||||
|
||||
// Stop specifics of event
|
||||
virtual bool ClearSceneEvent( CSceneEventInfo *info, bool fastKill, bool canceled );
|
||||
|
||||
// Add the event to the queue for this actor
|
||||
void AddSceneEvent( CChoreoScene *scene, CChoreoEvent *event, C_BaseEntity *pTarget = NULL, bool bClientSide = false );
|
||||
|
||||
// Remove the event from the queue for this actor
|
||||
void RemoveSceneEvent( CChoreoScene *scene, CChoreoEvent *event, bool fastKill );
|
||||
|
||||
// Checks to see if the event should be considered "completed"
|
||||
bool CheckSceneEvent( float currenttime, CChoreoScene *scene, CChoreoEvent *event );
|
||||
|
||||
// Checks to see if a event should be considered "completed"
|
||||
virtual bool CheckSceneEventCompletion( CSceneEventInfo *info, float currenttime, CChoreoScene *scene, CChoreoEvent *event );
|
||||
|
||||
int FlexControllerLocalToGlobal( const flexsettinghdr_t *pSettinghdr, int key );
|
||||
|
||||
// IHasLocalToGlobalFlexSettings
|
||||
virtual void EnsureTranslations( const flexsettinghdr_t *pSettinghdr );
|
||||
|
||||
// For handling scene files
|
||||
void *FindSceneFile( const char *filename );
|
||||
|
||||
private:
|
||||
|
||||
bool RequestStartSequenceSceneEvent( CSceneEventInfo *info, CChoreoScene *scene, CChoreoEvent *event, CChoreoActor *actor, CBaseEntity *pTarget );
|
||||
|
||||
bool ProcessFlexAnimationSceneEvent( CSceneEventInfo *info, CChoreoScene *scene, CChoreoEvent *event );
|
||||
bool ProcessFlexSettingSceneEvent( CSceneEventInfo *info, CChoreoScene *scene, CChoreoEvent *event );
|
||||
void AddFlexSetting( const char *expr, float scale,
|
||||
const flexsettinghdr_t *pSettinghdr, bool newexpression );
|
||||
|
||||
// Array of active SceneEvents, in order oldest to newest
|
||||
CUtlVector < CSceneEventInfo > m_SceneEvents;
|
||||
CUtlVector < CChoreoScene * > m_ActiveChoreoScenes;
|
||||
|
||||
bool HasSceneEvents() const;
|
||||
|
||||
private:
|
||||
CUtlRBTree< FS_LocalToGlobal_t, unsigned short > m_LocalToGlobal;
|
||||
|
||||
float m_blinktime;
|
||||
int m_prevblinktoggle;
|
||||
|
||||
int m_iBlink;
|
||||
LocalFlexController_t m_iEyeUpdown;
|
||||
LocalFlexController_t m_iEyeRightleft;
|
||||
bool m_bSearchedForEyeFlexes;
|
||||
int m_iMouthAttachment;
|
||||
|
||||
float m_flFlexDelayTime;
|
||||
float *m_flFlexDelayedWeight;
|
||||
int m_cFlexDelayedWeight;
|
||||
|
||||
// shared flex controllers
|
||||
static int g_numflexcontrollers;
|
||||
static char *g_flexcontroller[MAXSTUDIOFLEXCTRL*4]; // room for global set of flexcontrollers
|
||||
static float g_flexweight[MAXSTUDIOFLEXDESC];
|
||||
|
||||
protected:
|
||||
|
||||
Emphasized_Phoneme m_PhonemeClasses[ NUM_PHONEME_CLASSES ];
|
||||
|
||||
private:
|
||||
|
||||
C_BaseFlex( const C_BaseFlex & ); // not defined, not accessible
|
||||
|
||||
const flexsetting_t *FindNamedSetting( const flexsettinghdr_t *pSettinghdr, const char *expr );
|
||||
|
||||
void ProcessVisemes( Emphasized_Phoneme *classes );
|
||||
void AddVisemesForSentence( Emphasized_Phoneme *classes, float emphasis_intensity, CSentence *sentence, float t, float dt, bool juststarted );
|
||||
void AddViseme( Emphasized_Phoneme *classes, float emphasis_intensity, int phoneme, float scale, bool newexpression );
|
||||
bool SetupEmphasisBlend( Emphasized_Phoneme *classes, int phoneme );
|
||||
void ComputeBlendedSetting( Emphasized_Phoneme *classes, float emphasis_intensity );
|
||||
|
||||
#ifdef HL2_CLIENT_DLL
|
||||
public:
|
||||
|
||||
Vector m_vecLean;
|
||||
CInterpolatedVar< Vector > m_iv_vecLean;
|
||||
Vector m_vecShift;
|
||||
CInterpolatedVar< Vector > m_iv_vecShift;
|
||||
#endif
|
||||
};
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
class CFlexSceneFileManager : CAutoGameSystem
|
||||
{
|
||||
public:
|
||||
|
||||
CFlexSceneFileManager() : CAutoGameSystem( "CFlexSceneFileManager" )
|
||||
{
|
||||
}
|
||||
|
||||
virtual bool Init();
|
||||
virtual void Shutdown();
|
||||
|
||||
void EnsureTranslations( IHasLocalToGlobalFlexSettings *instance, const flexsettinghdr_t *pSettinghdr );
|
||||
void *FindSceneFile( IHasLocalToGlobalFlexSettings *instance, const char *filename, bool allowBlockingIO );
|
||||
|
||||
private:
|
||||
void DeleteSceneFiles();
|
||||
|
||||
CUtlVector< CFlexSceneFile * > m_FileList;
|
||||
};
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Do we have active expressions?
|
||||
//-----------------------------------------------------------------------------
|
||||
inline bool C_BaseFlex::HasSceneEvents() const
|
||||
{
|
||||
return m_SceneEvents.Count() != 0;
|
||||
}
|
||||
|
||||
|
||||
EXTERN_RECV_TABLE(DT_BaseFlex);
|
||||
|
||||
float *GetVisemeWeights( int phoneme );
|
||||
|
||||
|
||||
#endif // C_STUDIOFLEX_H
|
||||
|
||||
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,700 @@
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose: Client-side CBasePlayer.
|
||||
//
|
||||
// - Manages the player's flashlight effect.
|
||||
//
|
||||
//=============================================================================//
|
||||
|
||||
#ifndef C_BASEPLAYER_H
|
||||
#define C_BASEPLAYER_H
|
||||
#ifdef _WIN32
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
#include "c_playerlocaldata.h"
|
||||
#include "c_basecombatcharacter.h"
|
||||
#include "PlayerState.h"
|
||||
#include "usercmd.h"
|
||||
#include "shareddefs.h"
|
||||
#include "timedevent.h"
|
||||
#include "smartptr.h"
|
||||
#include "fx_water.h"
|
||||
#include "hintsystem.h"
|
||||
#include "SoundEmitterSystem/isoundemittersystembase.h"
|
||||
#include "c_env_fog_controller.h"
|
||||
#include "igameevents.h"
|
||||
#include "GameEventListener.h"
|
||||
|
||||
#if defined USES_ECON_ITEMS
|
||||
#include "econ_item.h"
|
||||
#include "game_item_schema.h"
|
||||
#include "econ_item_view.h"
|
||||
#endif
|
||||
|
||||
class C_BaseCombatWeapon;
|
||||
class C_BaseViewModel;
|
||||
class C_FuncLadder;
|
||||
class CFlashlightEffect;
|
||||
class C_EconWearable;
|
||||
|
||||
extern int g_nKillCamMode;
|
||||
extern int g_nKillCamTarget1;
|
||||
extern int g_nKillCamTarget2;
|
||||
|
||||
class C_CommandContext
|
||||
{
|
||||
public:
|
||||
bool needsprocessing;
|
||||
|
||||
CUserCmd cmd;
|
||||
int command_number;
|
||||
};
|
||||
|
||||
class C_PredictionError
|
||||
{
|
||||
public:
|
||||
float time;
|
||||
Vector error;
|
||||
};
|
||||
|
||||
#define CHASE_CAM_DISTANCE_MIN 16.0f
|
||||
#define CHASE_CAM_DISTANCE_MAX 96.0f
|
||||
#define WALL_OFFSET 6.0f
|
||||
|
||||
|
||||
bool IsInFreezeCam( void );
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Base Player class
|
||||
//-----------------------------------------------------------------------------
|
||||
class C_BasePlayer : public C_BaseCombatCharacter, public CGameEventListener
|
||||
{
|
||||
public:
|
||||
DECLARE_CLASS( C_BasePlayer, C_BaseCombatCharacter );
|
||||
DECLARE_CLIENTCLASS();
|
||||
DECLARE_PREDICTABLE();
|
||||
DECLARE_INTERPOLATION();
|
||||
|
||||
C_BasePlayer();
|
||||
virtual ~C_BasePlayer();
|
||||
|
||||
virtual void Spawn( void );
|
||||
virtual void SharedSpawn(); // Shared between client and server.
|
||||
virtual bool GetSteamID( CSteamID *pID );
|
||||
|
||||
// IClientEntity overrides.
|
||||
virtual void OnPreDataChanged( DataUpdateType_t updateType );
|
||||
virtual void OnDataChanged( DataUpdateType_t updateType );
|
||||
|
||||
virtual void PreDataUpdate( DataUpdateType_t updateType );
|
||||
virtual void PostDataUpdate( DataUpdateType_t updateType );
|
||||
|
||||
virtual void ReceiveMessage( int classID, bf_read &msg );
|
||||
|
||||
virtual void OnRestore();
|
||||
|
||||
virtual void AddEntity( void );
|
||||
|
||||
virtual void MakeTracer( const Vector &vecTracerSrc, const trace_t &tr, int iTracerType );
|
||||
|
||||
virtual void GetToolRecordingState( KeyValues *msg );
|
||||
|
||||
virtual float GetPlayerMaxSpeed();
|
||||
|
||||
void SetAnimationExtension( const char *pExtension );
|
||||
|
||||
C_BaseViewModel *GetViewModel( int viewmodelindex = 0, bool bObserverOK=true );
|
||||
C_BaseCombatWeapon *GetActiveWeapon( void ) const;
|
||||
const char *GetTracerType( void );
|
||||
|
||||
// View model prediction setup
|
||||
virtual void CalcView( Vector &eyeOrigin, QAngle &eyeAngles, float &zNear, float &zFar, float &fov );
|
||||
virtual void CalcViewModelView( const Vector& eyeOrigin, const QAngle& eyeAngles);
|
||||
|
||||
|
||||
// Handle view smoothing when going up stairs
|
||||
void SmoothViewOnStairs( Vector& eyeOrigin );
|
||||
virtual float CalcRoll (const QAngle& angles, const Vector& velocity, float rollangle, float rollspeed);
|
||||
void CalcViewRoll( QAngle& eyeAngles );
|
||||
void CreateWaterEffects( void );
|
||||
|
||||
virtual void SetPlayerUnderwater( bool state );
|
||||
void UpdateUnderwaterState( void );
|
||||
bool IsPlayerUnderwater( void ) { return m_bPlayerUnderwater; }
|
||||
|
||||
virtual Vector Weapon_ShootPosition();
|
||||
virtual void Weapon_DropPrimary( void ) {}
|
||||
|
||||
virtual Vector GetAutoaimVector( float flScale );
|
||||
void SetSuitUpdate(const char *name, int fgroup, int iNoRepeat);
|
||||
|
||||
// Input handling
|
||||
virtual bool CreateMove( float flInputSampleTime, CUserCmd *pCmd );
|
||||
virtual void AvoidPhysicsProps( CUserCmd *pCmd );
|
||||
|
||||
virtual void PlayerUse( void );
|
||||
CBaseEntity *FindUseEntity( void );
|
||||
virtual bool IsUseableEntity( CBaseEntity *pEntity, unsigned int requiredCaps );
|
||||
|
||||
// Data handlers
|
||||
virtual bool IsPlayer( void ) const { return true; }
|
||||
virtual int GetHealth() const { return m_iHealth; }
|
||||
|
||||
int GetBonusProgress() const { return m_iBonusProgress; }
|
||||
int GetBonusChallenge() const { return m_iBonusChallenge; }
|
||||
|
||||
// observer mode
|
||||
virtual int GetObserverMode() const;
|
||||
void SetObserverMode ( int iNewMode );
|
||||
virtual CBaseEntity *GetObserverTarget() const;
|
||||
void SetObserverTarget( EHANDLE hObserverTarget );
|
||||
|
||||
bool AudioStateIsUnderwater( Vector vecMainViewOrigin );
|
||||
|
||||
bool IsObserver() const;
|
||||
bool IsHLTV() const;
|
||||
bool IsReplay() const;
|
||||
void ResetObserverMode();
|
||||
bool IsBot( void ) const { return false; }
|
||||
|
||||
// Eye position..
|
||||
virtual Vector EyePosition();
|
||||
virtual const QAngle &EyeAngles(); // Direction of eyes
|
||||
void EyePositionAndVectors( Vector *pPosition, Vector *pForward, Vector *pRight, Vector *pUp );
|
||||
virtual const QAngle &LocalEyeAngles(); // Direction of eyes
|
||||
|
||||
// This can be overridden to return something other than m_pRagdoll if the mod uses separate
|
||||
// entities for ragdolls.
|
||||
virtual IRagdoll* GetRepresentativeRagdoll() const;
|
||||
|
||||
// override the initial bone position for ragdolls
|
||||
virtual bool GetRagdollInitBoneArrays( matrix3x4_t *pDeltaBones0, matrix3x4_t *pDeltaBones1, matrix3x4_t *pCurrentBones, float boneDt ) OVERRIDE;
|
||||
|
||||
// Returns eye vectors
|
||||
void EyeVectors( Vector *pForward, Vector *pRight = NULL, Vector *pUp = NULL );
|
||||
void CacheVehicleView( void ); // Calculate and cache the position of the player in the vehicle
|
||||
|
||||
|
||||
bool IsSuitEquipped( void ) { return m_Local.m_bWearingSuit; };
|
||||
|
||||
// Team handlers
|
||||
virtual void TeamChange( int iNewTeam );
|
||||
|
||||
// Flashlight
|
||||
void Flashlight( void );
|
||||
void UpdateFlashlight( void );
|
||||
|
||||
// Weapon selection code
|
||||
virtual bool IsAllowedToSwitchWeapons( void ) { return !IsObserver(); }
|
||||
virtual C_BaseCombatWeapon *GetActiveWeaponForSelection( void );
|
||||
|
||||
// Returns the view model if this is the local player. If you're in third person or
|
||||
// this is a remote player, it returns the active weapon
|
||||
// (and its appropriate left/right weapon if this is TF2).
|
||||
virtual C_BaseAnimating* GetRenderedWeaponModel();
|
||||
|
||||
virtual bool IsOverridingViewmodel( void ) { return false; };
|
||||
virtual int DrawOverriddenViewmodel( C_BaseViewModel *pViewmodel, int flags ) { return 0; };
|
||||
|
||||
virtual float GetDefaultAnimSpeed( void ) { return 1.0; }
|
||||
|
||||
void SetMaxSpeed( float flMaxSpeed ) { m_flMaxspeed = flMaxSpeed; }
|
||||
float MaxSpeed() const { return m_flMaxspeed; }
|
||||
|
||||
// Should this object cast shadows?
|
||||
virtual ShadowType_t ShadowCastType() { return SHADOWS_NONE; }
|
||||
|
||||
virtual bool ShouldReceiveProjectedTextures( int flags )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
bool IsLocalPlayer( void ) const;
|
||||
|
||||
// Global/static methods
|
||||
virtual void ThirdPersonSwitch( bool bThirdperson );
|
||||
static bool LocalPlayerInFirstPersonView();
|
||||
static bool ShouldDrawLocalPlayer();
|
||||
static C_BasePlayer *GetLocalPlayer( void );
|
||||
int GetUserID( void );
|
||||
virtual bool CanSetSoundMixer( void );
|
||||
virtual int GetVisionFilterFlags( bool bWeaponsCheck = false ) { return 0x00; }
|
||||
bool HasVisionFilterFlags( int nFlags, bool bWeaponsCheck = false ) { return ( GetVisionFilterFlags( bWeaponsCheck ) & nFlags ) == nFlags; }
|
||||
virtual void CalculateVisionUsingCurrentFlags( void ) {}
|
||||
void BuildFirstPersonMeathookTransformations( CStudioHdr *hdr, Vector *pos, Quaternion q[], const matrix3x4_t& cameraTransform, int boneMask, CBoneBitList &boneComputed, const char *pchHeadBoneName );
|
||||
|
||||
// Specific queries about this player.
|
||||
bool InFirstPersonView();
|
||||
bool ShouldDrawThisPlayer();
|
||||
|
||||
// Called by the view model if its rendering is being overridden.
|
||||
virtual bool ViewModel_IsTransparent( void );
|
||||
virtual bool ViewModel_IsUsingFBTexture( void );
|
||||
|
||||
#if !defined( NO_ENTITY_PREDICTION )
|
||||
void AddToPlayerSimulationList( C_BaseEntity *other );
|
||||
void SimulatePlayerSimulatedEntities( void );
|
||||
void RemoveFromPlayerSimulationList( C_BaseEntity *ent );
|
||||
void ClearPlayerSimulationList( void );
|
||||
#endif
|
||||
|
||||
virtual void PhysicsSimulate( void );
|
||||
virtual unsigned int PhysicsSolidMaskForEntity( void ) const { return MASK_PLAYERSOLID; }
|
||||
|
||||
// Prediction stuff
|
||||
virtual bool ShouldPredict( void );
|
||||
|
||||
virtual void PreThink( void );
|
||||
virtual void PostThink( void );
|
||||
|
||||
virtual void ItemPreFrame( void );
|
||||
virtual void ItemPostFrame( void );
|
||||
virtual void AbortReload( void );
|
||||
|
||||
virtual void SelectLastItem(void);
|
||||
virtual void Weapon_SetLast( C_BaseCombatWeapon *pWeapon );
|
||||
virtual bool Weapon_ShouldSetLast( C_BaseCombatWeapon *pOldWeapon, C_BaseCombatWeapon *pNewWeapon ) { return true; }
|
||||
virtual bool Weapon_ShouldSelectItem( C_BaseCombatWeapon *pWeapon );
|
||||
virtual bool Weapon_Switch( C_BaseCombatWeapon *pWeapon, int viewmodelindex = 0 ); // Switch to given weapon if has ammo (false if failed)
|
||||
virtual C_BaseCombatWeapon *GetLastWeapon( void ) { return m_hLastWeapon.Get(); }
|
||||
void ResetAutoaim( void );
|
||||
virtual void SelectItem( const char *pstr, int iSubType = 0 );
|
||||
|
||||
virtual void UpdateClientData( void );
|
||||
|
||||
bool IsLerpingFOV( void ) const;
|
||||
virtual float GetFOV( void );
|
||||
int GetDefaultFOV( void ) const;
|
||||
virtual bool IsZoomed( void ) { return false; }
|
||||
bool SetFOV( CBaseEntity *pRequester, int FOV, float zoomRate = 0.0f, int iZoomStart = 0 );
|
||||
void ClearZoomOwner( void );
|
||||
|
||||
float GetFOVDistanceAdjustFactor();
|
||||
|
||||
virtual void ViewPunch( const QAngle &angleOffset );
|
||||
void ViewPunchReset( float tolerance = 0 );
|
||||
|
||||
void UpdateButtonState( int nUserCmdButtonMask );
|
||||
int GetImpulse( void ) const;
|
||||
|
||||
virtual void Simulate();
|
||||
|
||||
virtual bool ShouldInterpolate();
|
||||
|
||||
virtual bool ShouldDraw();
|
||||
virtual int DrawModel( int flags );
|
||||
|
||||
// Called when not in tactical mode. Allows view to be overriden for things like driving a tank.
|
||||
virtual void OverrideView( CViewSetup *pSetup );
|
||||
|
||||
// returns the player name
|
||||
const char * GetPlayerName();
|
||||
virtual const Vector GetPlayerMins( void ) const; // uses local player
|
||||
virtual const Vector GetPlayerMaxs( void ) const; // uses local player
|
||||
|
||||
// Is the player dead?
|
||||
bool IsPlayerDead();
|
||||
bool IsPoisoned( void ) { return m_Local.m_bPoisoned; }
|
||||
|
||||
C_BaseEntity *GetUseEntity();
|
||||
|
||||
// Vehicles...
|
||||
IClientVehicle *GetVehicle();
|
||||
|
||||
bool IsInAVehicle() const { return ( NULL != m_hVehicle.Get() ) ? true : false; }
|
||||
virtual void SetVehicleRole( int nRole );
|
||||
void LeaveVehicle( void );
|
||||
|
||||
bool UsingStandardWeaponsInVehicle( void );
|
||||
|
||||
virtual void SetAnimation( PLAYER_ANIM playerAnim );
|
||||
|
||||
float GetTimeBase( void ) const;
|
||||
float GetFinalPredictedTime() const;
|
||||
|
||||
bool IsInVGuiInputMode() const;
|
||||
bool IsInViewModelVGuiInputMode() const;
|
||||
|
||||
C_CommandContext *GetCommandContext();
|
||||
|
||||
// Get the command number associated with the current usercmd we're running (if in predicted code).
|
||||
int CurrentCommandNumber() const;
|
||||
const CUserCmd *GetCurrentUserCommand() const;
|
||||
|
||||
const QAngle& GetPunchAngle();
|
||||
void SetPunchAngle( const QAngle &angle );
|
||||
|
||||
float GetWaterJumpTime() const;
|
||||
void SetWaterJumpTime( float flWaterJumpTime );
|
||||
float GetSwimSoundTime( void ) const;
|
||||
void SetSwimSoundTime( float flSwimSoundTime );
|
||||
|
||||
float GetDeathTime( void ) { return m_flDeathTime; }
|
||||
|
||||
void SetPreviouslyPredictedOrigin( const Vector &vecAbsOrigin );
|
||||
const Vector &GetPreviouslyPredictedOrigin() const;
|
||||
|
||||
// CS wants to allow small FOVs for zoomed-in AWPs.
|
||||
virtual float GetMinFOV() const;
|
||||
|
||||
virtual void DoMuzzleFlash();
|
||||
virtual void PlayPlayerJingle();
|
||||
|
||||
virtual void UpdateStepSound( surfacedata_t *psurface, const Vector &vecOrigin, const Vector &vecVelocity );
|
||||
virtual void PlayStepSound( Vector &vecOrigin, surfacedata_t *psurface, float fvol, bool force );
|
||||
virtual surfacedata_t * GetFootstepSurface( const Vector &origin, const char *surfaceName );
|
||||
virtual void GetStepSoundVelocities( float *velwalk, float *velrun );
|
||||
virtual void SetStepSoundTime( stepsoundtimes_t iStepSoundTime, bool bWalking );
|
||||
virtual const char *GetOverrideStepSound( const char *pszBaseStepSoundName ) { return pszBaseStepSoundName; }
|
||||
|
||||
virtual void OnEmitFootstepSound( const CSoundParameters& params, const Vector& vecOrigin, float fVolume ) {}
|
||||
|
||||
// Called by prediction when it detects a prediction correction.
|
||||
// vDelta is the line from where the client had predicted the player to at the usercmd in question,
|
||||
// to where the server says the client should be at said usercmd.
|
||||
void NotePredictionError( const Vector &vDelta );
|
||||
|
||||
// Called by the renderer to apply the prediction error smoothing.
|
||||
void GetPredictionErrorSmoothingVector( Vector &vOffset );
|
||||
|
||||
virtual void ExitLadder() {}
|
||||
surfacedata_t *GetLadderSurface( const Vector &origin );
|
||||
|
||||
surfacedata_t *GetSurfaceData( void ) { return m_pSurfaceData; }
|
||||
|
||||
void SetLadderNormal( Vector vecLadderNormal ) { m_vecLadderNormal = vecLadderNormal; }
|
||||
|
||||
// Hints
|
||||
virtual CHintSystem *Hints( void ) { return NULL; }
|
||||
bool ShouldShowHints( void ) { return Hints() ? Hints()->ShouldShowHints() : false; }
|
||||
bool HintMessage( int hint, bool bForce = false, bool bOnlyIfClear = false ) { return Hints() ? Hints()->HintMessage( hint, bForce, bOnlyIfClear ) : false; }
|
||||
void HintMessage( const char *pMessage ) { if (Hints()) Hints()->HintMessage( pMessage ); }
|
||||
|
||||
virtual IMaterial *GetHeadLabelMaterial( void );
|
||||
|
||||
// Fog
|
||||
fogparams_t *GetFogParams( void ) { return &m_CurrentFog; }
|
||||
void FogControllerChanged( bool bSnap );
|
||||
void UpdateFogController( void );
|
||||
void UpdateFogBlend( void );
|
||||
|
||||
float GetFOVTime( void ){ return m_flFOVTime; }
|
||||
|
||||
virtual void OnAchievementAchieved( int iAchievement ) {}
|
||||
|
||||
bool ShouldAnnounceAchievement( void ){ return m_flNextAchievementAnnounceTime < gpGlobals->curtime; }
|
||||
void SetNextAchievementAnnounceTime( float flTime ){ m_flNextAchievementAnnounceTime = flTime; }
|
||||
|
||||
#if defined USES_ECON_ITEMS
|
||||
// Wearables
|
||||
virtual void UpdateWearables();
|
||||
C_EconWearable *GetWearable( int i ) { return m_hMyWearables[i]; }
|
||||
int GetNumWearables( void ) { return m_hMyWearables.Count(); }
|
||||
#endif
|
||||
|
||||
bool HasFiredWeapon( void ) { return m_bFiredWeapon; }
|
||||
void SetFiredWeapon( bool bFlag ) { m_bFiredWeapon = bFlag; }
|
||||
|
||||
virtual bool CanUseFirstPersonCommand( void ){ return true; }
|
||||
|
||||
protected:
|
||||
fogparams_t m_CurrentFog;
|
||||
EHANDLE m_hOldFogController;
|
||||
|
||||
public:
|
||||
int m_StuckLast;
|
||||
|
||||
// Data for only the local player
|
||||
CNetworkVarEmbedded( CPlayerLocalData, m_Local );
|
||||
|
||||
#if defined USES_ECON_ITEMS
|
||||
CNetworkVarEmbedded( CAttributeList, m_AttributeList );
|
||||
#endif
|
||||
|
||||
// Data common to all other players, too
|
||||
CPlayerState pl;
|
||||
|
||||
// Player FOV values
|
||||
int m_iFOV; // field of view
|
||||
int m_iFOVStart; // starting value of the FOV changing over time (client only)
|
||||
float m_flFOVTime; // starting time of the FOV zoom
|
||||
int m_iDefaultFOV; // default FOV if no other zooms are occurring
|
||||
EHANDLE m_hZoomOwner; // This is a pointer to the entity currently controlling the player's zoom
|
||||
// Only this entity can change the zoom state once it has ownership
|
||||
|
||||
// For weapon prediction
|
||||
bool m_fOnTarget; //Is the crosshair on a target?
|
||||
|
||||
char m_szAnimExtension[32];
|
||||
|
||||
int m_afButtonLast;
|
||||
int m_afButtonPressed;
|
||||
int m_afButtonReleased;
|
||||
|
||||
int m_nButtons;
|
||||
|
||||
CUserCmd *m_pCurrentCommand;
|
||||
|
||||
// Movement constraints
|
||||
EHANDLE m_hConstraintEntity;
|
||||
Vector m_vecConstraintCenter;
|
||||
float m_flConstraintRadius;
|
||||
float m_flConstraintWidth;
|
||||
float m_flConstraintSpeedFactor;
|
||||
|
||||
protected:
|
||||
|
||||
void CalcPlayerView( Vector& eyeOrigin, QAngle& eyeAngles, float& fov );
|
||||
void CalcVehicleView(IClientVehicle *pVehicle, Vector& eyeOrigin, QAngle& eyeAngles,
|
||||
float& zNear, float& zFar, float& fov );
|
||||
virtual void CalcObserverView( Vector& eyeOrigin, QAngle& eyeAngles, float& fov );
|
||||
virtual Vector GetChaseCamViewOffset( CBaseEntity *target );
|
||||
void CalcChaseCamView( Vector& eyeOrigin, QAngle& eyeAngles, float& fov );
|
||||
virtual void CalcInEyeCamView( Vector& eyeOrigin, QAngle& eyeAngles, float& fov );
|
||||
|
||||
virtual float GetDeathCamInterpolationTime();
|
||||
|
||||
virtual void CalcDeathCamView( Vector& eyeOrigin, QAngle& eyeAngles, float& fov );
|
||||
void CalcRoamingView(Vector& eyeOrigin, QAngle& eyeAngles, float& fov);
|
||||
virtual void CalcFreezeCamView( Vector& eyeOrigin, QAngle& eyeAngles, float& fov );
|
||||
|
||||
// Check to see if we're in vgui input mode...
|
||||
void DetermineVguiInputMode( CUserCmd *pCmd );
|
||||
|
||||
// Used by prediction, sets the view angles for the player
|
||||
virtual void SetLocalViewAngles( const QAngle &viewAngles );
|
||||
virtual void SetViewAngles( const QAngle& ang );
|
||||
|
||||
// used by client side player footsteps
|
||||
surfacedata_t* GetGroundSurface();
|
||||
|
||||
virtual void FireGameEvent( IGameEvent *event );
|
||||
|
||||
protected:
|
||||
// Did we just enter a vehicle this frame?
|
||||
bool JustEnteredVehicle();
|
||||
|
||||
// DATA
|
||||
int m_iObserverMode; // if in spectator mode != 0
|
||||
EHANDLE m_hObserverTarget; // current observer target
|
||||
float m_flObserverChaseDistance; // last distance to observer traget
|
||||
Vector m_vecFreezeFrameStart;
|
||||
float m_flFreezeFrameStartTime; // Time at which we entered freeze frame observer mode
|
||||
float m_flFreezeFrameDistance;
|
||||
bool m_bWasFreezeFraming;
|
||||
float m_flDeathTime; // last time player died
|
||||
|
||||
float m_flStepSoundTime;
|
||||
bool m_IsFootprintOnLeft;
|
||||
|
||||
private:
|
||||
// Make sure no one calls this...
|
||||
C_BasePlayer& operator=( const C_BasePlayer& src );
|
||||
C_BasePlayer( const C_BasePlayer & ); // not defined, not accessible
|
||||
|
||||
// Vehicle stuff.
|
||||
EHANDLE m_hVehicle;
|
||||
EHANDLE m_hOldVehicle;
|
||||
EHANDLE m_hUseEntity;
|
||||
|
||||
float m_flMaxspeed;
|
||||
|
||||
int m_iBonusProgress;
|
||||
int m_iBonusChallenge;
|
||||
|
||||
CInterpolatedVar< Vector > m_iv_vecViewOffset;
|
||||
|
||||
// Not replicated
|
||||
Vector m_vecWaterJumpVel;
|
||||
float m_flWaterJumpTime; // used to be called teleport_time
|
||||
int m_nImpulse;
|
||||
|
||||
float m_flSwimSoundTime;
|
||||
Vector m_vecLadderNormal;
|
||||
|
||||
QAngle m_vecOldViewAngles;
|
||||
|
||||
bool m_bWasFrozen;
|
||||
int m_flPhysics;
|
||||
|
||||
int m_nTickBase;
|
||||
int m_nFinalPredictedTick;
|
||||
|
||||
EHANDLE m_pCurrentVguiScreen;
|
||||
|
||||
bool m_bFiredWeapon;
|
||||
|
||||
|
||||
// Player flashlight dynamic light pointers
|
||||
CFlashlightEffect *m_pFlashlight;
|
||||
|
||||
typedef CHandle<C_BaseCombatWeapon> CBaseCombatWeaponHandle;
|
||||
CNetworkVar( CBaseCombatWeaponHandle, m_hLastWeapon );
|
||||
|
||||
#if !defined( NO_ENTITY_PREDICTION )
|
||||
CUtlVector< CHandle< C_BaseEntity > > m_SimulatedByThisPlayer;
|
||||
#endif
|
||||
|
||||
// players own view models, left & right hand
|
||||
CHandle< C_BaseViewModel > m_hViewModel[ MAX_VIEWMODELS ];
|
||||
|
||||
float m_flOldPlayerZ;
|
||||
float m_flOldPlayerViewOffsetZ;
|
||||
|
||||
Vector m_vecVehicleViewOrigin; // Used to store the calculated view of the player while riding in a vehicle
|
||||
QAngle m_vecVehicleViewAngles; // Vehicle angles
|
||||
float m_flVehicleViewFOV;
|
||||
int m_nVehicleViewSavedFrame; // Used to mark which frame was the last one the view was calculated for
|
||||
|
||||
// For UI purposes...
|
||||
int m_iOldAmmo[ MAX_AMMO_TYPES ];
|
||||
|
||||
C_CommandContext m_CommandContext;
|
||||
|
||||
// For underwater effects
|
||||
float m_flWaterSurfaceZ;
|
||||
bool m_bResampleWaterSurface;
|
||||
TimedEvent m_tWaterParticleTimer;
|
||||
CSmartPtr<WaterDebrisEffect> m_pWaterEmitter;
|
||||
|
||||
bool m_bPlayerUnderwater;
|
||||
|
||||
friend class CPrediction;
|
||||
|
||||
// HACK FOR TF2 Prediction
|
||||
friend class CTFGameMovementRecon;
|
||||
friend class CGameMovement;
|
||||
friend class CTFGameMovement;
|
||||
friend class CHL1GameMovement;
|
||||
friend class CCSGameMovement;
|
||||
friend class CHL2GameMovement;
|
||||
friend class CDODGameMovement;
|
||||
friend class CPortalGameMovement;
|
||||
|
||||
// Accessors for gamemovement
|
||||
float GetStepSize( void ) const { return m_Local.m_flStepSize; }
|
||||
|
||||
float m_flNextAvoidanceTime;
|
||||
float m_flAvoidanceRight;
|
||||
float m_flAvoidanceForward;
|
||||
float m_flAvoidanceDotForward;
|
||||
float m_flAvoidanceDotRight;
|
||||
|
||||
protected:
|
||||
virtual bool IsDucked( void ) const { return m_Local.m_bDucked; }
|
||||
virtual bool IsDucking( void ) const { return m_Local.m_bDucking; }
|
||||
virtual float GetFallVelocity( void ) { return m_Local.m_flFallVelocity; }
|
||||
bool ForceSetupBonesAtTimeFakeInterpolation( matrix3x4_t *pBonesOut, float curtimeOffset );
|
||||
|
||||
float m_flLaggedMovementValue;
|
||||
|
||||
// These are used to smooth out prediction corrections. They're most useful when colliding with
|
||||
// vphysics objects. The server will be sending constant prediction corrections, and these can help
|
||||
// the errors not be so jerky.
|
||||
Vector m_vecPredictionError;
|
||||
float m_flPredictionErrorTime;
|
||||
|
||||
Vector m_vecPreviouslyPredictedOrigin; // Used to determine if non-gamemovement game code has teleported, or tweaked the player's origin
|
||||
|
||||
char m_szLastPlaceName[MAX_PLACE_NAME_LENGTH]; // received from the server
|
||||
|
||||
// Texture names and surface data, used by CGameMovement
|
||||
int m_surfaceProps;
|
||||
surfacedata_t* m_pSurfaceData;
|
||||
float m_surfaceFriction;
|
||||
char m_chTextureType;
|
||||
|
||||
bool m_bSentFreezeFrame;
|
||||
float m_flFreezeZOffset;
|
||||
|
||||
float m_flNextAchievementAnnounceTime;
|
||||
|
||||
int m_nForceVisionFilterFlags; // Force our vision filter to a specific setting
|
||||
int m_nLocalPlayerVisionFlags;
|
||||
|
||||
#if defined USES_ECON_ITEMS
|
||||
// Wearables
|
||||
CUtlVector<CHandle<C_EconWearable > > m_hMyWearables;
|
||||
#endif
|
||||
|
||||
private:
|
||||
|
||||
struct StepSoundCache_t
|
||||
{
|
||||
StepSoundCache_t() : m_usSoundNameIndex( 0 ) {}
|
||||
CSoundParameters m_SoundParameters;
|
||||
unsigned short m_usSoundNameIndex;
|
||||
};
|
||||
// One for left and one for right side of step
|
||||
StepSoundCache_t m_StepSoundCache[ 2 ];
|
||||
|
||||
public:
|
||||
|
||||
const char *GetLastKnownPlaceName( void ) const { return m_szLastPlaceName; } // return the last nav place name the player occupied
|
||||
|
||||
float GetLaggedMovementValue( void ){ return m_flLaggedMovementValue; }
|
||||
bool ShouldGoSouth( Vector vNPCForward, Vector vNPCRight ); //Such a bad name.
|
||||
|
||||
void SetOldPlayerZ( float flOld ) { m_flOldPlayerZ = flOld; }
|
||||
};
|
||||
|
||||
EXTERN_RECV_TABLE(DT_BasePlayer);
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Inline methods
|
||||
//-----------------------------------------------------------------------------
|
||||
inline C_BasePlayer *ToBasePlayer( C_BaseEntity *pEntity )
|
||||
{
|
||||
if ( !pEntity || !pEntity->IsPlayer() )
|
||||
return NULL;
|
||||
|
||||
#if _DEBUG
|
||||
Assert( dynamic_cast<C_BasePlayer *>( pEntity ) != NULL );
|
||||
#endif
|
||||
|
||||
return static_cast<C_BasePlayer *>( pEntity );
|
||||
}
|
||||
|
||||
inline C_BaseEntity *C_BasePlayer::GetUseEntity()
|
||||
{
|
||||
return m_hUseEntity;
|
||||
}
|
||||
|
||||
|
||||
inline IClientVehicle *C_BasePlayer::GetVehicle()
|
||||
{
|
||||
C_BaseEntity *pVehicleEnt = m_hVehicle.Get();
|
||||
return pVehicleEnt ? pVehicleEnt->GetClientVehicle() : NULL;
|
||||
}
|
||||
|
||||
inline bool C_BasePlayer::IsObserver() const
|
||||
{
|
||||
return (GetObserverMode() != OBS_MODE_NONE);
|
||||
}
|
||||
|
||||
inline int C_BasePlayer::GetImpulse( void ) const
|
||||
{
|
||||
return m_nImpulse;
|
||||
}
|
||||
|
||||
|
||||
inline C_CommandContext* C_BasePlayer::GetCommandContext()
|
||||
{
|
||||
return &m_CommandContext;
|
||||
}
|
||||
|
||||
inline int CBasePlayer::CurrentCommandNumber() const
|
||||
{
|
||||
Assert( m_pCurrentCommand );
|
||||
return m_pCurrentCommand->command_number;
|
||||
}
|
||||
|
||||
inline const CUserCmd *CBasePlayer::GetCurrentUserCommand() const
|
||||
{
|
||||
Assert( m_pCurrentCommand );
|
||||
return m_pCurrentCommand;
|
||||
}
|
||||
|
||||
#endif // C_BASEPLAYER_H
|
||||
@@ -0,0 +1,201 @@
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose: Core Temp Entity client implementation.
|
||||
//
|
||||
// $NoKeywords: $
|
||||
//=============================================================================//
|
||||
#include "cbase.h"
|
||||
#include "c_basetempentity.h"
|
||||
|
||||
// memdbgon must be the last include file in a .cpp file!!!
|
||||
#include "tier0/memdbgon.h"
|
||||
|
||||
IMPLEMENT_CLIENTCLASS(C_BaseTempEntity, DT_BaseTempEntity, CBaseTempEntity);
|
||||
|
||||
BEGIN_RECV_TABLE_NOBASE(C_BaseTempEntity, DT_BaseTempEntity)
|
||||
END_RECV_TABLE()
|
||||
|
||||
|
||||
// Global list of temp entity classes
|
||||
C_BaseTempEntity *C_BaseTempEntity::s_pTempEntities = NULL;
|
||||
|
||||
// Global list of dynamic temp entities
|
||||
C_BaseTempEntity *C_BaseTempEntity::s_pDynamicEntities = NULL;
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Returns head of list
|
||||
// Output : CBaseTempEntity * -- head of list
|
||||
//-----------------------------------------------------------------------------
|
||||
C_BaseTempEntity *C_BaseTempEntity::GetDynamicList( void )
|
||||
{
|
||||
return s_pDynamicEntities;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Returns head of list
|
||||
// Output : CBaseTempEntity * -- head of list
|
||||
//-----------------------------------------------------------------------------
|
||||
C_BaseTempEntity *C_BaseTempEntity::GetList( void )
|
||||
{
|
||||
return s_pTempEntities;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
// Output :
|
||||
//-----------------------------------------------------------------------------
|
||||
C_BaseTempEntity::C_BaseTempEntity( void )
|
||||
{
|
||||
// Add to list
|
||||
m_pNext = s_pTempEntities;
|
||||
s_pTempEntities = this;
|
||||
|
||||
m_pNextDynamic = NULL;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
// Output :
|
||||
//-----------------------------------------------------------------------------
|
||||
C_BaseTempEntity::~C_BaseTempEntity( void )
|
||||
{
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Get next temp ent in chain
|
||||
// Output : CBaseTempEntity *
|
||||
//-----------------------------------------------------------------------------
|
||||
C_BaseTempEntity *C_BaseTempEntity::GetNext( void )
|
||||
{
|
||||
return m_pNext;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Get next temp ent in chain
|
||||
// Output : CBaseTempEntity *
|
||||
//-----------------------------------------------------------------------------
|
||||
C_BaseTempEntity *C_BaseTempEntity::GetNextDynamic( void )
|
||||
{
|
||||
return m_pNextDynamic;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
void C_BaseTempEntity::Precache( void )
|
||||
{
|
||||
// Nothing...
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Called at startup to allow temp entities to precache any models/sounds that they need
|
||||
//-----------------------------------------------------------------------------
|
||||
void C_BaseTempEntity::PrecacheTempEnts( void )
|
||||
{
|
||||
C_BaseTempEntity *pTe = GetList();
|
||||
while ( pTe )
|
||||
{
|
||||
pTe->Precache();
|
||||
pTe = pTe->GetNext();
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Called at startup and level load to clear out leftover temp entities
|
||||
//-----------------------------------------------------------------------------
|
||||
void C_BaseTempEntity::ClearDynamicTempEnts( void )
|
||||
{
|
||||
C_BaseTempEntity *next;
|
||||
C_BaseTempEntity *pTe = s_pDynamicEntities;
|
||||
while ( pTe )
|
||||
{
|
||||
next = pTe->GetNextDynamic();
|
||||
delete pTe;
|
||||
pTe = next;
|
||||
}
|
||||
|
||||
s_pDynamicEntities = NULL;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Called at startup and level load to clear out leftover temp entities
|
||||
//-----------------------------------------------------------------------------
|
||||
void C_BaseTempEntity::CheckDynamicTempEnts( void )
|
||||
{
|
||||
C_BaseTempEntity *next, *newlist = NULL;
|
||||
C_BaseTempEntity *pTe = s_pDynamicEntities;
|
||||
while ( pTe )
|
||||
{
|
||||
next = pTe->GetNextDynamic();
|
||||
if ( pTe->ShouldDestroy() )
|
||||
{
|
||||
delete pTe;
|
||||
}
|
||||
else
|
||||
{
|
||||
pTe->m_pNextDynamic = newlist;
|
||||
newlist = pTe;
|
||||
}
|
||||
pTe = next;
|
||||
}
|
||||
|
||||
s_pDynamicEntities = newlist;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Dynamic/non-singleton temp entities are initialized by
|
||||
// calling into here. They should be added to a list of C_BaseTempEntities so
|
||||
// that their memory can be deallocated appropriately.
|
||||
// Input : *pEnt -
|
||||
// Output : Returns true on success, false on failure.
|
||||
//-----------------------------------------------------------------------------
|
||||
bool C_BaseTempEntity::Init( int entnum, int iSerialNum )
|
||||
{
|
||||
if ( entnum != -1 )
|
||||
{
|
||||
Assert( 0 );
|
||||
}
|
||||
|
||||
// Link into dynamic entity list
|
||||
m_pNextDynamic = s_pDynamicEntities;
|
||||
s_pDynamicEntities = this;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
void C_BaseTempEntity::Release()
|
||||
{
|
||||
Assert( !"C_BaseTempEntity::Release should never be called" );
|
||||
}
|
||||
|
||||
|
||||
void C_BaseTempEntity::NotifyShouldTransmit( ShouldTransmitState_t state )
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
// Input : bool -
|
||||
//-----------------------------------------------------------------------------
|
||||
void C_BaseTempEntity::PreDataUpdate( DataUpdateType_t updateType )
|
||||
{
|
||||
// TE's may or may not implement this
|
||||
}
|
||||
|
||||
|
||||
int C_BaseTempEntity::entindex( void ) const { Assert( 0 ); return 0; }
|
||||
void C_BaseTempEntity::PostDataUpdate( DataUpdateType_t updateType ) { Assert( 0 ); }
|
||||
void C_BaseTempEntity::OnPreDataChanged( DataUpdateType_t updateType ) { Assert( 0 ); }
|
||||
void C_BaseTempEntity::OnDataChanged( DataUpdateType_t updateType ) { Assert( 0 ); }
|
||||
void C_BaseTempEntity::SetDormant( bool bDormant ) { Assert( 0 ); }
|
||||
bool C_BaseTempEntity::IsDormant( void ) { Assert( 0 ); return false; };
|
||||
void C_BaseTempEntity::ReceiveMessage( int classID, bf_read &msg ) { Assert( 0 ); }
|
||||
void C_BaseTempEntity::SetDestroyedOnRecreateEntities( void ) { Assert(0); }
|
||||
|
||||
void* C_BaseTempEntity::GetDataTableBasePtr()
|
||||
{
|
||||
return this;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,122 @@
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
// $NoKeywords: $
|
||||
//=============================================================================//
|
||||
|
||||
#ifndef C_BASETEMPENTITY_H
|
||||
#define C_BASETEMPENTITY_H
|
||||
#ifdef _WIN32
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
|
||||
#include "client_class.h"
|
||||
#include "iclientnetworkable.h"
|
||||
#include "c_recipientfilter.h"
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Base class for TEs. All TEs should derive from this and at
|
||||
// least implement OnDataChanged to be notified when the TE has been received
|
||||
// from the server
|
||||
//-----------------------------------------------------------------------------
|
||||
class C_BaseTempEntity : public IClientUnknown, public IClientNetworkable
|
||||
|
||||
{
|
||||
public:
|
||||
DECLARE_CLASS_NOBASE( C_BaseTempEntity );
|
||||
DECLARE_CLIENTCLASS();
|
||||
|
||||
C_BaseTempEntity( void );
|
||||
virtual ~C_BaseTempEntity( void );
|
||||
|
||||
|
||||
// IClientUnknown implementation.
|
||||
public:
|
||||
|
||||
virtual void SetRefEHandle( const CBaseHandle &handle ) { Assert( false ); }
|
||||
virtual const CBaseHandle& GetRefEHandle() const { return *((CBaseHandle*)0); }
|
||||
|
||||
virtual IClientUnknown* GetIClientUnknown() { return this; }
|
||||
virtual ICollideable* GetCollideable() { return 0; }
|
||||
virtual IClientNetworkable* GetClientNetworkable() { return this; }
|
||||
virtual IClientRenderable* GetClientRenderable() { return 0; }
|
||||
virtual IClientEntity* GetIClientEntity() { return 0; }
|
||||
virtual C_BaseEntity* GetBaseEntity() { return 0; }
|
||||
virtual IClientThinkable* GetClientThinkable() { return 0; }
|
||||
|
||||
|
||||
// IClientNetworkable overrides.
|
||||
public:
|
||||
|
||||
virtual void Release();
|
||||
virtual void NotifyShouldTransmit( ShouldTransmitState_t state );
|
||||
virtual void PreDataUpdate( DataUpdateType_t updateType );
|
||||
virtual void PostDataUpdate( DataUpdateType_t updateType );
|
||||
virtual void OnDataUnchangedInPVS( void ) { }
|
||||
virtual void OnPreDataChanged( DataUpdateType_t updateType );
|
||||
virtual void OnDataChanged( DataUpdateType_t updateType );
|
||||
virtual void SetDormant( bool bDormant );
|
||||
virtual bool IsDormant( void );
|
||||
virtual int entindex( void ) const;
|
||||
virtual void ReceiveMessage( int classID, bf_read &msg );
|
||||
virtual void* GetDataTableBasePtr();
|
||||
virtual void SetDestroyedOnRecreateEntities( void );
|
||||
|
||||
public:
|
||||
|
||||
// Dummy for CNetworkVars.
|
||||
void NetworkStateChanged() {}
|
||||
void NetworkStateChanged( void *pVar ) {}
|
||||
|
||||
virtual bool Init(int entnum, int iSerialNum);
|
||||
|
||||
virtual void Precache( void );
|
||||
|
||||
// For dynamic entities, return true to allow destruction
|
||||
virtual bool ShouldDestroy( void ) { return false; };
|
||||
|
||||
C_BaseTempEntity *GetNext( void );
|
||||
|
||||
// Get list of tempentities
|
||||
static C_BaseTempEntity *GetList( void );
|
||||
|
||||
C_BaseTempEntity *GetNextDynamic( void );
|
||||
|
||||
// Determine the color modulation amount
|
||||
void GetColorModulation( float* color )
|
||||
{
|
||||
assert(color);
|
||||
color[0] = color[1] = color[2] = 1.0f;
|
||||
}
|
||||
|
||||
// Should this object be able to have shadows cast onto it?
|
||||
virtual bool ShouldReceiveProjectedTextures( int flags ) { return false; }
|
||||
|
||||
// Static members
|
||||
public:
|
||||
// List of dynamically allocated temp entis
|
||||
static C_BaseTempEntity *GetDynamicList();
|
||||
|
||||
// Called at startup to allow temp entities to precache any models/sounds that they need
|
||||
static void PrecacheTempEnts( void );
|
||||
|
||||
static void ClearDynamicTempEnts( void );
|
||||
|
||||
static void CheckDynamicTempEnts( void );
|
||||
|
||||
private:
|
||||
|
||||
// Next in chain
|
||||
C_BaseTempEntity *m_pNext;
|
||||
C_BaseTempEntity *m_pNextDynamic;
|
||||
|
||||
// TEs add themselves to this list for the executable.
|
||||
static C_BaseTempEntity *s_pTempEntities;
|
||||
static C_BaseTempEntity *s_pDynamicEntities;
|
||||
};
|
||||
|
||||
|
||||
#endif // C_BASETEMPENTITY_H
|
||||
@@ -0,0 +1,511 @@
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose: Client side view model implementation. Responsible for drawing
|
||||
// the view model.
|
||||
//
|
||||
// $NoKeywords: $
|
||||
//=============================================================================//
|
||||
#include "cbase.h"
|
||||
#include "c_baseviewmodel.h"
|
||||
#include "model_types.h"
|
||||
#include "hud.h"
|
||||
#include "view_shared.h"
|
||||
#include "iviewrender.h"
|
||||
#include "view.h"
|
||||
#include "mathlib/vmatrix.h"
|
||||
#include "cl_animevent.h"
|
||||
#include "eventlist.h"
|
||||
#include "tools/bonelist.h"
|
||||
#include <KeyValues.h>
|
||||
#include "hltvcamera.h"
|
||||
#ifdef TF_CLIENT_DLL
|
||||
#include "tf_weaponbase.h"
|
||||
#endif
|
||||
|
||||
#if defined( REPLAY_ENABLED )
|
||||
#include "replay/replaycamera.h"
|
||||
#include "replay/ireplaysystem.h"
|
||||
#include "replay/ienginereplay.h"
|
||||
#endif
|
||||
|
||||
// NVNT haptics system interface
|
||||
#include "haptics/ihaptics.h"
|
||||
|
||||
|
||||
// memdbgon must be the last include file in a .cpp file!!!
|
||||
#include "tier0/memdbgon.h"
|
||||
|
||||
#ifdef CSTRIKE_DLL
|
||||
ConVar cl_righthand( "cl_righthand", "1", FCVAR_ARCHIVE, "Use right-handed view models." );
|
||||
#endif
|
||||
|
||||
#ifdef TF_CLIENT_DLL
|
||||
ConVar cl_flipviewmodels( "cl_flipviewmodels", "0", FCVAR_USERINFO | FCVAR_ARCHIVE | FCVAR_NOT_CONNECTED, "Flip view models." );
|
||||
#endif
|
||||
|
||||
void PostToolMessage( HTOOLHANDLE hEntity, KeyValues *msg );
|
||||
|
||||
void FormatViewModelAttachment( Vector &vOrigin, bool bInverse )
|
||||
{
|
||||
// Presumably, SetUpView has been called so we know our FOV and render origin.
|
||||
const CViewSetup *pViewSetup = view->GetPlayerViewSetup();
|
||||
|
||||
float worldx = tan( pViewSetup->fov * M_PI/360.0 );
|
||||
float viewx = tan( pViewSetup->fovViewmodel * M_PI/360.0 );
|
||||
|
||||
// aspect ratio cancels out, so only need one factor
|
||||
// the difference between the screen coordinates of the 2 systems is the ratio
|
||||
// of the coefficients of the projection matrices (tan (fov/2) is that coefficient)
|
||||
// NOTE: viewx was coming in as 0 when folks set their viewmodel_fov to 0 and show their weapon.
|
||||
float factorX = viewx ? ( worldx / viewx ) : 0.0f;
|
||||
float factorY = factorX;
|
||||
|
||||
// Get the coordinates in the viewer's space.
|
||||
Vector tmp = vOrigin - pViewSetup->origin;
|
||||
Vector vTransformed( MainViewRight().Dot( tmp ), MainViewUp().Dot( tmp ), MainViewForward().Dot( tmp ) );
|
||||
|
||||
// Now squash X and Y.
|
||||
if ( bInverse )
|
||||
{
|
||||
if ( factorX != 0 && factorY != 0 )
|
||||
{
|
||||
vTransformed.x /= factorX;
|
||||
vTransformed.y /= factorY;
|
||||
}
|
||||
else
|
||||
{
|
||||
vTransformed.x = 0.0f;
|
||||
vTransformed.y = 0.0f;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
vTransformed.x *= factorX;
|
||||
vTransformed.y *= factorY;
|
||||
}
|
||||
|
||||
|
||||
|
||||
// Transform back to world space.
|
||||
Vector vOut = (MainViewRight() * vTransformed.x) + (MainViewUp() * vTransformed.y) + (MainViewForward() * vTransformed.z);
|
||||
vOrigin = pViewSetup->origin + vOut;
|
||||
}
|
||||
|
||||
|
||||
void C_BaseViewModel::FormatViewModelAttachment( int nAttachment, matrix3x4_t &attachmentToWorld )
|
||||
{
|
||||
Vector vecOrigin;
|
||||
MatrixPosition( attachmentToWorld, vecOrigin );
|
||||
::FormatViewModelAttachment( vecOrigin, false );
|
||||
PositionMatrix( vecOrigin, attachmentToWorld );
|
||||
}
|
||||
|
||||
|
||||
bool C_BaseViewModel::IsViewModel() const
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
void C_BaseViewModel::UncorrectViewModelAttachment( Vector &vOrigin )
|
||||
{
|
||||
// Unformat the attachment.
|
||||
::FormatViewModelAttachment( vOrigin, true );
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose
|
||||
//-----------------------------------------------------------------------------
|
||||
void C_BaseViewModel::FireEvent( const Vector& origin, const QAngle& angles, int event, const char *options )
|
||||
{
|
||||
// We override sound requests so that we can play them locally on the owning player
|
||||
if ( ( event == AE_CL_PLAYSOUND ) || ( event == CL_EVENT_SOUND ) )
|
||||
{
|
||||
// Only do this if we're owned by someone
|
||||
if ( GetOwner() != NULL )
|
||||
{
|
||||
CLocalPlayerFilter filter;
|
||||
EmitSound( filter, GetOwner()->GetSoundSourceIndex(), options, &GetAbsOrigin() );
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Otherwise pass the event to our associated weapon
|
||||
C_BaseCombatWeapon *pWeapon = GetActiveWeapon();
|
||||
if ( pWeapon )
|
||||
{
|
||||
// NVNT notify the haptics system of our viewmodel's event
|
||||
if ( haptics )
|
||||
haptics->ProcessHapticEvent(4,"Weapons",pWeapon->GetName(),"AnimationEvents",VarArgs("%i",event));
|
||||
|
||||
bool bResult = pWeapon->OnFireEvent( this, origin, angles, event, options );
|
||||
if ( !bResult )
|
||||
{
|
||||
BaseClass::FireEvent( origin, angles, event, options );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool C_BaseViewModel::Interpolate( float currentTime )
|
||||
{
|
||||
CStudioHdr *pStudioHdr = GetModelPtr();
|
||||
// Make sure we reset our animation information if we've switch sequences
|
||||
UpdateAnimationParity();
|
||||
|
||||
bool bret = BaseClass::Interpolate( currentTime );
|
||||
|
||||
// Hack to extrapolate cycle counter for view model
|
||||
float elapsed_time = currentTime - m_flAnimTime;
|
||||
C_BasePlayer *pPlayer = C_BasePlayer::GetLocalPlayer();
|
||||
|
||||
// Predicted viewmodels have fixed up interval
|
||||
if ( GetPredictable() || IsClientCreated() )
|
||||
{
|
||||
Assert( pPlayer );
|
||||
float curtime = pPlayer ? pPlayer->GetFinalPredictedTime() : gpGlobals->curtime;
|
||||
elapsed_time = curtime - m_flAnimTime;
|
||||
// Adjust for interpolated partial frame
|
||||
if ( !engine->IsPaused() )
|
||||
{
|
||||
elapsed_time += ( gpGlobals->interpolation_amount * TICK_INTERVAL );
|
||||
}
|
||||
}
|
||||
|
||||
// Prediction errors?
|
||||
if ( elapsed_time < 0 )
|
||||
{
|
||||
elapsed_time = 0;
|
||||
}
|
||||
|
||||
float dt = elapsed_time * GetSequenceCycleRate( pStudioHdr, GetSequence() ) * GetPlaybackRate();
|
||||
if ( dt >= 1.0f )
|
||||
{
|
||||
if ( !IsSequenceLooping( GetSequence() ) )
|
||||
{
|
||||
dt = 0.999f;
|
||||
}
|
||||
else
|
||||
{
|
||||
dt = fmod( dt, 1.0f );
|
||||
}
|
||||
}
|
||||
|
||||
SetCycle( dt );
|
||||
return bret;
|
||||
}
|
||||
|
||||
|
||||
bool C_BaseViewModel::ShouldFlipViewModel()
|
||||
{
|
||||
#ifdef CSTRIKE_DLL
|
||||
// If cl_righthand is set, then we want them all right-handed.
|
||||
CBaseCombatWeapon *pWeapon = m_hWeapon.Get();
|
||||
if ( pWeapon )
|
||||
{
|
||||
const FileWeaponInfo_t *pInfo = &pWeapon->GetWpnData();
|
||||
return pInfo->m_bAllowFlipping && pInfo->m_bBuiltRightHanded != cl_righthand.GetBool();
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef TF_CLIENT_DLL
|
||||
CBaseCombatWeapon *pWeapon = m_hWeapon.Get();
|
||||
if ( pWeapon )
|
||||
{
|
||||
return pWeapon->m_bFlipViewModel != cl_flipviewmodels.GetBool();
|
||||
}
|
||||
#endif
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
void C_BaseViewModel::ApplyBoneMatrixTransform( matrix3x4_t& transform )
|
||||
{
|
||||
if ( ShouldFlipViewModel() )
|
||||
{
|
||||
matrix3x4_t viewMatrix, viewMatrixInverse;
|
||||
|
||||
// We could get MATERIAL_VIEW here, but this is called sometimes before the renderer
|
||||
// has set that matrix. Luckily, this is called AFTER the CViewSetup has been initialized.
|
||||
const CViewSetup *pSetup = view->GetPlayerViewSetup();
|
||||
AngleMatrix( pSetup->angles, pSetup->origin, viewMatrixInverse );
|
||||
MatrixInvert( viewMatrixInverse, viewMatrix );
|
||||
|
||||
// Transform into view space.
|
||||
matrix3x4_t temp, temp2;
|
||||
ConcatTransforms( viewMatrix, transform, temp );
|
||||
|
||||
// Flip it along X.
|
||||
|
||||
// (This is the slower way to do it, and it equates to negating the top row).
|
||||
//matrix3x4_t mScale;
|
||||
//SetIdentityMatrix( mScale );
|
||||
//mScale[0][0] = 1;
|
||||
//mScale[1][1] = -1;
|
||||
//mScale[2][2] = 1;
|
||||
//ConcatTransforms( mScale, temp, temp2 );
|
||||
temp[1][0] = -temp[1][0];
|
||||
temp[1][1] = -temp[1][1];
|
||||
temp[1][2] = -temp[1][2];
|
||||
temp[1][3] = -temp[1][3];
|
||||
|
||||
// Transform back out of view space.
|
||||
ConcatTransforms( viewMatrixInverse, temp, transform );
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: check if weapon viewmodel should be drawn
|
||||
//-----------------------------------------------------------------------------
|
||||
bool C_BaseViewModel::ShouldDraw()
|
||||
{
|
||||
if ( engine->IsHLTV() )
|
||||
{
|
||||
return ( HLTVCamera()->GetMode() == OBS_MODE_IN_EYE &&
|
||||
HLTVCamera()->GetPrimaryTarget() == GetOwner() );
|
||||
}
|
||||
#if defined( REPLAY_ENABLED )
|
||||
else if ( g_pEngineClientReplay->IsPlayingReplayDemo() )
|
||||
{
|
||||
return ( ReplayCamera()->GetMode() == OBS_MODE_IN_EYE &&
|
||||
ReplayCamera()->GetPrimaryTarget() == GetOwner() );
|
||||
}
|
||||
#endif
|
||||
else
|
||||
{
|
||||
return BaseClass::ShouldDraw();
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Render the weapon. Draw the Viewmodel if the weapon's being carried
|
||||
// by this player, otherwise draw the worldmodel.
|
||||
//-----------------------------------------------------------------------------
|
||||
int C_BaseViewModel::DrawModel( int flags )
|
||||
{
|
||||
if ( !m_bReadyToDraw )
|
||||
return 0;
|
||||
|
||||
if ( flags & STUDIO_RENDER )
|
||||
{
|
||||
// Determine blending amount and tell engine
|
||||
float blend = (float)( GetFxBlend() / 255.0f );
|
||||
|
||||
// Totally gone
|
||||
if ( blend <= 0.0f )
|
||||
return 0;
|
||||
|
||||
// Tell engine
|
||||
render->SetBlend( blend );
|
||||
|
||||
float color[3];
|
||||
GetColorModulation( color );
|
||||
render->SetColorModulation( color );
|
||||
}
|
||||
|
||||
C_BasePlayer *pPlayer = C_BasePlayer::GetLocalPlayer();
|
||||
C_BaseCombatWeapon *pWeapon = GetOwningWeapon();
|
||||
int ret;
|
||||
// If the local player's overriding the viewmodel rendering, let him do it
|
||||
if ( pPlayer && pPlayer->IsOverridingViewmodel() )
|
||||
{
|
||||
ret = pPlayer->DrawOverriddenViewmodel( this, flags );
|
||||
}
|
||||
else if ( pWeapon && pWeapon->IsOverridingViewmodel() )
|
||||
{
|
||||
ret = pWeapon->DrawOverriddenViewmodel( this, flags );
|
||||
}
|
||||
else
|
||||
{
|
||||
ret = BaseClass::DrawModel( flags );
|
||||
}
|
||||
|
||||
// Now that we've rendered, reset the animation restart flag
|
||||
if ( flags & STUDIO_RENDER )
|
||||
{
|
||||
if ( m_nOldAnimationParity != m_nAnimationParity )
|
||||
{
|
||||
m_nOldAnimationParity = m_nAnimationParity;
|
||||
}
|
||||
// Tell the weapon itself that we've rendered, in case it wants to do something
|
||||
if ( pWeapon )
|
||||
{
|
||||
pWeapon->ViewModelDrawn( this );
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef TF_CLIENT_DLL
|
||||
CTFWeaponBase* pTFWeapon = dynamic_cast<CTFWeaponBase*>( pWeapon );
|
||||
if ( ( flags & STUDIO_RENDER ) && pTFWeapon && pTFWeapon->m_viewmodelStatTrakAddon )
|
||||
{
|
||||
pTFWeapon->m_viewmodelStatTrakAddon->RemoveEffects( EF_NODRAW );
|
||||
pTFWeapon->m_viewmodelStatTrakAddon->DrawModel( flags );
|
||||
pTFWeapon->m_viewmodelStatTrakAddon->AddEffects( EF_NODRAW );
|
||||
}
|
||||
#endif
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
int C_BaseViewModel::InternalDrawModel( int flags )
|
||||
{
|
||||
CMatRenderContextPtr pRenderContext( materials );
|
||||
if ( ShouldFlipViewModel() )
|
||||
pRenderContext->CullMode( MATERIAL_CULLMODE_CW );
|
||||
|
||||
int ret = BaseClass::InternalDrawModel( flags );
|
||||
|
||||
pRenderContext->CullMode( MATERIAL_CULLMODE_CCW );
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Called by the player when the player's overriding the viewmodel drawing. Avoids infinite recursion.
|
||||
//-----------------------------------------------------------------------------
|
||||
int C_BaseViewModel::DrawOverriddenViewmodel( int flags )
|
||||
{
|
||||
return BaseClass::DrawModel( flags );
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
// Output : int
|
||||
//-----------------------------------------------------------------------------
|
||||
int C_BaseViewModel::GetFxBlend( void )
|
||||
{
|
||||
// See if the local player wants to override the viewmodel's rendering
|
||||
C_BasePlayer *pPlayer = C_BasePlayer::GetLocalPlayer();
|
||||
if ( pPlayer && pPlayer->IsOverridingViewmodel() )
|
||||
{
|
||||
pPlayer->ComputeFxBlend();
|
||||
return pPlayer->GetFxBlend();
|
||||
}
|
||||
|
||||
C_BaseCombatWeapon *pWeapon = GetOwningWeapon();
|
||||
if ( pWeapon && pWeapon->IsOverridingViewmodel() )
|
||||
{
|
||||
pWeapon->ComputeFxBlend();
|
||||
return pWeapon->GetFxBlend();
|
||||
}
|
||||
|
||||
return BaseClass::GetFxBlend();
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
// Output : Returns true on success, false on failure.
|
||||
//-----------------------------------------------------------------------------
|
||||
bool C_BaseViewModel::IsTransparent( void )
|
||||
{
|
||||
// See if the local player wants to override the viewmodel's rendering
|
||||
C_BasePlayer *pPlayer = C_BasePlayer::GetLocalPlayer();
|
||||
if ( pPlayer && pPlayer->IsOverridingViewmodel() )
|
||||
{
|
||||
return pPlayer->ViewModel_IsTransparent();
|
||||
}
|
||||
|
||||
C_BaseCombatWeapon *pWeapon = GetOwningWeapon();
|
||||
if ( pWeapon && pWeapon->IsOverridingViewmodel() )
|
||||
return pWeapon->ViewModel_IsTransparent();
|
||||
|
||||
return BaseClass::IsTransparent();
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
bool C_BaseViewModel::UsesPowerOfTwoFrameBufferTexture( void )
|
||||
{
|
||||
// See if the local player wants to override the viewmodel's rendering
|
||||
C_BasePlayer *pPlayer = C_BasePlayer::GetLocalPlayer();
|
||||
if ( pPlayer && pPlayer->IsOverridingViewmodel() )
|
||||
{
|
||||
return pPlayer->ViewModel_IsUsingFBTexture();
|
||||
}
|
||||
|
||||
C_BaseCombatWeapon *pWeapon = GetOwningWeapon();
|
||||
if ( pWeapon && pWeapon->IsOverridingViewmodel() )
|
||||
{
|
||||
return pWeapon->ViewModel_IsUsingFBTexture();
|
||||
}
|
||||
|
||||
return BaseClass::UsesPowerOfTwoFrameBufferTexture();
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: If the animation parity of the weapon has changed, we reset cycle to avoid popping
|
||||
//-----------------------------------------------------------------------------
|
||||
void C_BaseViewModel::UpdateAnimationParity( void )
|
||||
{
|
||||
C_BasePlayer *pPlayer = C_BasePlayer::GetLocalPlayer();
|
||||
|
||||
// If we're predicting, then we don't use animation parity because we change the animations on the clientside
|
||||
// while predicting. When not predicting, only the server changes the animations, so a parity mismatch
|
||||
// tells us if we need to reset the animation.
|
||||
if ( m_nOldAnimationParity != m_nAnimationParity && !GetPredictable() )
|
||||
{
|
||||
float curtime = (pPlayer && IsIntermediateDataAllocated()) ? pPlayer->GetFinalPredictedTime() : gpGlobals->curtime;
|
||||
// FIXME: this is bad
|
||||
// Simulate a networked m_flAnimTime and m_flCycle
|
||||
// FIXME: Do we need the magic 0.1?
|
||||
SetCycle( 0.0f ); // GetSequenceCycleRate( GetSequence() ) * 0.1;
|
||||
m_flAnimTime = curtime;
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Update global map state based on data received
|
||||
// Input : bnewentity -
|
||||
//-----------------------------------------------------------------------------
|
||||
void C_BaseViewModel::OnDataChanged( DataUpdateType_t updateType )
|
||||
{
|
||||
SetPredictionEligible( true );
|
||||
BaseClass::OnDataChanged(updateType);
|
||||
}
|
||||
|
||||
void C_BaseViewModel::PostDataUpdate( DataUpdateType_t updateType )
|
||||
{
|
||||
BaseClass::PostDataUpdate(updateType);
|
||||
OnLatchInterpolatedVariables( LATCH_ANIMATION_VAR );
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Add entity to visible view models list
|
||||
//-----------------------------------------------------------------------------
|
||||
void C_BaseViewModel::AddEntity( void )
|
||||
{
|
||||
// Server says don't interpolate this frame, so set previous info to new info.
|
||||
if ( IsNoInterpolationFrame() )
|
||||
{
|
||||
ResetLatched();
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
void C_BaseViewModel::GetBoneControllers(float controllers[MAXSTUDIOBONECTRLS])
|
||||
{
|
||||
BaseClass::GetBoneControllers( controllers );
|
||||
|
||||
// Tell the weapon itself that we've rendered, in case it wants to do something
|
||||
C_BaseCombatWeapon *pWeapon = GetActiveWeapon();
|
||||
if ( pWeapon )
|
||||
{
|
||||
pWeapon->GetViewmodelBoneControllers( this, controllers );
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
// Output : RenderGroup_t
|
||||
//-----------------------------------------------------------------------------
|
||||
RenderGroup_t C_BaseViewModel::GetRenderGroup()
|
||||
{
|
||||
return RENDER_GROUP_VIEW_MODEL_OPAQUE;
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose: Client side view model implementation. Responsible for drawing
|
||||
// the view model.
|
||||
//
|
||||
// $NoKeywords: $
|
||||
//=============================================================================//
|
||||
|
||||
#ifndef C_BASEVIEWMODEL_H
|
||||
#define C_BASEVIEWMODEL_H
|
||||
#ifdef _WIN32
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
#include "c_baseanimating.h"
|
||||
#include "utlvector.h"
|
||||
#include "baseviewmodel_shared.h"
|
||||
|
||||
#endif // C_BASEVIEWMODEL_H
|
||||
@@ -0,0 +1,46 @@
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
//=============================================================================//
|
||||
#include "cbase.h"
|
||||
#include "model_types.h"
|
||||
#include "vcollide.h"
|
||||
#include "vcollide_parse.h"
|
||||
#include "solidsetdefaults.h"
|
||||
#include "bone_setup.h"
|
||||
#include "engine/ivmodelinfo.h"
|
||||
#include "physics.h"
|
||||
#include "c_breakableprop.h"
|
||||
#include "view.h"
|
||||
|
||||
// memdbgon must be the last include file in a .cpp file!!!
|
||||
#include "tier0/memdbgon.h"
|
||||
|
||||
IMPLEMENT_CLIENTCLASS_DT(C_BreakableProp, DT_BreakableProp, CBreakableProp)
|
||||
END_RECV_TABLE()
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
C_BreakableProp::C_BreakableProp( void )
|
||||
{
|
||||
m_takedamage = DAMAGE_YES;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
void C_BreakableProp::SetFadeMinMax( float fademin, float fademax )
|
||||
{
|
||||
m_fadeMinDist = fademin;
|
||||
m_fadeMaxDist = fademax;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Copy fade from another breakable prop
|
||||
//-----------------------------------------------------------------------------
|
||||
void C_BreakableProp::CopyFadeFrom( C_BreakableProp *pSource )
|
||||
{
|
||||
m_flFadeScale = pSource->m_flFadeScale;
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
//=============================================================================//
|
||||
|
||||
#ifndef C_BREAKABLEPROP_H
|
||||
#define C_BREAKABLEPROP_H
|
||||
#ifdef _WIN32
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
class C_BreakableProp : public C_BaseAnimating
|
||||
{
|
||||
typedef C_BaseAnimating BaseClass;
|
||||
public:
|
||||
DECLARE_CLIENTCLASS();
|
||||
|
||||
C_BreakableProp();
|
||||
|
||||
virtual void SetFadeMinMax( float fademin, float fademax );
|
||||
|
||||
// Copy fade from another breakable prop
|
||||
void CopyFadeFrom( C_BreakableProp *pSource );
|
||||
};
|
||||
|
||||
#endif // C_BREAKABLEPROP_H
|
||||
@@ -0,0 +1,156 @@
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose: Color correction entity with simple radial falloff
|
||||
//
|
||||
// $NoKeywords: $
|
||||
//===========================================================================//
|
||||
#include "cbase.h"
|
||||
|
||||
#include "filesystem.h"
|
||||
#include "cdll_client_int.h"
|
||||
#include "colorcorrectionmgr.h"
|
||||
#include "materialsystem/MaterialSystemUtil.h"
|
||||
|
||||
// memdbgon must be the last include file in a .cpp file!!!
|
||||
#include "tier0/memdbgon.h"
|
||||
|
||||
|
||||
static ConVar mat_colcorrection_disableentities( "mat_colcorrection_disableentities", "0", FCVAR_NONE, "Disable map color-correction entities" );
|
||||
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Purpose : Color correction entity with radial falloff
|
||||
//------------------------------------------------------------------------------
|
||||
class C_ColorCorrection : public C_BaseEntity
|
||||
{
|
||||
public:
|
||||
DECLARE_CLASS( C_ColorCorrection, C_BaseEntity );
|
||||
|
||||
DECLARE_CLIENTCLASS();
|
||||
|
||||
C_ColorCorrection();
|
||||
virtual ~C_ColorCorrection();
|
||||
|
||||
void OnDataChanged(DataUpdateType_t updateType);
|
||||
bool ShouldDraw();
|
||||
|
||||
void ClientThink();
|
||||
|
||||
private:
|
||||
Vector m_vecOrigin;
|
||||
|
||||
float m_minFalloff;
|
||||
float m_maxFalloff;
|
||||
float m_flCurWeight;
|
||||
char m_netLookupFilename[MAX_PATH];
|
||||
|
||||
bool m_bEnabled;
|
||||
|
||||
ClientCCHandle_t m_CCHandle;
|
||||
};
|
||||
|
||||
IMPLEMENT_CLIENTCLASS_DT(C_ColorCorrection, DT_ColorCorrection, CColorCorrection)
|
||||
RecvPropVector( RECVINFO(m_vecOrigin) ),
|
||||
RecvPropFloat( RECVINFO(m_minFalloff) ),
|
||||
RecvPropFloat( RECVINFO(m_maxFalloff) ),
|
||||
RecvPropFloat( RECVINFO(m_flCurWeight) ),
|
||||
RecvPropString( RECVINFO(m_netLookupFilename) ),
|
||||
RecvPropBool( RECVINFO(m_bEnabled) ),
|
||||
|
||||
END_RECV_TABLE()
|
||||
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Constructor, destructor
|
||||
//------------------------------------------------------------------------------
|
||||
C_ColorCorrection::C_ColorCorrection()
|
||||
{
|
||||
m_CCHandle = INVALID_CLIENT_CCHANDLE;
|
||||
}
|
||||
|
||||
C_ColorCorrection::~C_ColorCorrection()
|
||||
{
|
||||
g_pColorCorrectionMgr->RemoveColorCorrection( m_CCHandle );
|
||||
}
|
||||
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Purpose :
|
||||
// Input :
|
||||
// Output :
|
||||
//------------------------------------------------------------------------------
|
||||
void C_ColorCorrection::OnDataChanged(DataUpdateType_t updateType)
|
||||
{
|
||||
BaseClass::OnDataChanged( updateType );
|
||||
|
||||
if ( updateType == DATA_UPDATE_CREATED )
|
||||
{
|
||||
if ( m_CCHandle == INVALID_CLIENT_CCHANDLE )
|
||||
{
|
||||
char filename[MAX_PATH];
|
||||
Q_strncpy( filename, m_netLookupFilename, MAX_PATH );
|
||||
|
||||
m_CCHandle = g_pColorCorrectionMgr->AddColorCorrection( filename );
|
||||
SetNextClientThink( ( m_CCHandle != INVALID_CLIENT_CCHANDLE ) ? CLIENT_THINK_ALWAYS : CLIENT_THINK_NEVER );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// We don't draw...
|
||||
//------------------------------------------------------------------------------
|
||||
bool C_ColorCorrection::ShouldDraw()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
void C_ColorCorrection::ClientThink()
|
||||
{
|
||||
if ( m_CCHandle == INVALID_CLIENT_CCHANDLE )
|
||||
return;
|
||||
|
||||
if ( mat_colcorrection_disableentities.GetInt() )
|
||||
{
|
||||
// Allow the colorcorrectionui panel (or user) to turn off color-correction entities
|
||||
g_pColorCorrectionMgr->SetColorCorrectionWeight( m_CCHandle, 0.0f );
|
||||
return;
|
||||
}
|
||||
|
||||
if( !m_bEnabled && m_flCurWeight == 0.0f )
|
||||
{
|
||||
g_pColorCorrectionMgr->SetColorCorrectionWeight( m_CCHandle, 0.0f );
|
||||
return;
|
||||
}
|
||||
|
||||
C_BaseEntity *pPlayer = C_BasePlayer::GetLocalPlayer();
|
||||
if( !pPlayer )
|
||||
return;
|
||||
|
||||
Vector playerOrigin = pPlayer->GetAbsOrigin();
|
||||
|
||||
float weight = 0;
|
||||
if ( ( m_minFalloff != -1 ) && ( m_maxFalloff != -1 ) && m_minFalloff != m_maxFalloff )
|
||||
{
|
||||
float dist = (playerOrigin - m_vecOrigin).Length();
|
||||
weight = (dist-m_minFalloff) / (m_maxFalloff-m_minFalloff);
|
||||
if ( weight<0.0f ) weight = 0.0f;
|
||||
if ( weight>1.0f ) weight = 1.0f;
|
||||
}
|
||||
|
||||
g_pColorCorrectionMgr->SetColorCorrectionWeight( m_CCHandle, m_flCurWeight * ( 1.0 - weight ) );
|
||||
|
||||
BaseClass::ClientThink();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,119 @@
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose: Color correction entity.
|
||||
//
|
||||
// $NoKeywords: $
|
||||
//===========================================================================//
|
||||
#include "cbase.h"
|
||||
|
||||
#include "filesystem.h"
|
||||
#include "cdll_client_int.h"
|
||||
#include "materialsystem/MaterialSystemUtil.h"
|
||||
#include "colorcorrectionmgr.h"
|
||||
|
||||
// memdbgon must be the last include file in a .cpp file!!!
|
||||
#include "tier0/memdbgon.h"
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// FIXME: This really should inherit from something more lightweight
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Purpose : Shadow control entity
|
||||
//------------------------------------------------------------------------------
|
||||
class C_ColorCorrectionVolume : public C_BaseEntity
|
||||
{
|
||||
public:
|
||||
DECLARE_CLASS( C_ColorCorrectionVolume, C_BaseEntity );
|
||||
|
||||
DECLARE_CLIENTCLASS();
|
||||
DECLARE_PREDICTABLE();
|
||||
|
||||
C_ColorCorrectionVolume();
|
||||
virtual ~C_ColorCorrectionVolume();
|
||||
|
||||
void OnDataChanged(DataUpdateType_t updateType);
|
||||
bool ShouldDraw();
|
||||
|
||||
void ClientThink();
|
||||
|
||||
private:
|
||||
float m_Weight;
|
||||
char m_lookupFilename[MAX_PATH];
|
||||
|
||||
ClientCCHandle_t m_CCHandle;
|
||||
};
|
||||
|
||||
IMPLEMENT_CLIENTCLASS_DT(C_ColorCorrectionVolume, DT_ColorCorrectionVolume, CColorCorrectionVolume)
|
||||
RecvPropFloat( RECVINFO(m_Weight) ),
|
||||
RecvPropString( RECVINFO(m_lookupFilename) ),
|
||||
END_RECV_TABLE()
|
||||
|
||||
BEGIN_PREDICTION_DATA( C_ColorCorrectionVolume )
|
||||
DEFINE_PRED_FIELD( m_Weight, FIELD_FLOAT, FTYPEDESC_INSENDTABLE ),
|
||||
END_PREDICTION_DATA()
|
||||
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Constructor, destructor
|
||||
//------------------------------------------------------------------------------
|
||||
C_ColorCorrectionVolume::C_ColorCorrectionVolume()
|
||||
{
|
||||
m_CCHandle = INVALID_CLIENT_CCHANDLE;
|
||||
}
|
||||
|
||||
C_ColorCorrectionVolume::~C_ColorCorrectionVolume()
|
||||
{
|
||||
g_pColorCorrectionMgr->RemoveColorCorrection( m_CCHandle );
|
||||
}
|
||||
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Purpose :
|
||||
// Input :
|
||||
// Output :
|
||||
//------------------------------------------------------------------------------
|
||||
void C_ColorCorrectionVolume::OnDataChanged(DataUpdateType_t updateType)
|
||||
{
|
||||
BaseClass::OnDataChanged( updateType );
|
||||
|
||||
if ( updateType == DATA_UPDATE_CREATED )
|
||||
{
|
||||
if ( m_CCHandle == INVALID_CLIENT_CCHANDLE )
|
||||
{
|
||||
char filename[MAX_PATH];
|
||||
Q_strncpy( filename, m_lookupFilename, MAX_PATH );
|
||||
|
||||
m_CCHandle = g_pColorCorrectionMgr->AddColorCorrection( filename );
|
||||
SetNextClientThink( ( m_CCHandle != INVALID_CLIENT_CCHANDLE ) ? CLIENT_THINK_ALWAYS : CLIENT_THINK_NEVER );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// We don't draw...
|
||||
//------------------------------------------------------------------------------
|
||||
bool C_ColorCorrectionVolume::ShouldDraw()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
void C_ColorCorrectionVolume::ClientThink()
|
||||
{
|
||||
Vector entityPosition = GetAbsOrigin();
|
||||
g_pColorCorrectionMgr->SetColorCorrectionWeight( m_CCHandle, m_Weight );
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,237 @@
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose: Dynamic light
|
||||
//
|
||||
// $Workfile: $
|
||||
// $Date: $
|
||||
// $NoKeywords: $
|
||||
//=============================================================================//
|
||||
#include "cbase.h"
|
||||
#include "dlight.h"
|
||||
#include "iefx.h"
|
||||
#include "iviewrender.h"
|
||||
|
||||
// memdbgon must be the last include file in a .cpp file!!!
|
||||
#include "tier0/memdbgon.h"
|
||||
|
||||
|
||||
#if HL2_EPISODIC
|
||||
// In Episodic we unify the NO_WORLD_ILLUMINATION lights to use
|
||||
// the more efficient elight structure instead. This should theoretically
|
||||
// be extended to other projects but may have unintended consequences
|
||||
// and bears more thorough testing.
|
||||
//
|
||||
// For an earlier iteration on this technique see changelist 214433,
|
||||
// which had a specific flag for use of elights.
|
||||
#define DLIGHT_NO_WORLD_USES_ELIGHT 1
|
||||
#endif
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// A dynamic light, with the goofy hack needed for spotlights
|
||||
//-----------------------------------------------------------------------------
|
||||
class C_DynamicLight : public C_BaseEntity
|
||||
{
|
||||
public:
|
||||
DECLARE_CLASS( C_DynamicLight, C_BaseEntity );
|
||||
DECLARE_CLIENTCLASS();
|
||||
|
||||
C_DynamicLight();
|
||||
|
||||
public:
|
||||
void OnDataChanged(DataUpdateType_t updateType);
|
||||
bool ShouldDraw();
|
||||
void ClientThink( void );
|
||||
void Release( void );
|
||||
|
||||
unsigned char m_Flags;
|
||||
unsigned char m_LightStyle;
|
||||
|
||||
float m_Radius;
|
||||
int m_Exponent;
|
||||
float m_InnerAngle;
|
||||
float m_OuterAngle;
|
||||
float m_SpotRadius;
|
||||
|
||||
private:
|
||||
dlight_t* m_pDynamicLight;
|
||||
dlight_t* m_pSpotlightEnd;
|
||||
|
||||
|
||||
inline bool ShouldBeElight() { return (m_Flags & DLIGHT_NO_WORLD_ILLUMINATION); }
|
||||
};
|
||||
|
||||
IMPLEMENT_CLIENTCLASS_DT(C_DynamicLight, DT_DynamicLight, CDynamicLight)
|
||||
RecvPropInt (RECVINFO(m_Flags)),
|
||||
RecvPropInt (RECVINFO(m_LightStyle)),
|
||||
RecvPropFloat (RECVINFO(m_Radius)),
|
||||
RecvPropInt (RECVINFO(m_Exponent)),
|
||||
RecvPropFloat (RECVINFO(m_InnerAngle)),
|
||||
RecvPropFloat (RECVINFO(m_OuterAngle)),
|
||||
RecvPropFloat (RECVINFO(m_SpotRadius)),
|
||||
END_RECV_TABLE()
|
||||
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Purpose :
|
||||
//------------------------------------------------------------------------------
|
||||
C_DynamicLight::C_DynamicLight(void) : m_pSpotlightEnd(0), m_pDynamicLight(0)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Purpose :
|
||||
//------------------------------------------------------------------------------
|
||||
void C_DynamicLight::OnDataChanged(DataUpdateType_t updateType)
|
||||
{
|
||||
if ( updateType == DATA_UPDATE_CREATED )
|
||||
{
|
||||
SetNextClientThink(gpGlobals->curtime + 0.05);
|
||||
}
|
||||
|
||||
BaseClass::OnDataChanged( updateType );
|
||||
}
|
||||
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Purpose :
|
||||
//------------------------------------------------------------------------------
|
||||
bool C_DynamicLight::ShouldDraw()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Purpose : Disable drawing of this light when entity perishes
|
||||
//------------------------------------------------------------------------------
|
||||
void C_DynamicLight::Release()
|
||||
{
|
||||
if (m_pDynamicLight)
|
||||
{
|
||||
m_pDynamicLight->die = gpGlobals->curtime;
|
||||
m_pDynamicLight = 0;
|
||||
}
|
||||
|
||||
if (m_pSpotlightEnd)
|
||||
{
|
||||
m_pSpotlightEnd->die = gpGlobals->curtime;
|
||||
m_pSpotlightEnd = 0;
|
||||
}
|
||||
|
||||
BaseClass::Release();
|
||||
}
|
||||
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Purpose :
|
||||
//------------------------------------------------------------------------------
|
||||
void C_DynamicLight::ClientThink(void)
|
||||
{
|
||||
Vector forward;
|
||||
AngleVectors( GetAbsAngles(), &forward );
|
||||
|
||||
if ( (m_Flags & DLIGHT_NO_MODEL_ILLUMINATION) == 0 )
|
||||
{
|
||||
// Deal with the model light
|
||||
if ( !m_pDynamicLight || (m_pDynamicLight->key != index) )
|
||||
{
|
||||
#if DLIGHT_NO_WORLD_USES_ELIGHT
|
||||
m_pDynamicLight = ShouldBeElight() != 0
|
||||
? effects->CL_AllocElight( index )
|
||||
: effects->CL_AllocDlight( index );
|
||||
#else
|
||||
m_pDynamicLight = effects->CL_AllocDlight( index );
|
||||
#endif
|
||||
Assert (m_pDynamicLight);
|
||||
m_pDynamicLight->minlight = 0;
|
||||
}
|
||||
|
||||
m_pDynamicLight->style = m_LightStyle;
|
||||
m_pDynamicLight->radius = m_Radius;
|
||||
m_pDynamicLight->flags = m_Flags;
|
||||
if ( m_OuterAngle > 0 )
|
||||
m_pDynamicLight->flags |= DLIGHT_NO_WORLD_ILLUMINATION;
|
||||
m_pDynamicLight->color.r = m_clrRender->r;
|
||||
m_pDynamicLight->color.g = m_clrRender->g;
|
||||
m_pDynamicLight->color.b = m_clrRender->b;
|
||||
m_pDynamicLight->color.exponent = m_Exponent; // this makes it match the world
|
||||
m_pDynamicLight->origin = GetAbsOrigin();
|
||||
m_pDynamicLight->m_InnerAngle = m_InnerAngle;
|
||||
m_pDynamicLight->m_OuterAngle = m_OuterAngle;
|
||||
m_pDynamicLight->die = gpGlobals->curtime + 1e6;
|
||||
m_pDynamicLight->m_Direction = forward;
|
||||
}
|
||||
else
|
||||
{
|
||||
// In this case, the m_Flags could have changed; which is how we turn the light off
|
||||
if (m_pDynamicLight)
|
||||
{
|
||||
m_pDynamicLight->die = gpGlobals->curtime;
|
||||
m_pDynamicLight = 0;
|
||||
}
|
||||
}
|
||||
|
||||
#if DLIGHT_NO_WORLD_USES_ELIGHT
|
||||
if (( m_OuterAngle > 0 ) && !ShouldBeElight())
|
||||
#else
|
||||
if (( m_OuterAngle > 0 ) && ((m_Flags & DLIGHT_NO_WORLD_ILLUMINATION) == 0))
|
||||
#endif
|
||||
{
|
||||
// Raycast to where the endpoint goes
|
||||
// Deal with the environment light
|
||||
if ( !m_pSpotlightEnd || (m_pSpotlightEnd->key != -index) )
|
||||
{
|
||||
m_pSpotlightEnd = effects->CL_AllocDlight( -index );
|
||||
Assert (m_pSpotlightEnd);
|
||||
}
|
||||
|
||||
// Trace a line outward, don't use hitboxes (too slow)
|
||||
Vector end;
|
||||
VectorMA( GetAbsOrigin(), m_Radius, forward, end );
|
||||
|
||||
trace_t pm;
|
||||
C_BaseEntity::PushEnableAbsRecomputations( false ); // HACK don't recompute positions while doing RayTrace
|
||||
UTIL_TraceLine( GetAbsOrigin(), end, MASK_NPCWORLDSTATIC, NULL, COLLISION_GROUP_NONE, &pm );
|
||||
C_BaseEntity::PopEnableAbsRecomputations();
|
||||
VectorCopy( pm.endpos, m_pSpotlightEnd->origin );
|
||||
|
||||
if (pm.fraction == 1.0f)
|
||||
{
|
||||
m_pSpotlightEnd->die = gpGlobals->curtime;
|
||||
m_pSpotlightEnd = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
float falloff = 1.0 - pm.fraction;
|
||||
falloff *= falloff;
|
||||
|
||||
m_pSpotlightEnd->style = m_LightStyle;
|
||||
m_pSpotlightEnd->flags = DLIGHT_NO_MODEL_ILLUMINATION | (m_Flags & DLIGHT_DISPLACEMENT_MASK);
|
||||
m_pSpotlightEnd->radius = m_SpotRadius; // * falloff;
|
||||
m_pSpotlightEnd->die = gpGlobals->curtime + 1e6;
|
||||
m_pSpotlightEnd->color.r = m_clrRender->r * falloff;
|
||||
m_pSpotlightEnd->color.g = m_clrRender->g * falloff;
|
||||
m_pSpotlightEnd->color.b = m_clrRender->b * falloff;
|
||||
m_pSpotlightEnd->color.exponent = m_Exponent;
|
||||
|
||||
// For bumped lighting
|
||||
m_pSpotlightEnd->m_Direction = forward;
|
||||
|
||||
// Update list of surfaces we influence
|
||||
render->TouchLight( m_pSpotlightEnd );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// In this case, the m_Flags could have changed; which is how we turn the light off
|
||||
if (m_pSpotlightEnd)
|
||||
{
|
||||
m_pSpotlightEnd->die = gpGlobals->curtime;
|
||||
m_pSpotlightEnd = 0;
|
||||
}
|
||||
}
|
||||
|
||||
SetNextClientThink(gpGlobals->curtime + 0.001);
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,18 @@
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
//=============================================================================//
|
||||
|
||||
#ifndef C_EFFECTS_H
|
||||
#define C_EFFECTS_H
|
||||
#ifdef _WIN32
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
|
||||
// Draw rain effects.
|
||||
void DrawPrecipitation();
|
||||
|
||||
|
||||
#endif // C_EFFECTS_H
|
||||
@@ -0,0 +1,794 @@
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
// $NoKeywords: $
|
||||
//=============================================================================//
|
||||
|
||||
#include "cbase.h"
|
||||
|
||||
#include "iviewrender.h"
|
||||
#include "view.h"
|
||||
#include "studio.h"
|
||||
#include "bone_setup.h"
|
||||
#include "model_types.h"
|
||||
#include "beamdraw.h"
|
||||
#include "engine/ivdebugoverlay.h"
|
||||
#include "iviewrender_beams.h"
|
||||
#include "fx.h"
|
||||
#include "IEffects.h"
|
||||
#include "c_entitydissolve.h"
|
||||
#include "movevars_shared.h"
|
||||
#include "clienteffectprecachesystem.h"
|
||||
|
||||
// memdbgon must be the last include file in a .cpp file!!!
|
||||
#include "tier0/memdbgon.h"
|
||||
|
||||
CLIENTEFFECT_REGISTER_BEGIN( PrecacheEffectBuild )
|
||||
CLIENTEFFECT_MATERIAL( "effects/tesla_glow_noz" )
|
||||
CLIENTEFFECT_MATERIAL( "effects/spark" )
|
||||
CLIENTEFFECT_MATERIAL( "effects/combinemuzzle2" )
|
||||
CLIENTEFFECT_REGISTER_END()
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Networking
|
||||
//-----------------------------------------------------------------------------
|
||||
IMPLEMENT_CLIENTCLASS_DT( C_EntityDissolve, DT_EntityDissolve, CEntityDissolve )
|
||||
RecvPropTime(RECVINFO(m_flStartTime)),
|
||||
RecvPropFloat(RECVINFO(m_flFadeOutStart)),
|
||||
RecvPropFloat(RECVINFO(m_flFadeOutLength)),
|
||||
RecvPropFloat(RECVINFO(m_flFadeOutModelStart)),
|
||||
RecvPropFloat(RECVINFO(m_flFadeOutModelLength)),
|
||||
RecvPropFloat(RECVINFO(m_flFadeInStart)),
|
||||
RecvPropFloat(RECVINFO(m_flFadeInLength)),
|
||||
RecvPropInt(RECVINFO(m_nDissolveType)),
|
||||
RecvPropVector( RECVINFO( m_vDissolverOrigin) ),
|
||||
RecvPropInt( RECVINFO( m_nMagnitude ) ),
|
||||
END_RECV_TABLE()
|
||||
|
||||
extern PMaterialHandle g_Material_Spark;
|
||||
PMaterialHandle g_Material_AR2Glow = NULL;
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
C_EntityDissolve::C_EntityDissolve( void )
|
||||
{
|
||||
m_bLinkedToServerEnt = true;
|
||||
m_pController = NULL;
|
||||
m_bCoreExplode = false;
|
||||
m_vEffectColor = Vector( 255, 255, 255 );
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
void C_EntityDissolve::GetRenderBounds( Vector& theMins, Vector& theMaxs )
|
||||
{
|
||||
if ( GetMoveParent() )
|
||||
{
|
||||
GetMoveParent()->GetRenderBounds( theMins, theMaxs );
|
||||
}
|
||||
else
|
||||
{
|
||||
theMins = GetAbsOrigin();
|
||||
theMaxs = theMaxs;
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// On data changed
|
||||
//-----------------------------------------------------------------------------
|
||||
void C_EntityDissolve::OnDataChanged( DataUpdateType_t updateType )
|
||||
{
|
||||
BaseClass::OnDataChanged( updateType );
|
||||
if ( updateType == DATA_UPDATE_CREATED )
|
||||
{
|
||||
m_flNextSparkTime = m_flStartTime;
|
||||
SetNextClientThink( CLIENT_THINK_ALWAYS );
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Cleanup
|
||||
//-----------------------------------------------------------------------------
|
||||
void C_EntityDissolve::UpdateOnRemove( void )
|
||||
{
|
||||
if ( m_pController )
|
||||
{
|
||||
physenv->DestroyMotionController( m_pController );
|
||||
m_pController = NULL;
|
||||
}
|
||||
|
||||
BaseClass::UpdateOnRemove();
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Apply the forces to the entity
|
||||
//------------------------------------------------------------------------------
|
||||
IMotionEvent::simresult_e C_EntityDissolve::Simulate( IPhysicsMotionController *pController, IPhysicsObject *pObject, float deltaTime, Vector &linear, AngularImpulse &angular )
|
||||
{
|
||||
linear.Init();
|
||||
angular.Init();
|
||||
|
||||
// Make it zero g
|
||||
linear.z -= -1.02 * GetCurrentGravity();
|
||||
|
||||
Vector vel;
|
||||
AngularImpulse angVel;
|
||||
pObject->GetVelocity( &vel, &angVel );
|
||||
vel += linear * deltaTime; // account for gravity scale
|
||||
|
||||
Vector unitVel = vel;
|
||||
Vector unitAngVel = angVel;
|
||||
|
||||
float speed = VectorNormalize( unitVel );
|
||||
// float angSpeed = VectorNormalize( unitAngVel );
|
||||
|
||||
// float speedScale = 0.0;
|
||||
// float angSpeedScale = 0.0;
|
||||
|
||||
float flLinearLimit = 50;
|
||||
float flLinearLimitDelta = 40;
|
||||
if ( speed > flLinearLimit )
|
||||
{
|
||||
float flDeltaVel = (flLinearLimit - speed) / deltaTime;
|
||||
if ( flLinearLimitDelta != 0.0f )
|
||||
{
|
||||
float flMaxDeltaVel = -flLinearLimitDelta / deltaTime;
|
||||
if ( flDeltaVel < flMaxDeltaVel )
|
||||
{
|
||||
flDeltaVel = flMaxDeltaVel;
|
||||
}
|
||||
}
|
||||
VectorMA( linear, flDeltaVel, unitVel, linear );
|
||||
}
|
||||
|
||||
return SIM_GLOBAL_ACCELERATION;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Tesla effect
|
||||
//-----------------------------------------------------------------------------
|
||||
static void FX_BuildTesla( C_BaseEntity *pEntity, Vector &vecOrigin, Vector &vecEnd )
|
||||
{
|
||||
BeamInfo_t beamInfo;
|
||||
beamInfo.m_pStartEnt = pEntity;
|
||||
beamInfo.m_nStartAttachment = 0;
|
||||
beamInfo.m_pEndEnt = NULL;
|
||||
beamInfo.m_nEndAttachment = 0;
|
||||
beamInfo.m_nType = TE_BEAMTESLA;
|
||||
beamInfo.m_vecStart = vecOrigin;
|
||||
beamInfo.m_vecEnd = vecEnd;
|
||||
beamInfo.m_pszModelName = "sprites/lgtning.vmt";
|
||||
beamInfo.m_flHaloScale = 0.0;
|
||||
beamInfo.m_flLife = random->RandomFloat( 0.25f, 1.0f );
|
||||
beamInfo.m_flWidth = random->RandomFloat( 8.0f, 14.0f );
|
||||
beamInfo.m_flEndWidth = 1.0f;
|
||||
beamInfo.m_flFadeLength = 0.5f;
|
||||
beamInfo.m_flAmplitude = 24;
|
||||
beamInfo.m_flBrightness = 255.0;
|
||||
beamInfo.m_flSpeed = 150.0f;
|
||||
beamInfo.m_nStartFrame = 0.0;
|
||||
beamInfo.m_flFrameRate = 30.0;
|
||||
beamInfo.m_flRed = 255.0;
|
||||
beamInfo.m_flGreen = 255.0;
|
||||
beamInfo.m_flBlue = 255.0;
|
||||
beamInfo.m_nSegments = 18;
|
||||
beamInfo.m_bRenderable = true;
|
||||
beamInfo.m_nFlags = 0; //FBEAM_ONLYNOISEONCE;
|
||||
|
||||
beams->CreateBeamEntPoint( beamInfo );
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Tesla effect
|
||||
//-----------------------------------------------------------------------------
|
||||
void C_EntityDissolve::BuildTeslaEffect( mstudiobbox_t *pHitBox, const matrix3x4_t &hitboxToWorld, bool bRandom, float flYawOffset )
|
||||
{
|
||||
Vector vecOrigin;
|
||||
QAngle vecAngles;
|
||||
MatrixGetColumn( hitboxToWorld, 3, vecOrigin );
|
||||
MatrixAngles( hitboxToWorld, vecAngles.Base() );
|
||||
C_BaseEntity *pEntity = GetMoveParent();
|
||||
|
||||
// Make a couple of tries at it
|
||||
int iTries = -1;
|
||||
Vector vecForward;
|
||||
trace_t tr;
|
||||
do
|
||||
{
|
||||
iTries++;
|
||||
|
||||
// Some beams are deliberatly aimed around the point, the rest are random.
|
||||
if ( !bRandom )
|
||||
{
|
||||
QAngle vecTemp = vecAngles;
|
||||
vecTemp[YAW] += flYawOffset;
|
||||
AngleVectors( vecTemp, &vecForward );
|
||||
|
||||
// Randomly angle it up or down
|
||||
vecForward.z = RandomFloat( -1, 1 );
|
||||
}
|
||||
else
|
||||
{
|
||||
vecForward = RandomVector( -1, 1 );
|
||||
}
|
||||
|
||||
UTIL_TraceLine( vecOrigin, vecOrigin + (vecForward * 192), MASK_SHOT, pEntity, COLLISION_GROUP_NONE, &tr );
|
||||
} while ( tr.fraction >= 1.0 && iTries < 3 );
|
||||
|
||||
Vector vecEnd = tr.endpos - (vecForward * 8);
|
||||
|
||||
// Only spark & glow if we hit something
|
||||
if ( tr.fraction < 1.0 )
|
||||
{
|
||||
if ( !EffectOccluded( tr.endpos ) )
|
||||
{
|
||||
// Move it towards the camera
|
||||
Vector vecFlash = tr.endpos;
|
||||
AngleVectors( MainViewAngles(), &vecForward );
|
||||
vecFlash -= (vecForward * 8);
|
||||
|
||||
g_pEffects->EnergySplash( vecFlash, -vecForward, false );
|
||||
|
||||
// End glow
|
||||
CSmartPtr<CSimpleEmitter> pSimple = CSimpleEmitter::Create( "dust" );
|
||||
pSimple->SetSortOrigin( vecFlash );
|
||||
SimpleParticle *pParticle;
|
||||
pParticle = (SimpleParticle *) pSimple->AddParticle( sizeof( SimpleParticle ), pSimple->GetPMaterial( "effects/tesla_glow_noz" ), vecFlash );
|
||||
if ( pParticle != NULL )
|
||||
{
|
||||
pParticle->m_flLifetime = 0.0f;
|
||||
pParticle->m_flDieTime = RandomFloat( 0.5, 1 );
|
||||
pParticle->m_vecVelocity = vec3_origin;
|
||||
Vector color( 1,1,1 );
|
||||
float colorRamp = 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 = RandomFloat( 6,13 );
|
||||
pParticle->m_uchEndSize = pParticle->m_uchStartSize - 2;
|
||||
pParticle->m_uchStartAlpha = 255;
|
||||
pParticle->m_uchEndAlpha = 10;
|
||||
pParticle->m_flRoll = RandomFloat( 0,360 );
|
||||
pParticle->m_flRollDelta = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Build the tesla
|
||||
FX_BuildTesla( pEntity, vecOrigin, tr.endpos );
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// 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 C_EntityDissolve::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;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Sparks!
|
||||
//-----------------------------------------------------------------------------
|
||||
void C_EntityDissolve::DoSparks( mstudiohitboxset_t *set, matrix3x4_t *hitboxbones[MAXSTUDIOBONES] )
|
||||
{
|
||||
if ( m_flNextSparkTime > gpGlobals->curtime )
|
||||
return;
|
||||
|
||||
float dt = m_flStartTime + m_flFadeOutStart - gpGlobals->curtime;
|
||||
dt = clamp( dt, 0.0f, m_flFadeOutStart );
|
||||
|
||||
float flNextTime;
|
||||
if (m_nDissolveType == ENTITY_DISSOLVE_ELECTRICAL)
|
||||
{
|
||||
flNextTime = SimpleSplineRemapVal( dt, 0.0f, m_flFadeOutStart, 2.0f * TICK_INTERVAL, 0.4f );
|
||||
}
|
||||
else
|
||||
{
|
||||
// m_nDissolveType == ENTITY_DISSOLVE_ELECTRICAL_LIGHT);
|
||||
flNextTime = SimpleSplineRemapVal( dt, 0.0f, m_flFadeOutStart, 0.3f, 1.0f );
|
||||
}
|
||||
|
||||
m_flNextSparkTime = gpGlobals->curtime + flNextTime;
|
||||
|
||||
// Send out beams around us
|
||||
int iNumBeamsAround = 2;
|
||||
int iNumRandomBeams = 1;
|
||||
int iTotalBeams = iNumBeamsAround + iNumRandomBeams;
|
||||
float flYawOffset = RandomFloat(0,360);
|
||||
for ( int i = 0; i < iTotalBeams; i++ )
|
||||
{
|
||||
int nHitbox = random->RandomInt( 0, set->numhitboxes - 1 );
|
||||
mstudiobbox_t *pBox = set->pHitbox(nHitbox);
|
||||
|
||||
float flActualYawOffset = 0;
|
||||
bool bRandom = ( i >= iNumBeamsAround );
|
||||
if ( !bRandom )
|
||||
{
|
||||
flActualYawOffset = anglemod( flYawOffset + ((360 / iTotalBeams) * i) );
|
||||
}
|
||||
|
||||
BuildTeslaEffect( pBox, *hitboxbones[pBox->bone], bRandom, flActualYawOffset );
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
void C_EntityDissolve::SetupEmitter( void )
|
||||
{
|
||||
if ( !m_pEmitter )
|
||||
{
|
||||
m_pEmitter = CSimpleEmitter::Create( "C_EntityDissolve" );
|
||||
m_pEmitter->SetSortOrigin( GetAbsOrigin() );
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
// Output : float
|
||||
//-----------------------------------------------------------------------------
|
||||
float C_EntityDissolve::GetFadeInPercentage( void )
|
||||
{
|
||||
float dt = gpGlobals->curtime - m_flStartTime;
|
||||
|
||||
if ( dt > m_flFadeOutStart )
|
||||
return 1.0f;
|
||||
|
||||
if ( dt < m_flFadeInStart )
|
||||
return 0.0f;
|
||||
|
||||
if ( (dt > m_flFadeInStart) && (dt < m_flFadeInStart + m_flFadeInLength) )
|
||||
{
|
||||
dt -= m_flFadeInStart;
|
||||
|
||||
return ( dt / m_flFadeInLength );
|
||||
}
|
||||
|
||||
return 1.0f;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
// Output : float
|
||||
//-----------------------------------------------------------------------------
|
||||
float C_EntityDissolve::GetFadeOutPercentage( void )
|
||||
{
|
||||
float dt = gpGlobals->curtime - m_flStartTime;
|
||||
|
||||
if ( dt < m_flFadeInStart )
|
||||
return 1.0f;
|
||||
|
||||
if ( dt > m_flFadeOutStart )
|
||||
{
|
||||
dt -= m_flFadeOutStart;
|
||||
|
||||
if ( dt > m_flFadeOutLength )
|
||||
return 0.0f;
|
||||
|
||||
return 1.0f - ( dt / m_flFadeOutLength );
|
||||
}
|
||||
|
||||
return 1.0f;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
// Output : float
|
||||
//-----------------------------------------------------------------------------
|
||||
float C_EntityDissolve::GetModelFadeOutPercentage( void )
|
||||
{
|
||||
float dt = gpGlobals->curtime - m_flStartTime;
|
||||
|
||||
if ( dt < m_flFadeOutModelStart )
|
||||
return 1.0f;
|
||||
|
||||
if ( dt > m_flFadeOutModelStart )
|
||||
{
|
||||
dt -= m_flFadeOutModelStart;
|
||||
|
||||
if ( dt > m_flFadeOutModelLength )
|
||||
return 0.0f;
|
||||
|
||||
return 1.0f - ( dt / m_flFadeOutModelLength );
|
||||
}
|
||||
|
||||
return 1.0f;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
void C_EntityDissolve::ClientThink( void )
|
||||
{
|
||||
C_BaseEntity *pEnt = GetMoveParent();
|
||||
if ( !pEnt )
|
||||
return;
|
||||
|
||||
bool bIsRagdoll;
|
||||
#ifdef TF_CLIENT_DLL
|
||||
bIsRagdoll = true;
|
||||
#else
|
||||
C_BaseAnimating *pAnimating = GetMoveParent() ? GetMoveParent()->GetBaseAnimating() : NULL;
|
||||
if (!pAnimating)
|
||||
return;
|
||||
bIsRagdoll = pAnimating->IsRagdoll();
|
||||
#endif
|
||||
|
||||
// NOTE: IsRagdoll means *client-side* ragdoll. We shouldn't be trying to fight
|
||||
// the server ragdoll (or any server physics) on the client
|
||||
if (( !m_pController ) && ( m_nDissolveType == ENTITY_DISSOLVE_NORMAL ) && bIsRagdoll )
|
||||
{
|
||||
IPhysicsObject *ppList[VPHYSICS_MAX_OBJECT_LIST_COUNT];
|
||||
int nCount = pEnt->VPhysicsGetObjectList( ppList, ARRAYSIZE(ppList) );
|
||||
if ( nCount > 0 )
|
||||
{
|
||||
m_pController = physenv->CreateMotionController( this );
|
||||
for ( int i = 0; i < nCount; ++i )
|
||||
{
|
||||
m_pController->AttachObject( ppList[i], true );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
color32 color;
|
||||
|
||||
color.r = ( 1.0f - GetFadeInPercentage() ) * m_vEffectColor.x;
|
||||
color.g = ( 1.0f - GetFadeInPercentage() ) * m_vEffectColor.y;
|
||||
color.b = ( 1.0f - GetFadeInPercentage() ) * m_vEffectColor.z;
|
||||
color.a = GetModelFadeOutPercentage() * 255.0f;
|
||||
|
||||
// Setup the entity fade
|
||||
pEnt->SetRenderMode( kRenderTransColor );
|
||||
pEnt->SetRenderColor( color.r, color.g, color.b, color.a );
|
||||
|
||||
if ( GetModelFadeOutPercentage() <= 0.2f )
|
||||
{
|
||||
m_bCoreExplode = true;
|
||||
}
|
||||
|
||||
// If we're dead, fade out
|
||||
if ( GetFadeOutPercentage() <= 0.0f )
|
||||
{
|
||||
// Do NOT remove from the client entity list. It'll confuse the local network backdoor, and the entity will never get destroyed
|
||||
// because when the server says to destroy it, the client won't be able to find it.
|
||||
// ClientEntityList().RemoveEntity( GetClientHandle() );
|
||||
|
||||
::partition->Remove( PARTITION_CLIENT_SOLID_EDICTS | PARTITION_CLIENT_RESPONSIVE_EDICTS | PARTITION_CLIENT_NON_STATIC_EDICTS, CollisionProp()->GetPartitionHandle() );
|
||||
|
||||
RemoveFromLeafSystem();
|
||||
|
||||
//FIXME: Ick!
|
||||
//Adrian: I'll assume we don't need the ragdoll either so I'll remove that too.
|
||||
if ( m_bLinkedToServerEnt == false )
|
||||
{
|
||||
Release();
|
||||
|
||||
C_ClientRagdoll *pRagdoll = dynamic_cast <C_ClientRagdoll *> ( pEnt );
|
||||
|
||||
if ( pRagdoll )
|
||||
{
|
||||
pRagdoll->ReleaseRagdoll();
|
||||
}
|
||||
#ifdef TF_CLIENT_DLL
|
||||
else
|
||||
{
|
||||
// Hide the ragdoll -- don't actually delete it or else things get unhappy when
|
||||
// we get a message from the server telling us to delete it
|
||||
pEnt->AddEffects( EF_NODRAW );
|
||||
pEnt->ParticleProp()->StopEmission();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
// Input : flags -
|
||||
// Output : int
|
||||
//-----------------------------------------------------------------------------
|
||||
int C_EntityDissolve::DrawModel( int flags )
|
||||
{
|
||||
// See if we should draw
|
||||
if ( gpGlobals->frametime == 0 || m_bReadyToDraw == false )
|
||||
return 0;
|
||||
|
||||
C_BaseAnimating *pAnimating = GetMoveParent() ? GetMoveParent()->GetBaseAnimating() : NULL;
|
||||
if ( pAnimating == NULL )
|
||||
return 0;
|
||||
|
||||
matrix3x4_t *hitboxbones[MAXSTUDIOBONES];
|
||||
if ( pAnimating->HitboxToWorldTransforms( hitboxbones ) == false )
|
||||
return 0;
|
||||
|
||||
studiohdr_t *pStudioHdr = modelinfo->GetStudiomodel( pAnimating->GetModel() );
|
||||
if ( pStudioHdr == NULL )
|
||||
return false;
|
||||
|
||||
mstudiohitboxset_t *set = pStudioHdr->pHitboxSet( pAnimating->GetHitboxSet() );
|
||||
if ( set == NULL )
|
||||
return false;
|
||||
|
||||
// Make sure the emitter is setup properly
|
||||
SetupEmitter();
|
||||
|
||||
// Get fade percentages for the effect
|
||||
float fadeInPerc = GetFadeInPercentage();
|
||||
float fadeOutPerc = GetFadeOutPercentage();
|
||||
|
||||
float fadePerc = ( fadeInPerc >= 1.0f ) ? fadeOutPerc : fadeInPerc;
|
||||
|
||||
Vector vecSkew = vec3_origin;
|
||||
|
||||
// Do extra effects under certain circumstances
|
||||
if ( ( fadePerc < 0.99f ) && ( (m_nDissolveType == ENTITY_DISSOLVE_ELECTRICAL) || (m_nDissolveType == ENTITY_DISSOLVE_ELECTRICAL_LIGHT) ) )
|
||||
{
|
||||
DoSparks( set, hitboxbones );
|
||||
}
|
||||
|
||||
// Skew the particles in front or in back of their targets
|
||||
vecSkew = CurrentViewForward() * ( 8.0f - ( ( 1.0f - fadePerc ) * 32.0f ) );
|
||||
|
||||
float spriteScale = ( ( gpGlobals->curtime - m_flStartTime ) / m_flFadeOutLength );
|
||||
spriteScale = clamp( spriteScale, 0.75f, 1.0f );
|
||||
|
||||
// Cache off this material reference
|
||||
if ( g_Material_Spark == NULL )
|
||||
{
|
||||
g_Material_Spark = ParticleMgr()->GetPMaterial( "effects/spark" );
|
||||
}
|
||||
|
||||
if ( g_Material_AR2Glow == NULL )
|
||||
{
|
||||
g_Material_AR2Glow = ParticleMgr()->GetPMaterial( "effects/combinemuzzle2" );
|
||||
}
|
||||
|
||||
SimpleParticle *sParticle;
|
||||
|
||||
for ( int 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( 3.0f * fadePerc, 0.f, 3.f );
|
||||
|
||||
int iTempParts = 2;
|
||||
|
||||
if ( m_nDissolveType == ENTITY_DISSOLVE_CORE )
|
||||
{
|
||||
if ( m_bCoreExplode == true )
|
||||
{
|
||||
numParticles = 15;
|
||||
iTempParts = 20;
|
||||
}
|
||||
}
|
||||
|
||||
for ( int j = 0; j < iTempParts; j++ )
|
||||
{
|
||||
// Skew the origin
|
||||
offset = xDir * Helper_RandomFloat( -xScale*0.5f, xScale*0.5f ) + yDir * Helper_RandomFloat( -yScale*0.5f, yScale*0.5f );
|
||||
offset += vecSkew;
|
||||
|
||||
if ( random->RandomInt( 0, 2 ) != 0 )
|
||||
continue;
|
||||
|
||||
sParticle = (SimpleParticle *) m_pEmitter->AddParticle( sizeof(SimpleParticle), g_Material_Spark, vecAbsOrigin + offset );
|
||||
|
||||
if ( sParticle == NULL )
|
||||
return 1;
|
||||
|
||||
sParticle->m_vecVelocity = Vector( Helper_RandomFloat( -4.0f, 4.0f ), Helper_RandomFloat( -4.0f, 4.0f ), Helper_RandomFloat( 16.0f, 64.0f ) );
|
||||
|
||||
if ( m_nDissolveType == ENTITY_DISSOLVE_CORE )
|
||||
{
|
||||
if ( m_bCoreExplode == true )
|
||||
{
|
||||
Vector vDirection = (vecAbsOrigin + offset) - m_vDissolverOrigin;
|
||||
VectorNormalize( vDirection );
|
||||
sParticle->m_vecVelocity = vDirection * m_nMagnitude;
|
||||
}
|
||||
}
|
||||
|
||||
if ( sParticle->m_vecVelocity.z > 0 )
|
||||
{
|
||||
sParticle->m_uchStartSize = random->RandomFloat( 4, 6 ) * spriteScale;
|
||||
}
|
||||
else
|
||||
{
|
||||
sParticle->m_uchStartSize = 2 * spriteScale;
|
||||
}
|
||||
|
||||
sParticle->m_flDieTime = random->RandomFloat( 0.4f, 0.5f );
|
||||
|
||||
// If we're the last particles, last longer
|
||||
if ( numParticles == 0 )
|
||||
{
|
||||
sParticle->m_flDieTime *= 2.0f;
|
||||
sParticle->m_uchStartSize = 2 * spriteScale;
|
||||
sParticle->m_flRollDelta = Helper_RandomFloat( -4.0f, 4.0f );
|
||||
|
||||
if ( m_nDissolveType == ENTITY_DISSOLVE_CORE )
|
||||
{
|
||||
if ( m_bCoreExplode == true )
|
||||
{
|
||||
sParticle->m_flDieTime *= 2.0f;
|
||||
sParticle->m_flRollDelta = Helper_RandomFloat( -1.0f, 1.0f );
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
sParticle->m_flRollDelta = Helper_RandomFloat( -8.0f, 8.0f );
|
||||
}
|
||||
|
||||
sParticle->m_flLifetime = 0.0f;
|
||||
|
||||
sParticle->m_flRoll = Helper_RandomInt( 0, 360 );
|
||||
|
||||
float alpha = 255;
|
||||
|
||||
sParticle->m_uchColor[0] = m_vEffectColor.x;
|
||||
sParticle->m_uchColor[1] = m_vEffectColor.y;
|
||||
sParticle->m_uchColor[2] = m_vEffectColor.z;
|
||||
sParticle->m_uchStartAlpha = alpha;
|
||||
sParticle->m_uchEndAlpha = 0;
|
||||
sParticle->m_uchEndSize = 0;
|
||||
}
|
||||
|
||||
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), g_Material_AR2Glow, vecAbsOrigin + offset );
|
||||
|
||||
if ( sParticle == NULL )
|
||||
return 1;
|
||||
|
||||
sParticle->m_vecVelocity = Vector( Helper_RandomFloat( -4.0f, 4.0f ), Helper_RandomFloat( -4.0f, 4.0f ), Helper_RandomFloat( -64.0f, 128.0f ) );
|
||||
sParticle->m_uchStartSize = random->RandomFloat( 8, 12 ) * spriteScale;
|
||||
sParticle->m_flDieTime = 0.1f;
|
||||
sParticle->m_flLifetime = 0.0f;
|
||||
|
||||
sParticle->m_flRoll = Helper_RandomInt( 0, 360 );
|
||||
sParticle->m_flRollDelta = Helper_RandomFloat( -2.0f, 2.0f );
|
||||
|
||||
float alpha = 255;
|
||||
|
||||
sParticle->m_uchColor[0] = m_vEffectColor.x;
|
||||
sParticle->m_uchColor[1] = m_vEffectColor.y;
|
||||
sParticle->m_uchColor[2] = m_vEffectColor.z;
|
||||
sParticle->m_uchStartAlpha = alpha;
|
||||
sParticle->m_uchEndAlpha = 0;
|
||||
sParticle->m_uchEndSize = 0;
|
||||
|
||||
if ( m_nDissolveType == ENTITY_DISSOLVE_CORE )
|
||||
{
|
||||
if ( m_bCoreExplode == true )
|
||||
{
|
||||
Vector vDirection = (vecAbsOrigin + offset) - m_vDissolverOrigin;
|
||||
|
||||
VectorNormalize( vDirection );
|
||||
|
||||
sParticle->m_vecVelocity = vDirection * m_nMagnitude;
|
||||
|
||||
sParticle->m_flDieTime = 0.5f;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
@@ -0,0 +1,82 @@
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
// $NoKeywords: $
|
||||
//=============================================================================//
|
||||
|
||||
#ifndef C_ENTITY_DISSOLVE_H
|
||||
#define C_ENTITY_DISSOLVE_H
|
||||
|
||||
#include "cbase.h"
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Entity Dissolve, client-side implementation
|
||||
//-----------------------------------------------------------------------------
|
||||
class C_EntityDissolve : public C_BaseEntity, public IMotionEvent
|
||||
{
|
||||
public:
|
||||
DECLARE_CLIENTCLASS();
|
||||
DECLARE_CLASS( C_EntityDissolve, C_BaseEntity );
|
||||
|
||||
C_EntityDissolve( void );
|
||||
|
||||
// Inherited from C_BaseEntity
|
||||
virtual void GetRenderBounds( Vector& theMins, Vector& theMaxs );
|
||||
virtual int DrawModel( int flags );
|
||||
virtual bool ShouldDraw() { return true; }
|
||||
virtual void OnDataChanged( DataUpdateType_t updateType );
|
||||
virtual void UpdateOnRemove( void );
|
||||
|
||||
virtual Vector GetEffectColor( void ) { return m_vEffectColor; }
|
||||
virtual void SetEffectColor( Vector v ) { m_vEffectColor = v; }
|
||||
|
||||
// Inherited from IMotionEvent
|
||||
virtual simresult_e Simulate( IPhysicsMotionController *pController, IPhysicsObject *pObject, float deltaTime, Vector &linear, AngularImpulse &angular );
|
||||
|
||||
void SetupEmitter( void );
|
||||
|
||||
void ClientThink( void );
|
||||
|
||||
void SetServerLinkState( bool state ) { m_bLinkedToServerEnt = state; }
|
||||
|
||||
float m_flStartTime;
|
||||
float m_flFadeOutStart;
|
||||
float m_flFadeOutLength;
|
||||
float m_flFadeOutModelStart;
|
||||
float m_flFadeOutModelLength;
|
||||
float m_flFadeInStart;
|
||||
float m_flFadeInLength;
|
||||
int m_nDissolveType;
|
||||
float m_flNextSparkTime;
|
||||
|
||||
Vector m_vEffectColor;
|
||||
|
||||
Vector m_vDissolverOrigin;
|
||||
int m_nMagnitude;
|
||||
|
||||
bool m_bCoreExplode;
|
||||
|
||||
protected:
|
||||
|
||||
float GetFadeInPercentage( void ); // Fade in amount (entity fading to black)
|
||||
float GetFadeOutPercentage( void ); // Fade out amount (particles fading away)
|
||||
float GetModelFadeOutPercentage( void );// Mode fade out amount
|
||||
|
||||
// Compute the bounding box's center, size, and basis
|
||||
void ComputeRenderInfo( mstudiobbox_t *pHitBox, const matrix3x4_t &hitboxToWorld,
|
||||
Vector *pVecAbsOrigin, Vector *pXVec, Vector *pYVec );
|
||||
void BuildTeslaEffect( mstudiobbox_t *pHitBox, const matrix3x4_t &hitboxToWorld, bool bRandom, float flYawOffset );
|
||||
|
||||
void DoSparks( mstudiohitboxset_t *set, matrix3x4_t *hitboxbones[MAXSTUDIOBONES] );
|
||||
|
||||
private:
|
||||
|
||||
CSmartPtr<CSimpleEmitter> m_pEmitter;
|
||||
|
||||
bool m_bLinkedToServerEnt;
|
||||
IPhysicsMotionController *m_pController;
|
||||
};
|
||||
|
||||
#endif // C_ENTITY_DISSOLVE_H
|
||||
|
||||
@@ -0,0 +1,250 @@
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
// $NoKeywords: $
|
||||
//=============================================================================//
|
||||
|
||||
#include "cbase.h"
|
||||
#include "baseparticleentity.h"
|
||||
#include "entityparticletrail_shared.h"
|
||||
#include "particlemgr.h"
|
||||
#include "particle_util.h"
|
||||
#include "particles_simple.h"
|
||||
|
||||
// memdbgon must be the last include file in a .cpp file!!!
|
||||
#include "tier0/memdbgon.h"
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Entity particle trail, client-side implementation
|
||||
//-----------------------------------------------------------------------------
|
||||
class C_EntityParticleTrail : public C_BaseParticleEntity
|
||||
{
|
||||
public:
|
||||
DECLARE_CLIENTCLASS();
|
||||
DECLARE_CLASS( C_EntityParticleTrail, C_BaseParticleEntity );
|
||||
|
||||
C_EntityParticleTrail( );
|
||||
~C_EntityParticleTrail( );
|
||||
|
||||
// C_BaseEntity
|
||||
virtual void OnDataChanged( DataUpdateType_t updateType );
|
||||
|
||||
// IParticleEffect
|
||||
void Update( float fTimeDelta );
|
||||
virtual void RenderParticles( CParticleRenderIterator *pIterator );
|
||||
virtual void SimulateParticles( CParticleSimulateIterator *pIterator );
|
||||
|
||||
private:
|
||||
|
||||
C_EntityParticleTrail( const C_EntityParticleTrail & ); // not defined, not accessible
|
||||
|
||||
void Start( );
|
||||
void AddParticle( float flInitialDeltaTime, const Vector &vecMins, const Vector &vecMaxs, const matrix3x4_t &boxToWorld );
|
||||
|
||||
int m_iMaterialName;
|
||||
EntityParticleTrailInfo_t m_Info;
|
||||
EHANDLE m_hConstraintEntity;
|
||||
|
||||
PMaterialHandle m_hMaterial;
|
||||
TimedEvent m_teParticleSpawn;
|
||||
};
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Networking
|
||||
//-----------------------------------------------------------------------------
|
||||
IMPLEMENT_CLIENTCLASS_DT( C_EntityParticleTrail, DT_EntityParticleTrail, CEntityParticleTrail )
|
||||
RecvPropInt(RECVINFO(m_iMaterialName)),
|
||||
RecvPropDataTable( RECVINFO_DT( m_Info ), 0, &REFERENCE_RECV_TABLE(DT_EntityParticleTrailInfo) ),
|
||||
RecvPropEHandle(RECVINFO(m_hConstraintEntity)),
|
||||
END_RECV_TABLE()
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
C_EntityParticleTrail::C_EntityParticleTrail( void )
|
||||
{
|
||||
}
|
||||
|
||||
C_EntityParticleTrail::~C_EntityParticleTrail()
|
||||
{
|
||||
ParticleMgr()->RemoveEffect( &m_ParticleEffect );
|
||||
}
|
||||
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// On data changed
|
||||
//-----------------------------------------------------------------------------
|
||||
void C_EntityParticleTrail::OnDataChanged( DataUpdateType_t updateType )
|
||||
{
|
||||
BaseClass::OnDataChanged( updateType );
|
||||
if ( updateType == DATA_UPDATE_CREATED )
|
||||
{
|
||||
Start( );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
// Input : *pParticleMgr -
|
||||
// *pArgs -
|
||||
//-----------------------------------------------------------------------------
|
||||
void C_EntityParticleTrail::Start( )
|
||||
{
|
||||
if( ParticleMgr()->AddEffect( &m_ParticleEffect, this ) == false )
|
||||
return;
|
||||
|
||||
const char *pMaterialName = GetMaterialNameFromIndex( m_iMaterialName );
|
||||
if ( !pMaterialName )
|
||||
return;
|
||||
|
||||
m_hMaterial = ParticleMgr()->GetPMaterial( pMaterialName );
|
||||
m_teParticleSpawn.Init( 150 );
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
void C_EntityParticleTrail::AddParticle( float flInitialDeltaTime, const Vector &vecMins, const Vector &vecMaxs, const matrix3x4_t &boxToWorld )
|
||||
{
|
||||
// Select a random point somewhere in the hitboxes of the entity.
|
||||
Vector vecLocalPosition, vecWorldPosition;
|
||||
vecLocalPosition.x = Lerp( random->RandomFloat( 0.0f, 1.0f ), vecMins.x, vecMaxs.x );
|
||||
vecLocalPosition.y = Lerp( random->RandomFloat( 0.0f, 1.0f ), vecMins.y, vecMaxs.y );
|
||||
vecLocalPosition.z = Lerp( random->RandomFloat( 0.0f, 1.0f ), vecMins.z, vecMaxs.z );
|
||||
VectorTransform( vecLocalPosition, boxToWorld, vecWorldPosition );
|
||||
|
||||
// Don't emit the particle unless it's inside the model
|
||||
if ( m_hConstraintEntity.Get() )
|
||||
{
|
||||
Ray_t ray;
|
||||
trace_t tr;
|
||||
ray.Init( vecWorldPosition, vecWorldPosition );
|
||||
enginetrace->ClipRayToEntity( ray, MASK_ALL, m_hConstraintEntity, &tr );
|
||||
|
||||
if ( !tr.startsolid )
|
||||
return;
|
||||
}
|
||||
|
||||
// Make a new particle
|
||||
SimpleParticle *pParticle = (SimpleParticle *)m_ParticleEffect.AddParticle( sizeof(SimpleParticle), m_hMaterial );
|
||||
if ( pParticle == NULL )
|
||||
return;
|
||||
|
||||
pParticle->m_Pos = vecWorldPosition;
|
||||
pParticle->m_flRoll = Helper_RandomInt( 0, 360 );
|
||||
pParticle->m_flRollDelta = Helper_RandomFloat( -2.0f, 2.0f );
|
||||
|
||||
pParticle->m_flLifetime = flInitialDeltaTime;
|
||||
pParticle->m_flDieTime = m_Info.m_flLifetime;
|
||||
|
||||
pParticle->m_uchColor[0] = 64;
|
||||
pParticle->m_uchColor[1] = 140;
|
||||
pParticle->m_uchColor[2] = 225;
|
||||
pParticle->m_uchStartAlpha = Helper_RandomInt( 64, 64 );
|
||||
pParticle->m_uchEndAlpha = 0;
|
||||
|
||||
pParticle->m_uchStartSize = m_Info.m_flStartSize;
|
||||
pParticle->m_uchEndSize = m_Info.m_flEndSize;
|
||||
|
||||
pParticle->m_vecVelocity = vec3_origin;
|
||||
VectorMA( pParticle->m_Pos, flInitialDeltaTime, pParticle->m_vecVelocity, pParticle->m_Pos );
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
// Input : fTimeDelta -
|
||||
//-----------------------------------------------------------------------------
|
||||
void C_EntityParticleTrail::Update( float fTimeDelta )
|
||||
{
|
||||
float tempDelta = fTimeDelta;
|
||||
studiohdr_t *pStudioHdr;
|
||||
mstudiohitboxset_t *set;
|
||||
matrix3x4_t *hitboxbones[MAXSTUDIOBONES];
|
||||
|
||||
C_BaseEntity *pMoveParent = GetMoveParent();
|
||||
if ( !pMoveParent )
|
||||
return;
|
||||
|
||||
C_BaseAnimating *pAnimating = pMoveParent->GetBaseAnimating();
|
||||
if (!pAnimating)
|
||||
goto trailNoHitboxes;
|
||||
|
||||
if ( !pAnimating->HitboxToWorldTransforms( hitboxbones ) )
|
||||
goto trailNoHitboxes;
|
||||
|
||||
pStudioHdr = modelinfo->GetStudiomodel( pAnimating->GetModel() );
|
||||
if (!pStudioHdr)
|
||||
goto trailNoHitboxes;
|
||||
|
||||
set = pStudioHdr->pHitboxSet( pAnimating->GetHitboxSet() );
|
||||
if ( !set )
|
||||
goto trailNoHitboxes;
|
||||
|
||||
//Add new particles
|
||||
while ( m_teParticleSpawn.NextEvent( tempDelta ) )
|
||||
{
|
||||
int nHitbox = random->RandomInt( 0, set->numhitboxes - 1 );
|
||||
mstudiobbox_t *pBox = set->pHitbox(nHitbox);
|
||||
|
||||
AddParticle( tempDelta, pBox->bbmin, pBox->bbmax, *hitboxbones[pBox->bone] );
|
||||
}
|
||||
return;
|
||||
|
||||
trailNoHitboxes:
|
||||
while ( m_teParticleSpawn.NextEvent( tempDelta ) )
|
||||
{
|
||||
AddParticle( tempDelta, pMoveParent->CollisionProp()->OBBMins(), pMoveParent->CollisionProp()->OBBMaxs(), pMoveParent->EntityToWorldTransform() );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
inline void C_EntityParticleTrail::RenderParticles( CParticleRenderIterator *pIterator )
|
||||
{
|
||||
const SimpleParticle *pParticle = (const SimpleParticle*)pIterator->GetFirst();
|
||||
while ( pParticle )
|
||||
{
|
||||
float t = pParticle->m_flLifetime / pParticle->m_flDieTime;
|
||||
|
||||
// Render
|
||||
Vector tPos;
|
||||
TransformParticle( ParticleMgr()->GetModelView(), pParticle->m_Pos, tPos );
|
||||
float sortKey = tPos.z;
|
||||
|
||||
Vector color = Vector( pParticle->m_uchColor[0] / 255.0f, pParticle->m_uchColor[1] / 255.0f, pParticle->m_uchColor[2] / 255.0f );
|
||||
float alpha = Lerp( t, pParticle->m_uchStartAlpha / 255.0f, pParticle->m_uchEndAlpha / 255.0f );
|
||||
float flSize = Lerp( t, pParticle->m_uchStartSize, pParticle->m_uchEndSize );
|
||||
|
||||
// Render it
|
||||
RenderParticle_ColorSize( pIterator->GetParticleDraw(), tPos, color, alpha, flSize );
|
||||
|
||||
pParticle = (const SimpleParticle*)pIterator->GetNext( sortKey );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
inline void C_EntityParticleTrail::SimulateParticles( CParticleSimulateIterator *pIterator )
|
||||
{
|
||||
SimpleParticle *pParticle = (SimpleParticle*)pIterator->GetFirst();
|
||||
while ( pParticle )
|
||||
{
|
||||
// Update position
|
||||
float flTimeDelta = pIterator->GetTimeDelta();
|
||||
pParticle->m_Pos += pParticle->m_vecVelocity * flTimeDelta;
|
||||
|
||||
// NOTE: I'm overloading "die time" to be the actual start time.
|
||||
pParticle->m_flLifetime += flTimeDelta;
|
||||
|
||||
if ( pParticle->m_flLifetime >= pParticle->m_flDieTime )
|
||||
pIterator->RemoveParticle( pParticle );
|
||||
|
||||
pParticle = (SimpleParticle*)pIterator->GetNext();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,46 @@
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// An entity that allows level designer control over the fog parameters.
|
||||
//
|
||||
//=============================================================================
|
||||
|
||||
#include "cbase.h"
|
||||
#include "c_env_fog_controller.h"
|
||||
|
||||
// memdbgon must be the last include file in a .cpp file!!!
|
||||
#include "tier0/memdbgon.h"
|
||||
|
||||
IMPLEMENT_NETWORKCLASS_ALIASED( FogController, DT_FogController )
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Datatable
|
||||
//-----------------------------------------------------------------------------
|
||||
BEGIN_NETWORK_TABLE_NOBASE( CFogController, DT_FogController )
|
||||
// fog data
|
||||
RecvPropInt( RECVINFO( m_fog.enable ) ),
|
||||
RecvPropInt( RECVINFO( m_fog.blend ) ),
|
||||
RecvPropVector( RECVINFO( m_fog.dirPrimary ) ),
|
||||
RecvPropInt( RECVINFO( m_fog.colorPrimary ) ),
|
||||
RecvPropInt( RECVINFO( m_fog.colorSecondary ) ),
|
||||
RecvPropFloat( RECVINFO( m_fog.start ) ),
|
||||
RecvPropFloat( RECVINFO( m_fog.end ) ),
|
||||
RecvPropFloat( RECVINFO( m_fog.farz ) ),
|
||||
RecvPropFloat( RECVINFO( m_fog.maxdensity ) ),
|
||||
|
||||
RecvPropInt( RECVINFO( m_fog.colorPrimaryLerpTo ) ),
|
||||
RecvPropInt( RECVINFO( m_fog.colorSecondaryLerpTo ) ),
|
||||
RecvPropFloat( RECVINFO( m_fog.startLerpTo ) ),
|
||||
RecvPropFloat( RECVINFO( m_fog.endLerpTo ) ),
|
||||
RecvPropFloat( RECVINFO( m_fog.lerptime ) ),
|
||||
RecvPropFloat( RECVINFO( m_fog.duration ) ),
|
||||
END_NETWORK_TABLE()
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
C_FogController::C_FogController()
|
||||
{
|
||||
// Make sure that old maps without fog fields don't get wacked out fog values.
|
||||
m_fog.enable = false;
|
||||
m_fog.maxdensity = 1.0f;
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
// $NoKeywords: $
|
||||
//=============================================================================//
|
||||
|
||||
#ifndef C_ENV_FOG_CONTROLLER_H
|
||||
#define C_ENV_FOG_CONTROLLER_H
|
||||
|
||||
#define CFogController C_FogController
|
||||
|
||||
//=============================================================================
|
||||
//
|
||||
// Class Fog Controller:
|
||||
// Compares a set of integer inputs to the one main input
|
||||
// Outputs true if they are all equivalant, false otherwise
|
||||
//
|
||||
class C_FogController : public C_BaseEntity
|
||||
{
|
||||
public:
|
||||
DECLARE_NETWORKCLASS();
|
||||
DECLARE_CLASS( C_FogController, C_BaseEntity );
|
||||
|
||||
C_FogController();
|
||||
|
||||
public:
|
||||
|
||||
fogparams_t m_fog;
|
||||
};
|
||||
|
||||
|
||||
#endif // C_ENV_FOG_CONTROLLER_H
|
||||
@@ -0,0 +1,304 @@
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
// $NoKeywords: $
|
||||
//===========================================================================//
|
||||
|
||||
#include "cbase.h"
|
||||
#include "c_baseanimating.h"
|
||||
#include "particlemgr.h"
|
||||
#include "materialsystem/imaterialvar.h"
|
||||
#include "cl_animevent.h"
|
||||
#include "particle_util.h"
|
||||
|
||||
// memdbgon must be the last include file in a .cpp file!!!
|
||||
#include "tier0/memdbgon.h"
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// An entity which emits other entities at points
|
||||
//-----------------------------------------------------------------------------
|
||||
class C_EnvParticleScript : public C_BaseAnimating, public IParticleEffect
|
||||
{
|
||||
public:
|
||||
DECLARE_CLASS( C_EnvParticleScript, C_BaseAnimating );
|
||||
DECLARE_CLIENTCLASS();
|
||||
|
||||
C_EnvParticleScript();
|
||||
|
||||
// IParticleEffect overrides.
|
||||
public:
|
||||
virtual bool ShouldSimulate() const { return m_bSimulate; }
|
||||
virtual void SetShouldSimulate( bool bSim ) { m_bSimulate = bSim; }
|
||||
|
||||
virtual void RenderParticles( CParticleRenderIterator *pIterator );
|
||||
virtual void SimulateParticles( CParticleSimulateIterator *pIterator );
|
||||
|
||||
virtual const Vector &GetSortOrigin();
|
||||
|
||||
// C_BaseAnimating overrides
|
||||
public:
|
||||
// NOTE: Ths enclosed particle effect binding will do all the drawing
|
||||
// But we have to return true, unlike other particle systems, for the animation events to work
|
||||
virtual bool ShouldDraw() { return true; }
|
||||
virtual int DrawModel( int flags ) { return 0; }
|
||||
virtual int GetFxBlend( void ) { return 0; }
|
||||
|
||||
virtual void FireEvent( const Vector& origin, const QAngle& angles, int event, const char *options );
|
||||
virtual void OnPreDataChanged( DataUpdateType_t updateType );
|
||||
virtual void OnDataChanged( DataUpdateType_t updateType );
|
||||
|
||||
private:
|
||||
|
||||
// Creates, destroys particles attached to an attachment
|
||||
void CreateParticle( const char *pAttachmentName, const char *pSpriteName );
|
||||
void DestroyAllParticles( const char *pAttachmentName );
|
||||
void DestroyAllParticles( );
|
||||
|
||||
private:
|
||||
struct ParticleScriptParticle_t : public Particle
|
||||
{
|
||||
int m_nAttachment;
|
||||
float m_flSize;
|
||||
};
|
||||
|
||||
CParticleEffectBinding m_ParticleEffect;
|
||||
float m_flMaxParticleSize;
|
||||
int m_nOldSequence;
|
||||
float m_flSequenceScale;
|
||||
bool m_bSimulate;
|
||||
};
|
||||
|
||||
REGISTER_EFFECT( C_EnvParticleScript );
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Datatable
|
||||
//-----------------------------------------------------------------------------
|
||||
IMPLEMENT_CLIENTCLASS_DT( C_EnvParticleScript, DT_EnvParticleScript, CEnvParticleScript )
|
||||
RecvPropFloat( RECVINFO(m_flSequenceScale) ),
|
||||
END_RECV_TABLE()
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Constructor
|
||||
//-----------------------------------------------------------------------------
|
||||
C_EnvParticleScript::C_EnvParticleScript()
|
||||
{
|
||||
m_flMaxParticleSize = 0.0f;
|
||||
m_bSimulate = true;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Check for changed sequence numbers
|
||||
//-----------------------------------------------------------------------------
|
||||
void C_EnvParticleScript::OnPreDataChanged( DataUpdateType_t updateType )
|
||||
{
|
||||
BaseClass::OnPreDataChanged( updateType );
|
||||
|
||||
m_nOldSequence = GetSequence();
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Starts up the particle system
|
||||
//-----------------------------------------------------------------------------
|
||||
void C_EnvParticleScript::OnDataChanged( DataUpdateType_t updateType )
|
||||
{
|
||||
BaseClass::OnDataChanged( updateType );
|
||||
|
||||
if(updateType == DATA_UPDATE_CREATED)
|
||||
{
|
||||
ParticleMgr()->AddEffect( &m_ParticleEffect, this );
|
||||
}
|
||||
|
||||
if ( m_nOldSequence != GetSequence() )
|
||||
{
|
||||
DestroyAllParticles();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Creates, destroys particles attached to an attachment
|
||||
//-----------------------------------------------------------------------------
|
||||
void C_EnvParticleScript::CreateParticle( const char *pAttachmentName, const char *pSpriteName )
|
||||
{
|
||||
// Find the attachment
|
||||
int nAttachment = LookupAttachment( pAttachmentName );
|
||||
if ( nAttachment <= 0 )
|
||||
return;
|
||||
|
||||
// Get the sprite materials
|
||||
PMaterialHandle hMat = m_ParticleEffect.FindOrAddMaterial( pSpriteName );
|
||||
ParticleScriptParticle_t *pParticle =
|
||||
(ParticleScriptParticle_t*)m_ParticleEffect.AddParticle(sizeof(ParticleScriptParticle_t), hMat);
|
||||
|
||||
if ( pParticle == NULL )
|
||||
return;
|
||||
|
||||
// Get the sprite size from the material's materialvars
|
||||
bool bFound = false;
|
||||
IMaterialVar *pMaterialVar = NULL;
|
||||
IMaterial *pMaterial = ParticleMgr()->PMaterialToIMaterial( hMat );
|
||||
if ( pMaterial )
|
||||
{
|
||||
pMaterialVar = pMaterial->FindVar( "$spritesize", &bFound, false );
|
||||
}
|
||||
|
||||
if ( bFound )
|
||||
{
|
||||
pParticle->m_flSize = pMaterialVar->GetFloatValue();
|
||||
}
|
||||
else
|
||||
{
|
||||
pParticle->m_flSize = 100.0f;
|
||||
}
|
||||
|
||||
// Make sure the particle cull size reflects our particles
|
||||
if ( pParticle->m_flSize > m_flMaxParticleSize )
|
||||
{
|
||||
m_flMaxParticleSize = pParticle->m_flSize;
|
||||
m_ParticleEffect.SetParticleCullRadius( m_flMaxParticleSize );
|
||||
}
|
||||
|
||||
// Place the particle on the attachment specified
|
||||
pParticle->m_nAttachment = nAttachment;
|
||||
QAngle vecAngles;
|
||||
GetAttachment( nAttachment, pParticle->m_Pos, vecAngles );
|
||||
|
||||
if ( m_flSequenceScale != 1.0f )
|
||||
{
|
||||
pParticle->m_Pos -= GetAbsOrigin();
|
||||
pParticle->m_Pos *= m_flSequenceScale;
|
||||
pParticle->m_Pos += GetAbsOrigin();
|
||||
}
|
||||
}
|
||||
|
||||
void C_EnvParticleScript::DestroyAllParticles( const char *pAttachmentName )
|
||||
{
|
||||
int nAttachment = LookupAttachment( pAttachmentName );
|
||||
if ( nAttachment <= 0 )
|
||||
return;
|
||||
|
||||
int nCount = m_ParticleEffect.GetNumActiveParticles();
|
||||
Particle** ppParticles = (Particle**)stackalloc( nCount * sizeof(Particle*) );
|
||||
int nActualCount = m_ParticleEffect.GetActiveParticleList( nCount, ppParticles );
|
||||
Assert( nActualCount == nCount );
|
||||
|
||||
for ( int i = 0; i < nActualCount; ++i )
|
||||
{
|
||||
ParticleScriptParticle_t *pParticle = (ParticleScriptParticle_t*)ppParticles[i];
|
||||
if ( pParticle->m_nAttachment == nAttachment )
|
||||
{
|
||||
// Mark for deletion
|
||||
pParticle->m_nAttachment = -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void C_EnvParticleScript::DestroyAllParticles( )
|
||||
{
|
||||
int nCount = m_ParticleEffect.GetNumActiveParticles();
|
||||
Particle** ppParticles = (Particle**)stackalloc( nCount * sizeof(Particle*) );
|
||||
int nActualCount = m_ParticleEffect.GetActiveParticleList( nCount, ppParticles );
|
||||
Assert( nActualCount == nCount );
|
||||
|
||||
for ( int i = 0; i < nActualCount; ++i )
|
||||
{
|
||||
ParticleScriptParticle_t *pParticle = (ParticleScriptParticle_t*)ppParticles[i];
|
||||
|
||||
// Mark for deletion
|
||||
pParticle->m_nAttachment = -1;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// The animation events will create particles on the attachment points
|
||||
//-----------------------------------------------------------------------------
|
||||
void C_EnvParticleScript::FireEvent( const Vector& origin, const QAngle& angles, int event, const char *options )
|
||||
{
|
||||
// Handle events to create + destroy particles
|
||||
switch( event )
|
||||
{
|
||||
case CL_EVENT_SPRITEGROUP_CREATE:
|
||||
{
|
||||
char pAttachmentName[256];
|
||||
char pSpriteName[256];
|
||||
int nArgs = sscanf( options, "%255s %255s", pAttachmentName, pSpriteName );
|
||||
if ( nArgs == 2 )
|
||||
{
|
||||
CreateParticle( pAttachmentName, pSpriteName );
|
||||
}
|
||||
}
|
||||
return;
|
||||
|
||||
case CL_EVENT_SPRITEGROUP_DESTROY:
|
||||
{
|
||||
char pAttachmentName[256];
|
||||
int nArgs = sscanf( options, "%255s", pAttachmentName );
|
||||
if ( nArgs == 1 )
|
||||
{
|
||||
DestroyAllParticles( pAttachmentName );
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// Fall back
|
||||
BaseClass::FireEvent( origin, angles, event, options );
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Simulate the particles
|
||||
//-----------------------------------------------------------------------------
|
||||
void C_EnvParticleScript::RenderParticles( CParticleRenderIterator *pIterator )
|
||||
{
|
||||
const ParticleScriptParticle_t* pParticle = (const ParticleScriptParticle_t*)pIterator->GetFirst();
|
||||
while ( pParticle )
|
||||
{
|
||||
Vector vecRenderPos;
|
||||
TransformParticle( ParticleMgr()->GetModelView(), pParticle->m_Pos, vecRenderPos );
|
||||
float sortKey = vecRenderPos.z;
|
||||
|
||||
Vector color( 1, 1, 1 );
|
||||
RenderParticle_ColorSize( pIterator->GetParticleDraw(), vecRenderPos, color, 1.0f, pParticle->m_flSize );
|
||||
|
||||
pParticle = (const ParticleScriptParticle_t*)pIterator->GetNext( sortKey );
|
||||
}
|
||||
}
|
||||
|
||||
void C_EnvParticleScript::SimulateParticles( CParticleSimulateIterator *pIterator )
|
||||
{
|
||||
ParticleScriptParticle_t* pParticle = (ParticleScriptParticle_t*)pIterator->GetFirst();
|
||||
while ( pParticle )
|
||||
{
|
||||
// Here's how we retire particles
|
||||
if ( pParticle->m_nAttachment == -1 )
|
||||
{
|
||||
pIterator->RemoveParticle( pParticle );
|
||||
}
|
||||
else
|
||||
{
|
||||
// Move the particle to the attachment point
|
||||
QAngle vecAngles;
|
||||
GetAttachment( pParticle->m_nAttachment, pParticle->m_Pos, vecAngles );
|
||||
|
||||
if ( m_flSequenceScale != 1.0f )
|
||||
{
|
||||
pParticle->m_Pos -= GetAbsOrigin();
|
||||
pParticle->m_Pos *= m_flSequenceScale;
|
||||
pParticle->m_Pos += GetAbsOrigin();
|
||||
}
|
||||
}
|
||||
|
||||
pParticle = (ParticleScriptParticle_t*)pIterator->GetNext();
|
||||
}
|
||||
}
|
||||
|
||||
const Vector &C_EnvParticleScript::GetSortOrigin()
|
||||
{
|
||||
return GetAbsOrigin();
|
||||
}
|
||||
@@ -0,0 +1,236 @@
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
//=============================================================================
|
||||
|
||||
#include "cbase.h"
|
||||
#include "shareddefs.h"
|
||||
#include "materialsystem/imesh.h"
|
||||
#include "materialsystem/imaterial.h"
|
||||
#include "view.h"
|
||||
#include "iviewrender.h"
|
||||
#include "view_shared.h"
|
||||
#include "texture_group_names.h"
|
||||
#include "tier0/icommandline.h"
|
||||
|
||||
// memdbgon must be the last include file in a .cpp file!!!
|
||||
#include "tier0/memdbgon.h"
|
||||
|
||||
static ConVar mat_slopescaledepthbias_shadowmap( "mat_slopescaledepthbias_shadowmap", "16", FCVAR_CHEAT );
|
||||
static ConVar mat_depthbias_shadowmap( "mat_depthbias_shadowmap", "0.0005", FCVAR_CHEAT );
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
class C_EnvProjectedTexture : public C_BaseEntity
|
||||
{
|
||||
DECLARE_CLASS( C_EnvProjectedTexture, C_BaseEntity );
|
||||
public:
|
||||
DECLARE_CLIENTCLASS();
|
||||
|
||||
virtual void OnDataChanged( DataUpdateType_t updateType );
|
||||
void ShutDownLightHandle( void );
|
||||
|
||||
virtual void Simulate();
|
||||
|
||||
void UpdateLight( bool bForceUpdate );
|
||||
|
||||
C_EnvProjectedTexture();
|
||||
~C_EnvProjectedTexture();
|
||||
|
||||
private:
|
||||
|
||||
ClientShadowHandle_t m_LightHandle;
|
||||
|
||||
EHANDLE m_hTargetEntity;
|
||||
|
||||
bool m_bState;
|
||||
float m_flLightFOV;
|
||||
bool m_bEnableShadows;
|
||||
bool m_bLightOnlyTarget;
|
||||
bool m_bLightWorld;
|
||||
bool m_bCameraSpace;
|
||||
Vector m_LinearFloatLightColor;
|
||||
float m_flAmbient;
|
||||
float m_flNearZ;
|
||||
float m_flFarZ;
|
||||
char m_SpotlightTextureName[ MAX_PATH ];
|
||||
int m_nSpotlightTextureFrame;
|
||||
int m_nShadowQuality;
|
||||
};
|
||||
|
||||
IMPLEMENT_CLIENTCLASS_DT( C_EnvProjectedTexture, DT_EnvProjectedTexture, CEnvProjectedTexture )
|
||||
RecvPropEHandle( RECVINFO( m_hTargetEntity ) ),
|
||||
RecvPropBool( RECVINFO( m_bState ) ),
|
||||
RecvPropFloat( RECVINFO( m_flLightFOV ) ),
|
||||
RecvPropBool( RECVINFO( m_bEnableShadows ) ),
|
||||
RecvPropBool( RECVINFO( m_bLightOnlyTarget ) ),
|
||||
RecvPropBool( RECVINFO( m_bLightWorld ) ),
|
||||
RecvPropBool( RECVINFO( m_bCameraSpace ) ),
|
||||
RecvPropVector( RECVINFO( m_LinearFloatLightColor ) ),
|
||||
RecvPropFloat( RECVINFO( m_flAmbient ) ),
|
||||
RecvPropString( RECVINFO( m_SpotlightTextureName ) ),
|
||||
RecvPropInt( RECVINFO( m_nSpotlightTextureFrame ) ),
|
||||
RecvPropFloat( RECVINFO( m_flNearZ ) ),
|
||||
RecvPropFloat( RECVINFO( m_flFarZ ) ),
|
||||
RecvPropInt( RECVINFO( m_nShadowQuality ) ),
|
||||
END_RECV_TABLE()
|
||||
|
||||
C_EnvProjectedTexture::C_EnvProjectedTexture( void )
|
||||
{
|
||||
m_LightHandle = CLIENTSHADOW_INVALID_HANDLE;
|
||||
}
|
||||
|
||||
C_EnvProjectedTexture::~C_EnvProjectedTexture( void )
|
||||
{
|
||||
ShutDownLightHandle();
|
||||
}
|
||||
|
||||
void C_EnvProjectedTexture::ShutDownLightHandle( void )
|
||||
{
|
||||
// Clear out the light
|
||||
if( m_LightHandle != CLIENTSHADOW_INVALID_HANDLE )
|
||||
{
|
||||
g_pClientShadowMgr->DestroyFlashlight( m_LightHandle );
|
||||
m_LightHandle = CLIENTSHADOW_INVALID_HANDLE;
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
// Input : updateType -
|
||||
//-----------------------------------------------------------------------------
|
||||
void C_EnvProjectedTexture::OnDataChanged( DataUpdateType_t updateType )
|
||||
{
|
||||
UpdateLight( true );
|
||||
BaseClass::OnDataChanged( updateType );
|
||||
}
|
||||
|
||||
void C_EnvProjectedTexture::UpdateLight( bool bForceUpdate )
|
||||
{
|
||||
if ( m_bState == false )
|
||||
{
|
||||
if ( m_LightHandle != CLIENTSHADOW_INVALID_HANDLE )
|
||||
{
|
||||
ShutDownLightHandle();
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
Vector vForward, vRight, vUp, vPos = GetAbsOrigin();
|
||||
FlashlightState_t state;
|
||||
|
||||
if ( m_hTargetEntity != NULL )
|
||||
{
|
||||
if ( m_bCameraSpace )
|
||||
{
|
||||
const QAngle &angles = GetLocalAngles();
|
||||
|
||||
C_BasePlayer *pPlayer = C_BasePlayer::GetLocalPlayer();
|
||||
if( pPlayer )
|
||||
{
|
||||
const QAngle playerAngles = pPlayer->GetAbsAngles();
|
||||
|
||||
Vector vPlayerForward, vPlayerRight, vPlayerUp;
|
||||
AngleVectors( playerAngles, &vPlayerForward, &vPlayerRight, &vPlayerUp );
|
||||
|
||||
matrix3x4_t mRotMatrix;
|
||||
AngleMatrix( angles, mRotMatrix );
|
||||
|
||||
VectorITransform( vPlayerForward, mRotMatrix, vForward );
|
||||
VectorITransform( vPlayerRight, mRotMatrix, vRight );
|
||||
VectorITransform( vPlayerUp, mRotMatrix, vUp );
|
||||
|
||||
float dist = (m_hTargetEntity->GetAbsOrigin() - GetAbsOrigin()).Length();
|
||||
vPos = m_hTargetEntity->GetAbsOrigin() - vForward*dist;
|
||||
|
||||
VectorNormalize( vForward );
|
||||
VectorNormalize( vRight );
|
||||
VectorNormalize( vUp );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
vForward = m_hTargetEntity->GetAbsOrigin() - GetAbsOrigin();
|
||||
VectorNormalize( vForward );
|
||||
|
||||
// JasonM - unimplemented
|
||||
Assert (0);
|
||||
|
||||
//Quaternion q = DirectionToOrientation( dir );
|
||||
|
||||
|
||||
//
|
||||
// JasonM - set up vRight, vUp
|
||||
//
|
||||
|
||||
// VectorNormalize( vRight );
|
||||
// VectorNormalize( vUp );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
AngleVectors( GetAbsAngles(), &vForward, &vRight, &vUp );
|
||||
}
|
||||
|
||||
state.m_fHorizontalFOVDegrees = m_flLightFOV;
|
||||
state.m_fVerticalFOVDegrees = m_flLightFOV;
|
||||
|
||||
state.m_vecLightOrigin = vPos;
|
||||
BasisToQuaternion( vForward, vRight, vUp, state.m_quatOrientation );
|
||||
|
||||
state.m_fQuadraticAtten = 0.0;
|
||||
state.m_fLinearAtten = 100;
|
||||
state.m_fConstantAtten = 0.0f;
|
||||
state.m_Color[0] = m_LinearFloatLightColor.x;
|
||||
state.m_Color[1] = m_LinearFloatLightColor.y;
|
||||
state.m_Color[2] = m_LinearFloatLightColor.z;
|
||||
state.m_Color[3] = 0.0f; // fixme: need to make ambient work m_flAmbient;
|
||||
state.m_NearZ = m_flNearZ;
|
||||
state.m_FarZ = m_flFarZ;
|
||||
state.m_flShadowSlopeScaleDepthBias = mat_slopescaledepthbias_shadowmap.GetFloat();
|
||||
state.m_flShadowDepthBias = mat_depthbias_shadowmap.GetFloat();
|
||||
state.m_bEnableShadows = m_bEnableShadows;
|
||||
state.m_pSpotlightTexture = materials->FindTexture( m_SpotlightTextureName, TEXTURE_GROUP_OTHER, false );
|
||||
state.m_nSpotlightTextureFrame = m_nSpotlightTextureFrame;
|
||||
|
||||
state.m_nShadowQuality = m_nShadowQuality; // Allow entity to affect shadow quality
|
||||
|
||||
if( m_LightHandle == CLIENTSHADOW_INVALID_HANDLE )
|
||||
{
|
||||
m_LightHandle = g_pClientShadowMgr->CreateFlashlight( state );
|
||||
}
|
||||
else
|
||||
{
|
||||
if ( m_hTargetEntity != NULL || bForceUpdate == true )
|
||||
{
|
||||
g_pClientShadowMgr->UpdateFlashlightState( m_LightHandle, state );
|
||||
}
|
||||
}
|
||||
|
||||
if( m_bLightOnlyTarget )
|
||||
{
|
||||
g_pClientShadowMgr->SetFlashlightTarget( m_LightHandle, m_hTargetEntity );
|
||||
}
|
||||
else
|
||||
{
|
||||
g_pClientShadowMgr->SetFlashlightTarget( m_LightHandle, NULL );
|
||||
}
|
||||
|
||||
g_pClientShadowMgr->SetFlashlightLightWorld( m_LightHandle, m_bLightWorld );
|
||||
|
||||
if ( bForceUpdate == false )
|
||||
{
|
||||
g_pClientShadowMgr->UpdateProjectedTexture( m_LightHandle, true );
|
||||
}
|
||||
}
|
||||
|
||||
void C_EnvProjectedTexture::Simulate( void )
|
||||
{
|
||||
UpdateLight( false );
|
||||
|
||||
BaseClass::Simulate();
|
||||
}
|
||||
|
||||
@@ -0,0 +1,327 @@
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
//=============================================================================//
|
||||
|
||||
#include "cbase.h"
|
||||
#include "shareddefs.h"
|
||||
#include "materialsystem/imesh.h"
|
||||
#include "materialsystem/imaterial.h"
|
||||
#include "view.h"
|
||||
#include "iviewrender.h"
|
||||
#include "view_shared.h"
|
||||
#include "texture_group_names.h"
|
||||
#include "tier0/icommandline.h"
|
||||
#include "KeyValues.h"
|
||||
#include "ScreenSpaceEffects.h"
|
||||
#include "materialsystem/imaterialsystemhardwareconfig.h"
|
||||
|
||||
// memdbgon must be the last include file in a .cpp file!!!
|
||||
#include "tier0/memdbgon.h"
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
class C_EnvScreenOverlay : public C_BaseEntity
|
||||
{
|
||||
DECLARE_CLASS( C_EnvScreenOverlay, C_BaseEntity );
|
||||
public:
|
||||
DECLARE_CLIENTCLASS();
|
||||
|
||||
void PreDataUpdate( DataUpdateType_t updateType );
|
||||
void PostDataUpdate( DataUpdateType_t updateType );
|
||||
|
||||
void HandleOverlaySwitch( void );
|
||||
void StartOverlays( void );
|
||||
void StopOverlays( void );
|
||||
void StartCurrentOverlay( void );
|
||||
void ClientThink( void );
|
||||
|
||||
protected:
|
||||
char m_iszOverlayNames[ MAX_SCREEN_OVERLAYS ][255];
|
||||
float m_flOverlayTimes[ MAX_SCREEN_OVERLAYS ];
|
||||
float m_flStartTime;
|
||||
int m_iDesiredOverlay;
|
||||
bool m_bIsActive;
|
||||
bool m_bWasActive;
|
||||
int m_iCachedDesiredOverlay;
|
||||
int m_iCurrentOverlay;
|
||||
float m_flCurrentOverlayTime;
|
||||
};
|
||||
|
||||
IMPLEMENT_CLIENTCLASS_DT( C_EnvScreenOverlay, DT_EnvScreenOverlay, CEnvScreenOverlay )
|
||||
RecvPropArray( RecvPropString( RECVINFO( m_iszOverlayNames[0]) ), m_iszOverlayNames ),
|
||||
RecvPropArray( RecvPropFloat( RECVINFO( m_flOverlayTimes[0] ) ), m_flOverlayTimes ),
|
||||
RecvPropFloat( RECVINFO( m_flStartTime ) ),
|
||||
RecvPropInt( RECVINFO( m_iDesiredOverlay ) ),
|
||||
RecvPropBool( RECVINFO( m_bIsActive ) ),
|
||||
END_RECV_TABLE()
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
// Input : updateType -
|
||||
//-----------------------------------------------------------------------------
|
||||
void C_EnvScreenOverlay::PreDataUpdate( DataUpdateType_t updateType )
|
||||
{
|
||||
BaseClass::PreDataUpdate( updateType );
|
||||
|
||||
m_bWasActive = m_bIsActive;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
void C_EnvScreenOverlay::PostDataUpdate( DataUpdateType_t updateType )
|
||||
{
|
||||
BaseClass::PostDataUpdate( updateType );
|
||||
|
||||
// If we have a start time now, start the overlays going
|
||||
if ( m_bIsActive && m_flStartTime > 0 && view->GetScreenOverlayMaterial() == NULL )
|
||||
{
|
||||
StartOverlays();
|
||||
}
|
||||
|
||||
if ( m_flStartTime == -1 )
|
||||
{
|
||||
StopOverlays();
|
||||
}
|
||||
|
||||
HandleOverlaySwitch();
|
||||
|
||||
if ( updateType == DATA_UPDATE_CREATED &&
|
||||
CommandLine()->FindParm( "-makereslists" ) )
|
||||
{
|
||||
for ( int i = 0; i < MAX_SCREEN_OVERLAYS; ++i )
|
||||
{
|
||||
if ( m_iszOverlayNames[ i ] && m_iszOverlayNames[ i ][ 0 ] )
|
||||
{
|
||||
materials->FindMaterial( m_iszOverlayNames[ i ], TEXTURE_GROUP_CLIENT_EFFECTS, false );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
void C_EnvScreenOverlay::StopOverlays( void )
|
||||
{
|
||||
SetNextClientThink( CLIENT_THINK_NEVER );
|
||||
|
||||
if ( m_bWasActive && !m_bIsActive )
|
||||
{
|
||||
view->SetScreenOverlayMaterial( NULL );
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
void C_EnvScreenOverlay::StartOverlays( void )
|
||||
{
|
||||
m_iCurrentOverlay = 0;
|
||||
m_flCurrentOverlayTime = 0;
|
||||
m_iCachedDesiredOverlay = 0;
|
||||
SetNextClientThink( CLIENT_THINK_ALWAYS );
|
||||
|
||||
StartCurrentOverlay();
|
||||
HandleOverlaySwitch();
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
void C_EnvScreenOverlay::HandleOverlaySwitch( void )
|
||||
{
|
||||
if( m_iCachedDesiredOverlay != m_iDesiredOverlay )
|
||||
{
|
||||
m_iCurrentOverlay = m_iDesiredOverlay;
|
||||
m_iCachedDesiredOverlay = m_iDesiredOverlay;
|
||||
StartCurrentOverlay();
|
||||
}
|
||||
}
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
void C_EnvScreenOverlay::StartCurrentOverlay( void )
|
||||
{
|
||||
if ( m_iCurrentOverlay == MAX_SCREEN_OVERLAYS || !m_iszOverlayNames[m_iCurrentOverlay] || !m_iszOverlayNames[m_iCurrentOverlay][0] )
|
||||
{
|
||||
// Hit the end of our overlays, so stop.
|
||||
m_flStartTime = 0;
|
||||
StopOverlays();
|
||||
return;
|
||||
}
|
||||
|
||||
if ( m_flOverlayTimes[m_iCurrentOverlay] == -1 )
|
||||
m_flCurrentOverlayTime = -1;
|
||||
else
|
||||
m_flCurrentOverlayTime = gpGlobals->curtime + m_flOverlayTimes[m_iCurrentOverlay];
|
||||
|
||||
// Bring up the current overlay
|
||||
IMaterial *pMaterial = materials->FindMaterial( m_iszOverlayNames[m_iCurrentOverlay], TEXTURE_GROUP_CLIENT_EFFECTS, false );
|
||||
if ( !IsErrorMaterial( pMaterial ) )
|
||||
{
|
||||
view->SetScreenOverlayMaterial( pMaterial );
|
||||
}
|
||||
else
|
||||
{
|
||||
Warning("env_screenoverlay couldn't find overlay %s.\n", m_iszOverlayNames[m_iCurrentOverlay] );
|
||||
StopOverlays();
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
void C_EnvScreenOverlay::ClientThink( void )
|
||||
{
|
||||
// If the current overlay's run out, go to the next one
|
||||
if ( m_flCurrentOverlayTime != -1 && m_flCurrentOverlayTime < gpGlobals->curtime )
|
||||
{
|
||||
m_iCurrentOverlay++;
|
||||
StartCurrentOverlay();
|
||||
}
|
||||
}
|
||||
|
||||
// Effect types
|
||||
enum
|
||||
{
|
||||
SCREENEFFECT_EP2_ADVISOR_STUN,
|
||||
SCREENEFFECT_EP1_INTRO,
|
||||
SCREENEFFECT_EP2_GROGGY,
|
||||
};
|
||||
|
||||
// ============================================================================
|
||||
// Screenspace effect
|
||||
// ============================================================================
|
||||
|
||||
class C_EnvScreenEffect : public C_BaseEntity
|
||||
{
|
||||
DECLARE_CLASS( C_EnvScreenEffect, C_BaseEntity );
|
||||
public:
|
||||
DECLARE_CLIENTCLASS();
|
||||
|
||||
virtual void ReceiveMessage( int classID, bf_read &msg );
|
||||
|
||||
private:
|
||||
float m_flDuration;
|
||||
int m_nType;
|
||||
};
|
||||
|
||||
IMPLEMENT_CLIENTCLASS_DT( C_EnvScreenEffect, DT_EnvScreenEffect, CEnvScreenEffect )
|
||||
RecvPropFloat( RECVINFO( m_flDuration ) ),
|
||||
RecvPropInt( RECVINFO( m_nType ) ),
|
||||
END_RECV_TABLE()
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
// Input : classID -
|
||||
// &msg -
|
||||
//-----------------------------------------------------------------------------
|
||||
void C_EnvScreenEffect::ReceiveMessage( int classID, bf_read &msg )
|
||||
{
|
||||
// Make sure our IDs match
|
||||
if ( classID != GetClientClass()->m_ClassID )
|
||||
{
|
||||
// Message is for subclass
|
||||
BaseClass::ReceiveMessage( classID, msg );
|
||||
return;
|
||||
}
|
||||
|
||||
int messageType = msg.ReadByte();
|
||||
switch( messageType )
|
||||
{
|
||||
// Effect turning on
|
||||
case 0: // FIXME: Declare
|
||||
{
|
||||
// Create a keyvalue block to set these params
|
||||
KeyValues *pKeys = new KeyValues( "keys" );
|
||||
if ( pKeys == NULL )
|
||||
return;
|
||||
|
||||
if ( m_nType == SCREENEFFECT_EP1_INTRO )
|
||||
{
|
||||
if( g_pMaterialSystemHardwareConfig->GetDXSupportLevel() < 80 )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// Set our keys
|
||||
pKeys->SetFloat( "duration", m_flDuration );
|
||||
pKeys->SetInt( "fadeout", 0 );
|
||||
|
||||
g_pScreenSpaceEffects->SetScreenSpaceEffectParams( "episodic_intro", pKeys );
|
||||
g_pScreenSpaceEffects->EnableScreenSpaceEffect( "episodic_intro" );
|
||||
}
|
||||
else if ( m_nType == SCREENEFFECT_EP2_ADVISOR_STUN )
|
||||
{
|
||||
// Set our keys
|
||||
pKeys->SetFloat( "duration", m_flDuration );
|
||||
|
||||
g_pScreenSpaceEffects->SetScreenSpaceEffectParams( "episodic_stun", pKeys );
|
||||
g_pScreenSpaceEffects->EnableScreenSpaceEffect( "episodic_stun" );
|
||||
}
|
||||
else if ( m_nType == SCREENEFFECT_EP2_GROGGY )
|
||||
{
|
||||
if( g_pMaterialSystemHardwareConfig->GetDXSupportLevel() < 80 )
|
||||
return;
|
||||
|
||||
// Set our keys
|
||||
pKeys->SetFloat( "duration", m_flDuration );
|
||||
pKeys->SetInt( "fadeout", 0 );
|
||||
|
||||
g_pScreenSpaceEffects->SetScreenSpaceEffectParams( "ep2_groggy", pKeys );
|
||||
g_pScreenSpaceEffects->EnableScreenSpaceEffect( "ep2_groggy" );
|
||||
}
|
||||
|
||||
pKeys->deleteThis();
|
||||
}
|
||||
break;
|
||||
|
||||
// Effect turning off
|
||||
case 1: // FIXME: Declare
|
||||
|
||||
if ( m_nType == SCREENEFFECT_EP1_INTRO )
|
||||
{
|
||||
if( g_pMaterialSystemHardwareConfig->GetDXSupportLevel() < 80 )
|
||||
{
|
||||
return;
|
||||
}
|
||||
// Create a keyvalue block to set these params
|
||||
KeyValues *pKeys = new KeyValues( "keys" );
|
||||
if ( pKeys == NULL )
|
||||
return;
|
||||
|
||||
// Set our keys
|
||||
pKeys->SetFloat( "duration", m_flDuration );
|
||||
pKeys->SetInt( "fadeout", 1 );
|
||||
|
||||
g_pScreenSpaceEffects->SetScreenSpaceEffectParams( "episodic_intro", pKeys );
|
||||
}
|
||||
else if ( m_nType == SCREENEFFECT_EP2_ADVISOR_STUN )
|
||||
{
|
||||
g_pScreenSpaceEffects->DisableScreenSpaceEffect( "episodic_stun" );
|
||||
}
|
||||
else if ( m_nType == SCREENEFFECT_EP2_GROGGY )
|
||||
{
|
||||
if( g_pMaterialSystemHardwareConfig->GetDXSupportLevel() < 80 )
|
||||
{
|
||||
return;
|
||||
}
|
||||
// Create a keyvalue block to set these params
|
||||
KeyValues *pKeys = new KeyValues( "keys" );
|
||||
if ( pKeys == NULL )
|
||||
return;
|
||||
|
||||
// Set our keys
|
||||
pKeys->SetFloat( "duration", m_flDuration );
|
||||
pKeys->SetInt( "fadeout", 1 );
|
||||
|
||||
g_pScreenSpaceEffects->SetScreenSpaceEffectParams( "ep2_groggy", pKeys );
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,97 @@
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
//=============================================================================
|
||||
#include "cbase.h"
|
||||
|
||||
extern bool g_bUseCustomAutoExposureMin;
|
||||
extern bool g_bUseCustomAutoExposureMax;
|
||||
extern bool g_bUseCustomBloomScale;
|
||||
extern float g_flCustomAutoExposureMin;
|
||||
extern float g_flCustomAutoExposureMax;
|
||||
extern float g_flCustomBloomScale;
|
||||
extern float g_flCustomBloomScaleMinimum;
|
||||
|
||||
EHANDLE g_hTonemapControllerInUse = NULL;
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
class C_EnvTonemapController : public C_BaseEntity
|
||||
{
|
||||
DECLARE_CLASS( C_EnvTonemapController, C_BaseEntity );
|
||||
public:
|
||||
DECLARE_CLIENTCLASS();
|
||||
|
||||
C_EnvTonemapController();
|
||||
~C_EnvTonemapController();
|
||||
virtual void OnDataChanged( DataUpdateType_t updateType );
|
||||
|
||||
private:
|
||||
bool m_bUseCustomAutoExposureMin;
|
||||
bool m_bUseCustomAutoExposureMax;
|
||||
bool m_bUseCustomBloomScale;
|
||||
float m_flCustomAutoExposureMin;
|
||||
float m_flCustomAutoExposureMax;
|
||||
float m_flCustomBloomScale;
|
||||
float m_flCustomBloomScaleMinimum;
|
||||
private:
|
||||
C_EnvTonemapController( const C_EnvTonemapController & );
|
||||
};
|
||||
|
||||
IMPLEMENT_CLIENTCLASS_DT( C_EnvTonemapController, DT_EnvTonemapController, CEnvTonemapController )
|
||||
RecvPropInt( RECVINFO(m_bUseCustomAutoExposureMin) ),
|
||||
RecvPropInt( RECVINFO(m_bUseCustomAutoExposureMax) ),
|
||||
RecvPropInt( RECVINFO(m_bUseCustomBloomScale) ),
|
||||
RecvPropFloat( RECVINFO(m_flCustomAutoExposureMin) ),
|
||||
RecvPropFloat( RECVINFO(m_flCustomAutoExposureMax) ),
|
||||
RecvPropFloat( RECVINFO(m_flCustomBloomScale) ),
|
||||
RecvPropFloat( RECVINFO(m_flCustomBloomScaleMinimum) ),
|
||||
END_RECV_TABLE()
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
C_EnvTonemapController::C_EnvTonemapController( void )
|
||||
{
|
||||
m_bUseCustomAutoExposureMin = false;
|
||||
m_bUseCustomAutoExposureMax = false;
|
||||
m_bUseCustomBloomScale = false;
|
||||
m_flCustomAutoExposureMin = 0;
|
||||
m_flCustomAutoExposureMax = 0;
|
||||
m_flCustomBloomScale = 0.0f;
|
||||
m_flCustomBloomScaleMinimum = 0.0f;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
C_EnvTonemapController::~C_EnvTonemapController( void )
|
||||
{
|
||||
if ( g_hTonemapControllerInUse == this )
|
||||
{
|
||||
g_bUseCustomAutoExposureMin = false;
|
||||
g_bUseCustomAutoExposureMax = false;
|
||||
g_bUseCustomBloomScale = false;
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
void C_EnvTonemapController::OnDataChanged( DataUpdateType_t updateType )
|
||||
{
|
||||
BaseClass::OnDataChanged(updateType);
|
||||
|
||||
g_bUseCustomAutoExposureMin = m_bUseCustomAutoExposureMin;
|
||||
g_bUseCustomAutoExposureMax = m_bUseCustomAutoExposureMax;
|
||||
g_bUseCustomBloomScale = m_bUseCustomBloomScale;
|
||||
g_flCustomAutoExposureMin = m_flCustomAutoExposureMin;
|
||||
g_flCustomAutoExposureMax = m_flCustomAutoExposureMax;
|
||||
g_flCustomBloomScale = m_flCustomBloomScale;
|
||||
g_flCustomBloomScaleMinimum = m_flCustomBloomScaleMinimum;
|
||||
|
||||
g_hTonemapControllerInUse = this;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,409 @@
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
// $NoKeywords: $
|
||||
//=============================================================================//
|
||||
#include "cbase.h"
|
||||
#include "iviewrender.h"
|
||||
#include "clienteffectprecachesystem.h"
|
||||
#include "studio.h"
|
||||
#include "bone_setup.h"
|
||||
#include "engine/ivmodelinfo.h"
|
||||
#include "c_fire_smoke.h"
|
||||
#include "engine/IEngineSound.h"
|
||||
#include "iefx.h"
|
||||
#include "dlight.h"
|
||||
#include "tier0/icommandline.h"
|
||||
|
||||
// memdbgon must be the last include file in a .cpp file!!!
|
||||
#include "tier0/memdbgon.h"
|
||||
|
||||
|
||||
CLIENTEFFECT_REGISTER_BEGIN( SmokeStackMaterials )
|
||||
CLIENTEFFECT_MATERIAL( "particle/SmokeStack" )
|
||||
CLIENTEFFECT_REGISTER_END()
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
// Input : *pRecvProp -
|
||||
// *pStruct -
|
||||
// *pVarData -
|
||||
// *pIn -
|
||||
// objectID -
|
||||
//-----------------------------------------------------------------------------
|
||||
void RecvProxy_Scale( const CRecvProxyData *pData, void *pStruct, void *pOut )
|
||||
{
|
||||
C_FireSmoke *pFireSmoke = (C_FireSmoke *) pStruct;
|
||||
float scale = pData->m_Value.m_Float;
|
||||
|
||||
//If changed, update our internal information
|
||||
if ( ( pFireSmoke->m_flScale != scale ) && ( pFireSmoke->m_flScaleEnd != scale ) )
|
||||
{
|
||||
pFireSmoke->m_flScaleStart = pFireSmoke->m_flScaleRegister;
|
||||
pFireSmoke->m_flScaleEnd = scale;
|
||||
}
|
||||
|
||||
pFireSmoke->m_flScale = scale;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
// Input : *pRecvProp -
|
||||
// *pStruct -
|
||||
// *pVarData -
|
||||
// *pIn -
|
||||
// objectID -
|
||||
//-----------------------------------------------------------------------------
|
||||
void RecvProxy_ScaleTime( const CRecvProxyData *pData, void *pStruct, void *pOut )
|
||||
{
|
||||
C_FireSmoke *pFireSmoke = (C_FireSmoke *) pStruct;
|
||||
float time = pData->m_Value.m_Float;
|
||||
|
||||
//If changed, update our internal information
|
||||
//if ( pFireSmoke->m_flScaleTime != time )
|
||||
{
|
||||
if ( time == -1.0f )
|
||||
{
|
||||
pFireSmoke->m_flScaleTimeStart = Helper_GetTime()-1.0f;
|
||||
pFireSmoke->m_flScaleTimeEnd = pFireSmoke->m_flScaleTimeStart;
|
||||
}
|
||||
else
|
||||
{
|
||||
pFireSmoke->m_flScaleTimeStart = Helper_GetTime();
|
||||
pFireSmoke->m_flScaleTimeEnd = Helper_GetTime() + time;
|
||||
}
|
||||
}
|
||||
|
||||
pFireSmoke->m_flScaleTime = time;
|
||||
}
|
||||
|
||||
//Receive datatable
|
||||
IMPLEMENT_CLIENTCLASS_DT( C_FireSmoke, DT_FireSmoke, CFireSmoke )
|
||||
RecvPropFloat( RECVINFO( m_flStartScale )),
|
||||
RecvPropFloat( RECVINFO( m_flScale ), 0, RecvProxy_Scale ),
|
||||
RecvPropFloat( RECVINFO( m_flScaleTime ), 0, RecvProxy_ScaleTime ),
|
||||
RecvPropInt( RECVINFO( m_nFlags ) ),
|
||||
RecvPropInt( RECVINFO( m_nFlameModelIndex ) ),
|
||||
RecvPropInt( RECVINFO( m_nFlameFromAboveModelIndex ) ),
|
||||
END_RECV_TABLE()
|
||||
|
||||
//==================================================
|
||||
// C_FireSmoke
|
||||
//==================================================
|
||||
|
||||
C_FireSmoke::C_FireSmoke()
|
||||
{
|
||||
}
|
||||
|
||||
C_FireSmoke::~C_FireSmoke()
|
||||
{
|
||||
|
||||
// Shut down our effect if we have it
|
||||
if ( m_hEffect )
|
||||
{
|
||||
m_hEffect->StopEmission(false, false , true);
|
||||
m_hEffect = NULL;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
void C_FireSmoke::Simulate( void )
|
||||
{
|
||||
}
|
||||
|
||||
#define FLAME_ALPHA_START 0.9f
|
||||
#define FLAME_ALPHA_END 1.0f
|
||||
|
||||
#define FLAME_TRANS_START 0.75f
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
void C_FireSmoke::AddFlames( void )
|
||||
{
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
// Input : bnewentity -
|
||||
//-----------------------------------------------------------------------------
|
||||
void C_FireSmoke::OnDataChanged( DataUpdateType_t updateType )
|
||||
{
|
||||
BaseClass::OnDataChanged( updateType );
|
||||
|
||||
|
||||
if ( updateType == DATA_UPDATE_CREATED )
|
||||
{
|
||||
Start();
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
void C_FireSmoke::UpdateEffects( void )
|
||||
{
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
// Output : Returns true on success, false on failure.
|
||||
//-----------------------------------------------------------------------------
|
||||
bool C_FireSmoke::ShouldDraw()
|
||||
{
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
void C_FireSmoke::Start( void )
|
||||
{
|
||||
const char *lpszEffectName;
|
||||
int nSize = (int) floor( m_flStartScale / 36.0f );
|
||||
switch ( nSize )
|
||||
{
|
||||
case 0:
|
||||
lpszEffectName = ( m_nFlags & bitsFIRESMOKE_SMOKE ) ? "env_fire_tiny_smoke" : "env_fire_tiny";
|
||||
break;
|
||||
|
||||
case 1:
|
||||
lpszEffectName = ( m_nFlags & bitsFIRESMOKE_SMOKE ) ? "env_fire_small_smoke" : "env_fire_small";
|
||||
break;
|
||||
|
||||
case 2:
|
||||
lpszEffectName = ( m_nFlags & bitsFIRESMOKE_SMOKE ) ? "env_fire_medium_smoke" : "env_fire_medium";
|
||||
break;
|
||||
|
||||
case 3:
|
||||
default:
|
||||
lpszEffectName = ( m_nFlags & bitsFIRESMOKE_SMOKE ) ? "env_fire_large_smoke" : "env_fire_large";
|
||||
break;
|
||||
}
|
||||
|
||||
// Create the effect of the correct size
|
||||
m_hEffect = ParticleProp()->Create( lpszEffectName, PATTACH_ABSORIGIN );
|
||||
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: FIXME: what's the right way to do this?
|
||||
//-----------------------------------------------------------------------------
|
||||
void C_FireSmoke::StartClientOnly( void )
|
||||
{
|
||||
Start();
|
||||
|
||||
ClientEntityList().AddNonNetworkableEntity( this );
|
||||
CollisionProp()->CreatePartitionHandle();
|
||||
AddEffects( EF_NORECEIVESHADOW | EF_NOSHADOW );
|
||||
AddToLeafSystem();
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
void C_FireSmoke::RemoveClientOnly(void)
|
||||
{
|
||||
ClientThinkList()->RemoveThinkable( GetClientHandle() );
|
||||
|
||||
// Remove from the client entity list.
|
||||
ClientEntityList().RemoveEntity( GetClientHandle() );
|
||||
|
||||
::partition->Remove( PARTITION_CLIENT_SOLID_EDICTS | PARTITION_CLIENT_RESPONSIVE_EDICTS | PARTITION_CLIENT_NON_STATIC_EDICTS, CollisionProp()->GetPartitionHandle() );
|
||||
|
||||
RemoveFromLeafSystem();
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
void C_FireSmoke::UpdateAnimation( void )
|
||||
{
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
void C_FireSmoke::UpdateFlames( void )
|
||||
{
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
void C_FireSmoke::UpdateScale( void )
|
||||
{
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
void C_FireSmoke::Update( void )
|
||||
{
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
void C_FireSmoke::FindClipPlane( void )
|
||||
{
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Spawn smoke (...duh)
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
void C_FireSmoke::SpawnSmoke( void )
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
IMPLEMENT_CLIENTCLASS_DT( C_EntityFlame, DT_EntityFlame, CEntityFlame )
|
||||
RecvPropEHandle(RECVINFO(m_hEntAttached)),
|
||||
END_RECV_TABLE()
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
C_EntityFlame::C_EntityFlame( void ) :
|
||||
m_hEffect( NULL )
|
||||
{
|
||||
m_hOldAttached = NULL;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
C_EntityFlame::~C_EntityFlame( void )
|
||||
{
|
||||
StopEffect();
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
void C_EntityFlame::StopEffect( void )
|
||||
{
|
||||
if ( m_hEffect )
|
||||
{
|
||||
ParticleProp()->StopEmission( m_hEffect, true );
|
||||
m_hEffect->SetControlPointEntity( 0, NULL );
|
||||
m_hEffect->SetControlPointEntity( 1, NULL );
|
||||
m_hEffect = NULL;
|
||||
}
|
||||
|
||||
if ( m_hEntAttached )
|
||||
{
|
||||
m_hEntAttached->RemoveFlag( FL_ONFIRE );
|
||||
m_hEntAttached->SetEffectEntity( NULL );
|
||||
m_hEntAttached->StopSound( "General.BurningFlesh" );
|
||||
m_hEntAttached->StopSound( "General.BurningObject" );
|
||||
|
||||
|
||||
m_hEntAttached = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
void C_EntityFlame::UpdateOnRemove( void )
|
||||
{
|
||||
StopEffect();
|
||||
BaseClass::UpdateOnRemove();
|
||||
}
|
||||
|
||||
void C_EntityFlame::CreateEffect( void )
|
||||
{
|
||||
if ( m_hEffect )
|
||||
{
|
||||
ParticleProp()->StopEmission( m_hEffect, true );
|
||||
m_hEffect->SetControlPointEntity( 0, NULL );
|
||||
m_hEffect->SetControlPointEntity( 1, NULL );
|
||||
m_hEffect = NULL;
|
||||
}
|
||||
|
||||
#ifdef TF_CLIENT_DLL
|
||||
m_hEffect = ParticleProp()->Create( "burningplayer_red", PATTACH_ABSORIGIN_FOLLOW );
|
||||
#else
|
||||
m_hEffect = ParticleProp()->Create( "burning_character", PATTACH_ABSORIGIN_FOLLOW );
|
||||
#endif
|
||||
|
||||
if ( m_hEffect )
|
||||
{
|
||||
C_BaseEntity *pEntity = m_hEntAttached;
|
||||
m_hOldAttached = m_hEntAttached;
|
||||
|
||||
ParticleProp()->AddControlPoint( m_hEffect, 1, pEntity, PATTACH_ABSORIGIN_FOLLOW );
|
||||
m_hEffect->SetControlPoint( 0, GetAbsOrigin() );
|
||||
m_hEffect->SetControlPoint( 1, GetAbsOrigin() );
|
||||
m_hEffect->SetControlPointEntity( 0, pEntity );
|
||||
m_hEffect->SetControlPointEntity( 1, pEntity );
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
void C_EntityFlame::OnDataChanged( DataUpdateType_t updateType )
|
||||
{
|
||||
if ( updateType == DATA_UPDATE_CREATED )
|
||||
{
|
||||
CreateEffect();
|
||||
}
|
||||
|
||||
// FIXME: This is a bit of a shady path
|
||||
if ( updateType == DATA_UPDATE_DATATABLE_CHANGED )
|
||||
{
|
||||
// If our owner changed, then recreate the effect
|
||||
if ( m_hEntAttached != m_hOldAttached )
|
||||
{
|
||||
CreateEffect();
|
||||
}
|
||||
}
|
||||
|
||||
BaseClass::OnDataChanged( updateType );
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
void C_EntityFlame::Simulate( void )
|
||||
{
|
||||
if ( gpGlobals->frametime <= 0.0f )
|
||||
return;
|
||||
|
||||
#ifdef HL2_EPISODIC
|
||||
|
||||
if ( IsEffectActive(EF_BRIGHTLIGHT) || IsEffectActive(EF_DIMLIGHT) )
|
||||
{
|
||||
dlight_t *dl = effects->CL_AllocDlight ( index );
|
||||
dl->origin = GetAbsOrigin();
|
||||
dl->origin[2] += 16;
|
||||
dl->color.r = 254;
|
||||
dl->color.g = 174;
|
||||
dl->color.b = 10;
|
||||
dl->radius = random->RandomFloat(400,431);
|
||||
dl->die = gpGlobals->curtime + 0.001;
|
||||
}
|
||||
|
||||
#endif // HL2_EPISODIC
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
void C_EntityFlame::ClientThink( void )
|
||||
{
|
||||
StopEffect();
|
||||
Release();
|
||||
}
|
||||
@@ -0,0 +1,302 @@
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
// $NoKeywords: $
|
||||
//
|
||||
//=============================================================================//
|
||||
#ifndef C_FIRE_SMOKE_H
|
||||
#define C_FIRE_SMOKE_H
|
||||
|
||||
#include "particles_simple.h"
|
||||
#include "tempent.h"
|
||||
#include "glow_overlay.h"
|
||||
#include "view.h"
|
||||
#include "particle_litsmokeemitter.h"
|
||||
|
||||
class CFireOverlay;
|
||||
|
||||
class C_FireSprite : public C_Sprite
|
||||
{
|
||||
DECLARE_CLASS( C_FireSprite, C_Sprite );
|
||||
|
||||
private:
|
||||
virtual int DrawModel( int flags )
|
||||
{
|
||||
if ( m_bFadeFromAbove )
|
||||
{
|
||||
// The sprites become less visible the more you look down or up at them
|
||||
Vector vToPos = GetLocalOrigin() - CurrentViewOrigin();
|
||||
VectorNormalize( vToPos );
|
||||
|
||||
float fUpAmount = vToPos.z;
|
||||
|
||||
int iAlpha = 255;
|
||||
|
||||
if ( fUpAmount < -0.75f )
|
||||
iAlpha = 0;
|
||||
else if ( fUpAmount < -0.65f )
|
||||
iAlpha = 255 - (int)( ( fUpAmount + 0.65f ) * 10.0f * -255.0f );
|
||||
else if ( fUpAmount > 0.85f )
|
||||
iAlpha = 0;
|
||||
else if ( fUpAmount > 0.75f )
|
||||
iAlpha = 255 - (int)( ( fUpAmount - 0.75f ) * 10.0f * 255.0f );
|
||||
|
||||
SetColor( iAlpha, iAlpha, iAlpha );
|
||||
}
|
||||
|
||||
return BaseClass::DrawModel( flags );
|
||||
}
|
||||
|
||||
public:
|
||||
Vector m_vecMoveDir;
|
||||
bool m_bFadeFromAbove;
|
||||
};
|
||||
|
||||
class C_FireFromAboveSprite : public C_Sprite
|
||||
{
|
||||
DECLARE_CLASS( C_FireFromAboveSprite, C_Sprite );
|
||||
|
||||
virtual int DrawModel( int flags )
|
||||
{
|
||||
// The sprites become more visible the more you look down or up at them
|
||||
Vector vToPos = GetLocalOrigin() - CurrentViewOrigin();
|
||||
VectorNormalize( vToPos );
|
||||
|
||||
float fUpAmount = vToPos.z;
|
||||
|
||||
int iAlpha = 0;
|
||||
|
||||
if ( fUpAmount < -0.85f )
|
||||
iAlpha = 255;
|
||||
else if ( fUpAmount < -0.65f )
|
||||
iAlpha = (int)( ( fUpAmount + 0.65f ) * 5.0f * -255.0f );
|
||||
else if ( fUpAmount > 0.75f )
|
||||
iAlpha = 255;
|
||||
else if ( fUpAmount > 0.55f )
|
||||
iAlpha = (int)( ( fUpAmount - 0.55f ) * 5.0f * 255.0f );
|
||||
|
||||
SetColor( iAlpha, iAlpha, iAlpha );
|
||||
|
||||
return BaseClass::DrawModel( flags );
|
||||
}
|
||||
};
|
||||
|
||||
#ifdef _XBOX
|
||||
// XBox reduces the flame count
|
||||
#define NUM_CHILD_FLAMES 1
|
||||
#else
|
||||
#define NUM_CHILD_FLAMES 4
|
||||
#endif
|
||||
|
||||
#define SMOKE_RISE_RATE 92.0f
|
||||
#define SMOKE_LIFETIME 2.0f
|
||||
#define EMBER_LIFETIME 2.0f
|
||||
|
||||
#define FLAME_CHILD_SPREAD 64.0f
|
||||
#define FLAME_SOURCE_HEIGHT 128.0f
|
||||
#define FLAME_FROM_ABOVE_SOURCE_HEIGHT 32.0f
|
||||
|
||||
//==================================================
|
||||
// C_FireSmoke
|
||||
//==================================================
|
||||
|
||||
//NOTENOTE: Mirrored in dlls/fire_smoke.h
|
||||
#define bitsFIRESMOKE_NONE 0x00000000
|
||||
#define bitsFIRESMOKE_ACTIVE 0x00000001
|
||||
#define bitsFIRESMOKE_SMOKE 0x00000002
|
||||
#define bitsFIRESMOKE_SMOKE_COLLISION 0x00000004
|
||||
#define bitsFIRESMOKE_GLOW 0x00000008
|
||||
#define bitsFIRESMOKE_VISIBLE_FROM_ABOVE 0x00000010
|
||||
|
||||
#define OVERLAY_MAX_VISIBLE_RANGE 512.0f
|
||||
|
||||
|
||||
class C_FireSmoke : public C_BaseEntity
|
||||
{
|
||||
public:
|
||||
DECLARE_CLIENTCLASS();
|
||||
DECLARE_CLASS( C_FireSmoke, C_BaseEntity );
|
||||
|
||||
C_FireSmoke();
|
||||
~C_FireSmoke();
|
||||
|
||||
void Start( void );
|
||||
void Simulate( void );
|
||||
|
||||
void StartClientOnly( void );
|
||||
void RemoveClientOnly( void );
|
||||
|
||||
protected:
|
||||
void Update( void );
|
||||
void UpdateAnimation( void );
|
||||
void UpdateScale( void );
|
||||
void UpdateFlames( void );
|
||||
void AddFlames( void );
|
||||
void SpawnSmoke( void );
|
||||
void FindClipPlane( void );
|
||||
|
||||
//C_BaseEntity
|
||||
public:
|
||||
|
||||
virtual void OnDataChanged( DataUpdateType_t updateType );
|
||||
virtual bool ShouldDraw();
|
||||
|
||||
float GetScale( void ) const { return m_flScaleRegister; }
|
||||
|
||||
//From the server
|
||||
public:
|
||||
float m_flStartScale;
|
||||
float m_flScale;
|
||||
float m_flScaleTime;
|
||||
int m_nFlags;
|
||||
int m_nFlameModelIndex;
|
||||
int m_nFlameFromAboveModelIndex;
|
||||
|
||||
//Client-side only
|
||||
public:
|
||||
float m_flScaleRegister;
|
||||
float m_flScaleStart;
|
||||
float m_flScaleEnd;
|
||||
float m_flScaleTimeStart;
|
||||
float m_flScaleTimeEnd;
|
||||
float m_flChildFlameSpread;
|
||||
|
||||
VPlane m_planeClip;
|
||||
float m_flClipPerc;
|
||||
bool m_bClipTested;
|
||||
|
||||
bool m_bFadingOut;
|
||||
|
||||
protected:
|
||||
|
||||
void UpdateEffects( void );
|
||||
|
||||
//CSmartPtr<CEmberEffect> m_pEmberEmitter;
|
||||
CSmartPtr<CLitSmokeEmitter> m_pSmokeEmitter;
|
||||
|
||||
C_FireSprite m_entFlames[NUM_CHILD_FLAMES];
|
||||
C_FireFromAboveSprite m_entFlamesFromAbove[NUM_CHILD_FLAMES];
|
||||
float m_entFlameScales[NUM_CHILD_FLAMES];
|
||||
|
||||
TimedEvent m_tParticleSpawn;
|
||||
|
||||
CFireOverlay *m_pFireOverlay;
|
||||
|
||||
// New Particle Fire Effect
|
||||
CNewParticleEffect *m_hEffect;
|
||||
private:
|
||||
C_FireSmoke( const C_FireSmoke & );
|
||||
};
|
||||
|
||||
//Fire overlay
|
||||
class CFireOverlay : public CGlowOverlay
|
||||
{
|
||||
public:
|
||||
|
||||
//Constructor
|
||||
CFireOverlay( C_FireSmoke *owner )
|
||||
{
|
||||
m_pOwner = owner;
|
||||
m_flScale = 0.0f;
|
||||
m_nGUID = random->RandomInt( -999999, 999999 );
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Generate a flicker value
|
||||
// Output : scalar value
|
||||
//-----------------------------------------------------------------------------
|
||||
float GetFlickerScale( void )
|
||||
{
|
||||
float result = 0.0f;
|
||||
|
||||
float time = Helper_GetTime() + m_nGUID;
|
||||
|
||||
result = sin( time * 1000.0f );
|
||||
result += 0.5f * sin( time * 2000.0f );
|
||||
result -= 0.5f * cos( time * 8000.0f );
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Update the overlay
|
||||
//-----------------------------------------------------------------------------
|
||||
virtual bool Update( void )
|
||||
{
|
||||
if ( m_pOwner == NULL )
|
||||
return false;
|
||||
|
||||
float scale = m_pOwner->GetScale();
|
||||
float dscale = scale - m_flScale;
|
||||
|
||||
m_vPos[2] += dscale * FLAME_SOURCE_HEIGHT;
|
||||
m_flScale = scale;
|
||||
|
||||
scale *= 0.75f;
|
||||
|
||||
float flickerScale = GetFlickerScale();
|
||||
|
||||
float newScale = scale + ( scale * flickerScale * 0.1f );
|
||||
|
||||
m_Sprites[0].m_flHorzSize = ( newScale * 0.2f ) + ( m_Sprites[0].m_flHorzSize * 0.8f );
|
||||
m_Sprites[0].m_flVertSize = m_Sprites[0].m_flHorzSize * 1.5f;
|
||||
|
||||
float cameraDistance = ( CurrentViewOrigin() - (m_pOwner->GetAbsOrigin())).Length();
|
||||
|
||||
C_BasePlayer *local = C_BasePlayer::GetLocalPlayer();
|
||||
if ( local )
|
||||
{
|
||||
cameraDistance *= local->GetFOVDistanceAdjustFactor();
|
||||
}
|
||||
|
||||
if ( cameraDistance > OVERLAY_MAX_VISIBLE_RANGE )
|
||||
cameraDistance = OVERLAY_MAX_VISIBLE_RANGE;
|
||||
|
||||
float alpha = 1.0f - ( cameraDistance / OVERLAY_MAX_VISIBLE_RANGE );
|
||||
|
||||
Vector newColor = m_vBaseColors[0] + ( m_vBaseColors[0] * flickerScale * 0.5f );
|
||||
m_Sprites[0].m_vColor = ( newColor * 0.1f ) + ( m_Sprites[0].m_vColor * 0.9f ) * alpha;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
C_FireSmoke *m_pOwner;
|
||||
Vector m_vBaseColors[MAX_SUN_LAYERS];
|
||||
float m_flScale;
|
||||
int m_nGUID;
|
||||
};
|
||||
|
||||
//
|
||||
// Entity flame, client-side implementation
|
||||
//
|
||||
|
||||
#define NUM_FLAMELETS 5
|
||||
|
||||
class C_EntityFlame : public C_BaseEntity
|
||||
{
|
||||
public:
|
||||
DECLARE_CLIENTCLASS();
|
||||
DECLARE_CLASS( C_EntityFlame, C_BaseEntity );
|
||||
|
||||
C_EntityFlame( void );
|
||||
~C_EntityFlame( void );
|
||||
|
||||
virtual void Simulate( void );
|
||||
virtual void UpdateOnRemove( void );
|
||||
virtual void OnDataChanged( DataUpdateType_t updateType );
|
||||
virtual void ClientThink( void );
|
||||
|
||||
CNewParticleEffect *m_hEffect;
|
||||
EHANDLE m_hEntAttached; // The entity that we are burning (attached to).
|
||||
EHANDLE m_hOldAttached;
|
||||
|
||||
protected:
|
||||
|
||||
void CreateEffect( void );
|
||||
void StopEffect( void );
|
||||
};
|
||||
|
||||
#endif //C_FIRE_SMOKE_H
|
||||
@@ -0,0 +1,355 @@
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
// $NoKeywords: $
|
||||
//
|
||||
//=============================================================================//
|
||||
// c_fish.cpp
|
||||
// Simple fish client-side logic
|
||||
// Author: Michael S. Booth, April 2005
|
||||
|
||||
#include "cbase.h"
|
||||
#include <bitbuf.h>
|
||||
#include "engine/ivdebugoverlay.h"
|
||||
|
||||
// memdbgon must be the last include file in a .cpp file!!!
|
||||
#include "tier0/memdbgon.h"
|
||||
|
||||
extern float UTIL_WaterLevel( const Vector &position, float minz, float maxz );
|
||||
|
||||
|
||||
ConVar FishDebug( "fish_debug", "0", FCVAR_CHEAT, "Show debug info for fish" );
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
/**
|
||||
* Client-side fish entity
|
||||
*/
|
||||
class C_Fish : public C_BaseAnimating
|
||||
{
|
||||
public:
|
||||
DECLARE_CLASS( C_Fish, C_BaseAnimating );
|
||||
DECLARE_CLIENTCLASS();
|
||||
|
||||
virtual void Spawn( void );
|
||||
virtual void ClientThink();
|
||||
|
||||
virtual void OnDataChanged( DataUpdateType_t type );
|
||||
|
||||
private:
|
||||
friend void RecvProxy_FishOriginX( const CRecvProxyData *pData, void *pStruct, void *pOut );
|
||||
friend void RecvProxy_FishOriginY( const CRecvProxyData *pData, void *pStruct, void *pOut );
|
||||
|
||||
Vector m_pos; ///< local position
|
||||
Vector m_vel; ///< local velocity
|
||||
QAngle m_angles; ///< local angles
|
||||
|
||||
int m_localLifeState; ///< our version of m_lifeState
|
||||
|
||||
float m_deathDepth; ///< water depth when we died
|
||||
float m_deathAngle; ///< angle to float at when dead
|
||||
float m_buoyancy; ///< so each fish floats at a different rate when dead
|
||||
|
||||
CountdownTimer m_wiggleTimer; ///< for simulating swimming motions
|
||||
float m_wigglePhase; ///< where in the wiggle sinusoid we are
|
||||
float m_wiggleRate; ///< the speed of our wiggling
|
||||
|
||||
Vector m_actualPos; ///< position from server
|
||||
QAngle m_actualAngles; ///< angles from server
|
||||
|
||||
Vector m_poolOrigin;
|
||||
float m_waterLevel; ///< Z coordinate of water surface
|
||||
|
||||
bool m_gotUpdate; ///< true after we have received a network update
|
||||
|
||||
enum { MAX_ERROR_HISTORY = 20 };
|
||||
float m_errorHistory[ MAX_ERROR_HISTORY ]; ///< error history samples
|
||||
int m_errorHistoryIndex;
|
||||
int m_errorHistoryCount;
|
||||
float m_averageError;
|
||||
};
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
void RecvProxy_FishOriginX( const CRecvProxyData *pData, void *pStruct, void *pOut )
|
||||
{
|
||||
C_Fish *fish = (C_Fish *)pStruct;
|
||||
float *out = (float *)pOut;
|
||||
|
||||
*out = pData->m_Value.m_Float + fish->m_poolOrigin.x;
|
||||
}
|
||||
|
||||
void RecvProxy_FishOriginY( const CRecvProxyData *pData, void *pStruct, void *pOut )
|
||||
{
|
||||
C_Fish *fish = (C_Fish *)pStruct;
|
||||
float *out = (float *)pOut;
|
||||
|
||||
*out = pData->m_Value.m_Float + fish->m_poolOrigin.y;
|
||||
}
|
||||
|
||||
|
||||
IMPLEMENT_CLIENTCLASS_DT_NOBASE( C_Fish, DT_CFish, CFish )
|
||||
|
||||
RecvPropVector( RECVINFO(m_poolOrigin) ),
|
||||
|
||||
RecvPropFloat( RECVINFO_NAME( m_actualPos.x, m_x ), 0, RecvProxy_FishOriginX ),
|
||||
RecvPropFloat( RECVINFO_NAME( m_actualPos.y, m_y ), 0, RecvProxy_FishOriginY ),
|
||||
RecvPropFloat( RECVINFO_NAME( m_actualPos.z, m_z ) ),
|
||||
|
||||
RecvPropFloat( RECVINFO_NAME( m_actualAngles.y, m_angle ) ),
|
||||
|
||||
RecvPropInt( RECVINFO(m_nModelIndex) ),
|
||||
RecvPropInt( RECVINFO(m_lifeState) ),
|
||||
|
||||
RecvPropFloat( RECVINFO(m_waterLevel) ), ///< get this from the server in case we die when slightly out of the water due to error correction
|
||||
|
||||
END_RECV_TABLE()
|
||||
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
void C_Fish::Spawn( void )
|
||||
{
|
||||
BaseClass::Spawn();
|
||||
|
||||
m_angles = QAngle( 0, 0, 0 );
|
||||
m_actualAngles = m_angles;
|
||||
|
||||
m_vel = Vector( 0, 0, 0 );
|
||||
m_gotUpdate = false;
|
||||
m_localLifeState = LIFE_ALIVE;
|
||||
m_buoyancy = RandomFloat( 0.4f, 1.0f );
|
||||
|
||||
m_errorHistoryIndex = 0;
|
||||
m_errorHistoryCount = 0;
|
||||
m_averageError = 0.0f;
|
||||
|
||||
SetNextClientThink( CLIENT_THINK_ALWAYS );
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
void C_Fish::ClientThink()
|
||||
{
|
||||
if (FishDebug.GetBool())
|
||||
{
|
||||
if ( debugoverlay )
|
||||
{
|
||||
debugoverlay->AddLineOverlay( m_pos, m_actualPos, 255, 0, 0, true, 0.1f );
|
||||
switch( m_localLifeState )
|
||||
{
|
||||
case LIFE_DYING:
|
||||
debugoverlay->AddTextOverlay( m_pos, 0.1f, "DYING" );
|
||||
break;
|
||||
|
||||
case LIFE_DEAD:
|
||||
debugoverlay->AddTextOverlay( m_pos, 0.1f, "DEAD" );
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
float deltaT = gpGlobals->frametime;
|
||||
|
||||
|
||||
// check if we just died
|
||||
if (m_localLifeState == LIFE_ALIVE && m_lifeState != LIFE_ALIVE)
|
||||
{
|
||||
// we have died
|
||||
m_localLifeState = LIFE_DYING;
|
||||
|
||||
m_deathDepth = m_pos.z;
|
||||
|
||||
// determine surface float angle
|
||||
m_deathAngle = RandomFloat( 87.0f, 93.0f ) * ((RandomInt( 0, 100 ) < 50) ? 1.0f : -1.0f);
|
||||
}
|
||||
|
||||
|
||||
switch( m_localLifeState )
|
||||
{
|
||||
case LIFE_DYING:
|
||||
{
|
||||
// depth parameter
|
||||
float t = (m_pos.z - m_deathDepth) / (m_waterLevel - m_deathDepth);
|
||||
t *= t;
|
||||
|
||||
// roll onto side
|
||||
m_angles.z = m_deathAngle * t;
|
||||
|
||||
// float to surface
|
||||
const float fudge = 2.0f;
|
||||
if (m_pos.z < m_waterLevel - fudge)
|
||||
{
|
||||
m_vel.z += (1.0f - t) * m_buoyancy * deltaT;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_localLifeState = LIFE_DEAD;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case LIFE_DEAD:
|
||||
{
|
||||
// depth parameter
|
||||
float t = (m_pos.z - m_deathDepth) / (m_waterLevel - m_deathDepth);
|
||||
t *= t;
|
||||
|
||||
// roll onto side
|
||||
m_angles.z = m_deathAngle * t;
|
||||
|
||||
// keep near water surface
|
||||
const float sub = 0.5f;
|
||||
m_vel.z += 10.0f * (m_waterLevel - m_pos.z - sub) * deltaT;
|
||||
|
||||
// bob on surface
|
||||
const float rollAmp = 5.0f;
|
||||
const float rollFreq = 2.33f;
|
||||
m_angles.z += rollAmp * sin( rollFreq * (gpGlobals->curtime + 10.0f * entindex()) ) * deltaT;
|
||||
|
||||
const float rollAmp2 = 7.0f;
|
||||
const float rollFreq2 = 4.0f;
|
||||
m_angles.x += rollAmp2 * sin( rollFreq2 * (gpGlobals->curtime + 10.0f * entindex()) ) * deltaT;
|
||||
|
||||
const float bobAmp = 0.75f;
|
||||
const float bobFreq = 4.0f;
|
||||
m_vel.z += bobAmp * sin( bobFreq * (gpGlobals->curtime + 10.0f * entindex()) ) * deltaT;
|
||||
|
||||
const float bobAmp2 = 0.75f;
|
||||
const float bobFreq2 = 3.333f;
|
||||
m_vel.z += bobAmp2 * sin( bobFreq2 * (gpGlobals->curtime + 10.0f * entindex()) ) * deltaT;
|
||||
|
||||
// decay movement speed to zero
|
||||
const float drag = 1.0f;
|
||||
m_vel.z -= drag * m_vel.z * deltaT;
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case LIFE_ALIVE:
|
||||
{
|
||||
// use server-side Z coordinate directly
|
||||
m_pos.z = m_actualPos.z;
|
||||
|
||||
// use server-side angles
|
||||
m_angles = m_actualAngles;
|
||||
|
||||
// fishy wiggle based on movement
|
||||
if (!m_wiggleTimer.IsElapsed())
|
||||
{
|
||||
float swimPower = 1.0f - (m_wiggleTimer.GetElapsedTime() / m_wiggleTimer.GetCountdownDuration());
|
||||
const float amp = 6.0f * swimPower;
|
||||
float wiggle = amp * sin( m_wigglePhase );
|
||||
|
||||
m_wigglePhase += m_wiggleRate * deltaT;
|
||||
|
||||
// wiggle decay
|
||||
const float wiggleDecay = 5.0f;
|
||||
m_wiggleRate -= wiggleDecay * deltaT;
|
||||
|
||||
m_angles.y += wiggle;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// compute error between our local position and actual server position
|
||||
Vector error = m_actualPos - m_pos;
|
||||
error.z = 0.0f;
|
||||
float errorLen = error.Length();
|
||||
|
||||
if (m_localLifeState == LIFE_ALIVE)
|
||||
{
|
||||
// if error is far above average, start swimming
|
||||
const float wiggleThreshold = 2.0f;
|
||||
if (errorLen - m_averageError > wiggleThreshold)
|
||||
{
|
||||
// if error is large, we must have started swimming
|
||||
const float swimTime = 5.0f;
|
||||
m_wiggleTimer.Start( swimTime );
|
||||
|
||||
m_wiggleRate = 2.0f * errorLen;
|
||||
|
||||
const float maxWiggleRate = 30.0f;
|
||||
if (m_wiggleRate > maxWiggleRate)
|
||||
{
|
||||
m_wiggleRate = maxWiggleRate;
|
||||
}
|
||||
}
|
||||
|
||||
// update average error
|
||||
m_errorHistory[ m_errorHistoryIndex++ ] = errorLen;
|
||||
if (m_errorHistoryIndex >= MAX_ERROR_HISTORY)
|
||||
{
|
||||
m_errorHistoryIndex = 0;
|
||||
m_errorHistoryCount = MAX_ERROR_HISTORY;
|
||||
}
|
||||
else if (m_errorHistoryCount < MAX_ERROR_HISTORY)
|
||||
{
|
||||
++m_errorHistoryCount;
|
||||
}
|
||||
|
||||
m_averageError = 0.0f;
|
||||
if (m_errorHistoryCount)
|
||||
{
|
||||
for( int r=0; r<m_errorHistoryCount; ++r )
|
||||
{
|
||||
m_averageError += m_errorHistory[r];
|
||||
}
|
||||
m_averageError /= (float)m_errorHistoryCount;
|
||||
}
|
||||
}
|
||||
|
||||
// keep fish motion smooth by correcting towards actual server position
|
||||
// NOTE: This only tracks XY motion
|
||||
const float maxError = 20.0f;
|
||||
float errorT = errorLen / maxError;
|
||||
if (errorT > 1.0f)
|
||||
{
|
||||
errorT = 1.0f;
|
||||
}
|
||||
|
||||
// we want a nonlinear spring force for tracking
|
||||
errorT *= errorT;
|
||||
|
||||
// as fish move faster, their error increases - use a stiffer spring when fast, and a weak one when slow
|
||||
const float trackRate = 0.0f + errorT * 115.0f;
|
||||
m_vel.x += trackRate * error.x * deltaT;
|
||||
m_vel.y += trackRate * error.y * deltaT;
|
||||
|
||||
const float trackDrag = 2.0f + errorT * 6.0f;
|
||||
m_vel.x -= trackDrag * m_vel.x * deltaT;
|
||||
m_vel.y -= trackDrag * m_vel.y * deltaT;
|
||||
|
||||
|
||||
// euler integration
|
||||
m_pos += m_vel * deltaT;
|
||||
|
||||
SetNetworkOrigin( m_pos );
|
||||
SetAbsOrigin( m_pos );
|
||||
|
||||
SetNetworkAngles( m_angles );
|
||||
SetAbsAngles( m_angles );
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
void C_Fish::OnDataChanged( DataUpdateType_t type )
|
||||
{
|
||||
//if (!m_gotUpdate)
|
||||
|
||||
if (type == DATA_UPDATE_CREATED)
|
||||
{
|
||||
// initial update
|
||||
m_gotUpdate = true;
|
||||
|
||||
m_pos = m_actualPos;
|
||||
m_vel = Vector( 0, 0, 0 );
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,302 @@
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
#include "cbase.h"
|
||||
#include "forcefeedback.h"
|
||||
#include "hud_macros.h"
|
||||
#include "input.h"
|
||||
|
||||
#define FF_CLIENT_FLAG 0x8000
|
||||
|
||||
class FFParams
|
||||
{
|
||||
public:
|
||||
FORCEFEEDBACK_t m_nEffectType;
|
||||
FFBaseParams_t m_BaseParams;
|
||||
};
|
||||
|
||||
struct FFEffectInfo_t
|
||||
{
|
||||
FORCEFEEDBACK_t effectType;
|
||||
char const *name;
|
||||
};
|
||||
|
||||
#define DECLARE_FFEFFECT( name ) { name, #name }
|
||||
|
||||
static FFEffectInfo_t g_EffectTypes[] =
|
||||
{
|
||||
DECLARE_FFEFFECT( FORCE_FEEDBACK_SHOT_SINGLE ),
|
||||
DECLARE_FFEFFECT( FORCE_FEEDBACK_SHOT_DOUBLE ),
|
||||
DECLARE_FFEFFECT( FORCE_FEEDBACK_TAKEDAMAGE ),
|
||||
DECLARE_FFEFFECT( FORCE_FEEDBACK_SCREENSHAKE ),
|
||||
DECLARE_FFEFFECT( FORCE_FEEDBACK_SKIDDING ),
|
||||
DECLARE_FFEFFECT( FORCE_FEEDBACK_BREAKING )
|
||||
};
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
// Input : effect -
|
||||
// Output : char const
|
||||
//-----------------------------------------------------------------------------
|
||||
char const *NameForForceFeedbackEffect( FORCEFEEDBACK_t effect )
|
||||
{
|
||||
int c = ARRAYSIZE( g_EffectTypes );
|
||||
if ( (int)effect < 0 || (int)effect >= c )
|
||||
return "???";
|
||||
|
||||
const FFEffectInfo_t& info = g_EffectTypes[ (int)effect ];
|
||||
Assert( info.effectType == effect );
|
||||
return info.name;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
// Input : *name -
|
||||
// Output : FORCEFEEDBACK_t
|
||||
//-----------------------------------------------------------------------------
|
||||
FORCEFEEDBACK_t ForceFeedbackEffectForName( const char *name )
|
||||
{
|
||||
int c = ARRAYSIZE( g_EffectTypes );
|
||||
for ( int i = 0 ; i < c; ++i )
|
||||
{
|
||||
const FFEffectInfo_t& info = g_EffectTypes[ i ];
|
||||
|
||||
if ( !Q_stricmp( info.name, name ) )
|
||||
return info.effectType;
|
||||
}
|
||||
|
||||
return ( FORCEFEEDBACK_t )-1;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
class CForceFeedback : public IForceFeedback, public CAutoGameSystem
|
||||
{
|
||||
public:
|
||||
virtual bool Init();
|
||||
virtual void Shutdown();
|
||||
|
||||
// API
|
||||
virtual void StopAllEffects( CBasePlayer *player );
|
||||
virtual void StopEffect( CBasePlayer *player, FORCEFEEDBACK_t effect );
|
||||
virtual void StartEffect( CBasePlayer *player, FORCEFEEDBACK_t effect, const FFBaseParams_t& params );
|
||||
|
||||
virtual void PauseAll( CBasePlayer *player );
|
||||
virtual void ResumeAll( CBasePlayer *player );
|
||||
|
||||
void MsgFunc_ForceFeedback( bf_read &msg );
|
||||
|
||||
private:
|
||||
|
||||
void Internal_StopAllEffects();
|
||||
void Internal_StopEffect( FORCEFEEDBACK_t effect );
|
||||
void Internal_StartEffect( FORCEFEEDBACK_t, const FFBaseParams_t& params );
|
||||
void Internal_PauseAll();
|
||||
void Internal_ResumeAll();
|
||||
};
|
||||
|
||||
static CForceFeedback g_ForceFeedbackSingleton;
|
||||
IForceFeedback *forcefeedback = &g_ForceFeedbackSingleton;
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
// Input : &msg -
|
||||
//-----------------------------------------------------------------------------
|
||||
void __MsgFunc_ForceFeedback( bf_read &msg )
|
||||
{
|
||||
g_ForceFeedbackSingleton.MsgFunc_ForceFeedback( msg );
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
// Output : Returns true on success, false on failure.
|
||||
//-----------------------------------------------------------------------------
|
||||
bool CForceFeedback::Init()
|
||||
{
|
||||
HOOK_MESSAGE( ForceFeedback );
|
||||
return true;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
void CForceFeedback::Shutdown()
|
||||
{
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
// Input : *player -
|
||||
//-----------------------------------------------------------------------------
|
||||
void CForceFeedback::StopAllEffects( CBasePlayer *player )
|
||||
{
|
||||
if ( !player )
|
||||
return;
|
||||
|
||||
Internal_StopAllEffects();
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
// Input : *player -
|
||||
// effect -
|
||||
//-----------------------------------------------------------------------------
|
||||
void CForceFeedback::StopEffect( CBasePlayer *player, FORCEFEEDBACK_t effect )
|
||||
{
|
||||
if ( !player )
|
||||
return;
|
||||
|
||||
Internal_StopEffect( effect );
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
// Input : *player -
|
||||
// effect -
|
||||
// params -
|
||||
//-----------------------------------------------------------------------------
|
||||
void CForceFeedback::StartEffect( CBasePlayer *player, FORCEFEEDBACK_t effect, const FFBaseParams_t& params )
|
||||
{
|
||||
if ( !player )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
Internal_StartEffect( effect, params );
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
// Input : *player -
|
||||
//-----------------------------------------------------------------------------
|
||||
void CForceFeedback::PauseAll( CBasePlayer *player )
|
||||
{
|
||||
if ( !player )
|
||||
return;
|
||||
|
||||
Internal_PauseAll();
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
// Input : *player -
|
||||
//-----------------------------------------------------------------------------
|
||||
void CForceFeedback::ResumeAll( CBasePlayer *player )
|
||||
{
|
||||
if ( !player )
|
||||
return;
|
||||
|
||||
Internal_ResumeAll();
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
void CForceFeedback::Internal_StopAllEffects()
|
||||
{
|
||||
input->ForceFeedback_StopAll();
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
// Input : heffect -
|
||||
//-----------------------------------------------------------------------------
|
||||
void CForceFeedback::Internal_StopEffect( FORCEFEEDBACK_t effect )
|
||||
{
|
||||
input->ForceFeedback_Stop( effect );
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
// Input : effect -
|
||||
//-----------------------------------------------------------------------------
|
||||
void CForceFeedback::Internal_StartEffect( FORCEFEEDBACK_t effect, const FFBaseParams_t& params)
|
||||
{
|
||||
char const *name = NameForForceFeedbackEffect( effect );
|
||||
Msg( "Starting FF effect '%s'\n", name );
|
||||
|
||||
FFParams p;
|
||||
p.m_nEffectType = effect;
|
||||
p.m_BaseParams = params;
|
||||
|
||||
input->ForceFeedback_Start( effect, params );
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
void CForceFeedback::Internal_PauseAll()
|
||||
{
|
||||
input->ForceFeedback_Pause();
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
void CForceFeedback::Internal_ResumeAll()
|
||||
{
|
||||
input->ForceFeedback_Resume();
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
// Input : *pszName -
|
||||
// iSize -
|
||||
// *pbuf -
|
||||
//-----------------------------------------------------------------------------
|
||||
void CForceFeedback::MsgFunc_ForceFeedback( bf_read &msg )
|
||||
{
|
||||
byte msgType = msg.ReadByte();
|
||||
|
||||
switch ( msgType )
|
||||
{
|
||||
default:
|
||||
{
|
||||
Warning( "Bad parse in MsgFunc_ForceFeedback!\n" );
|
||||
}
|
||||
break;
|
||||
case FFMSG_STOPALL:
|
||||
{
|
||||
Internal_StopAllEffects();
|
||||
}
|
||||
break;
|
||||
case FFMSG_START:
|
||||
{
|
||||
FORCEFEEDBACK_t effectType = (FORCEFEEDBACK_t)msg.ReadByte();
|
||||
|
||||
FFBaseParams_t params;
|
||||
params.m_flDirection = 360.0f * ( (byte)msg.ReadByte() / 255.0f );
|
||||
params.m_flDuration = (float)msg.ReadLong() / 1000.0f;
|
||||
params.m_flGain = ( (byte)msg.ReadByte() / 255.0f );
|
||||
params.m_nPriority = msg.ReadByte();
|
||||
params.m_bSolo = msg.ReadByte() == 0 ? false : true;
|
||||
|
||||
if ( effectType >= 0 && effectType < NUM_FORCE_FEEDBACK_PRESETS )
|
||||
{
|
||||
Internal_StartEffect( effectType, params );
|
||||
}
|
||||
else
|
||||
{
|
||||
Warning( "Bad parse in MsgFunc_ForceFeedback, FFMSG_START (%i)!\n", effectType );
|
||||
}
|
||||
}
|
||||
break;
|
||||
case FFMSG_STOP:
|
||||
{
|
||||
FORCEFEEDBACK_t effectType = (FORCEFEEDBACK_t)msg.ReadByte();
|
||||
|
||||
Internal_StopEffect( effectType );
|
||||
}
|
||||
break;
|
||||
case FFMSG_PAUSE:
|
||||
{
|
||||
Internal_PauseAll();
|
||||
}
|
||||
break;
|
||||
case FFMSG_RESUME:
|
||||
{
|
||||
Internal_ResumeAll();
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,147 @@
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
// $NoKeywords: $
|
||||
//
|
||||
//=============================================================================//
|
||||
#include "cbase.h"
|
||||
#include "view.h"
|
||||
#include "model_types.h"
|
||||
#include "ivrenderview.h"
|
||||
#include "engine/ivmodelinfo.h"
|
||||
|
||||
// memdbgon must be the last include file in a .cpp file!!!
|
||||
#include "tier0/memdbgon.h"
|
||||
|
||||
#define VIEWER_PADDING 80.0f
|
||||
|
||||
class C_FuncAreaPortalWindow : public C_BaseEntity
|
||||
{
|
||||
public:
|
||||
DECLARE_CLIENTCLASS();
|
||||
DECLARE_CLASS( C_FuncAreaPortalWindow, C_BaseEntity );
|
||||
|
||||
|
||||
// Overrides.
|
||||
public:
|
||||
|
||||
virtual void ComputeFxBlend();
|
||||
virtual bool IsTransparent();
|
||||
virtual int DrawModel( int flags );
|
||||
virtual bool ShouldReceiveProjectedTextures( int flags );
|
||||
|
||||
private:
|
||||
|
||||
float GetDistanceBlend();
|
||||
|
||||
|
||||
|
||||
public:
|
||||
float m_flFadeStartDist; // Distance at which it starts fading (when <= this, alpha=m_flTranslucencyLimit).
|
||||
float m_flFadeDist; // Distance at which it becomes solid.
|
||||
|
||||
// 0-1 value - minimum translucency it's allowed to get to.
|
||||
float m_flTranslucencyLimit;
|
||||
|
||||
int m_iBackgroundModelIndex;
|
||||
};
|
||||
|
||||
|
||||
|
||||
IMPLEMENT_CLIENTCLASS_DT( C_FuncAreaPortalWindow, DT_FuncAreaPortalWindow, CFuncAreaPortalWindow )
|
||||
RecvPropFloat( RECVINFO( m_flFadeStartDist ) ),
|
||||
RecvPropFloat( RECVINFO( m_flFadeDist ) ),
|
||||
RecvPropFloat( RECVINFO( m_flTranslucencyLimit ) ),
|
||||
RecvPropInt( RECVINFO( m_iBackgroundModelIndex ) )
|
||||
END_RECV_TABLE()
|
||||
|
||||
|
||||
|
||||
void C_FuncAreaPortalWindow::ComputeFxBlend()
|
||||
{
|
||||
// We reset our blend down below so pass anything except 0 to the renderer.
|
||||
m_nRenderFXBlend = 255;
|
||||
|
||||
#ifdef _DEBUG
|
||||
m_nFXComputeFrame = gpGlobals->framecount;
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
|
||||
bool C_FuncAreaPortalWindow::IsTransparent()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
int C_FuncAreaPortalWindow::DrawModel( int flags )
|
||||
{
|
||||
if ( !m_bReadyToDraw )
|
||||
return 0;
|
||||
|
||||
if( !GetModel() )
|
||||
return 0;
|
||||
|
||||
// Make sure we're a brush model.
|
||||
int modelType = modelinfo->GetModelType( GetModel() );
|
||||
if( modelType != mod_brush )
|
||||
return 0;
|
||||
|
||||
// Draw the fading version.
|
||||
render->SetBlend( GetDistanceBlend() );
|
||||
|
||||
DrawBrushModelMode_t mode = DBM_DRAW_ALL;
|
||||
if ( flags & STUDIO_TWOPASS )
|
||||
{
|
||||
mode = ( flags & STUDIO_TRANSPARENCY ) ? DBM_DRAW_TRANSLUCENT_ONLY : DBM_DRAW_OPAQUE_ONLY;
|
||||
}
|
||||
|
||||
render->DrawBrushModelEx(
|
||||
this,
|
||||
(model_t *)GetModel(),
|
||||
GetAbsOrigin(),
|
||||
GetAbsAngles(),
|
||||
mode );
|
||||
|
||||
// Draw the optional foreground model next.
|
||||
// Only use the alpha in the texture from the thing in the front.
|
||||
if (m_iBackgroundModelIndex >= 0)
|
||||
{
|
||||
render->SetBlend( 1 );
|
||||
model_t *pBackground = ( model_t * )modelinfo->GetModel( m_iBackgroundModelIndex );
|
||||
if( pBackground && modelinfo->GetModelType( pBackground ) == mod_brush )
|
||||
{
|
||||
render->DrawBrushModelEx(
|
||||
this,
|
||||
pBackground,
|
||||
GetAbsOrigin(),
|
||||
GetAbsAngles(),
|
||||
mode );
|
||||
}
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
float C_FuncAreaPortalWindow::GetDistanceBlend()
|
||||
{
|
||||
// Get the viewer's distance to us.
|
||||
float flDist = CollisionProp()->CalcDistanceFromPoint( CurrentViewOrigin() );
|
||||
C_BasePlayer *local = C_BasePlayer::GetLocalPlayer();
|
||||
if ( local )
|
||||
{
|
||||
flDist *= local->GetFOVDistanceAdjustFactor();
|
||||
}
|
||||
|
||||
return RemapValClamped( flDist, m_flFadeStartDist, m_flFadeDist, m_flTranslucencyLimit, 1 );
|
||||
}
|
||||
|
||||
bool C_FuncAreaPortalWindow::ShouldReceiveProjectedTextures( int flags )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,158 @@
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
//===========================================================================//
|
||||
|
||||
#include "cbase.h"
|
||||
#include "materialsystem/imaterialproxy.h"
|
||||
#include "materialsystem/imaterial.h"
|
||||
#include "materialsystem/imaterialvar.h"
|
||||
#include "functionproxy.h"
|
||||
#include <KeyValues.h>
|
||||
#include "mathlib/vmatrix.h"
|
||||
#include "toolframework_client.h"
|
||||
|
||||
// memdbgon must be the last include file in a .cpp file!!!
|
||||
#include "tier0/memdbgon.h"
|
||||
|
||||
// forward declarations
|
||||
void ToolFramework_RecordMaterialParams( IMaterial *pMaterial );
|
||||
|
||||
class C_FuncConveyor : public C_BaseEntity
|
||||
{
|
||||
public:
|
||||
DECLARE_CLASS( C_FuncConveyor, C_BaseEntity );
|
||||
DECLARE_CLIENTCLASS();
|
||||
|
||||
C_FuncConveyor();
|
||||
|
||||
float GetConveyorSpeed() { return m_flConveyorSpeed; }
|
||||
|
||||
private:
|
||||
float m_flConveyorSpeed;
|
||||
};
|
||||
|
||||
|
||||
IMPLEMENT_CLIENTCLASS_DT( C_FuncConveyor, DT_FuncConveyor, CFuncConveyor )
|
||||
RecvPropFloat( RECVINFO( m_flConveyorSpeed ) ),
|
||||
END_RECV_TABLE()
|
||||
|
||||
|
||||
C_FuncConveyor::C_FuncConveyor()
|
||||
{
|
||||
m_flConveyorSpeed = 0.0;
|
||||
}
|
||||
|
||||
|
||||
class CConveyorMaterialProxy : public IMaterialProxy
|
||||
{
|
||||
public:
|
||||
CConveyorMaterialProxy();
|
||||
virtual ~CConveyorMaterialProxy();
|
||||
|
||||
virtual bool Init( IMaterial *pMaterial, KeyValues *pKeyValues );
|
||||
virtual void OnBind( void *pC_BaseEntity );
|
||||
virtual void Release( void ) { delete this; }
|
||||
virtual IMaterial *GetMaterial();
|
||||
|
||||
private:
|
||||
C_BaseEntity *BindArgToEntity( void *pArg );
|
||||
|
||||
IMaterialVar *m_pTextureScrollVar;
|
||||
};
|
||||
|
||||
CConveyorMaterialProxy::CConveyorMaterialProxy()
|
||||
{
|
||||
m_pTextureScrollVar = NULL;
|
||||
}
|
||||
|
||||
CConveyorMaterialProxy::~CConveyorMaterialProxy()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
bool CConveyorMaterialProxy::Init( IMaterial *pMaterial, KeyValues *pKeyValues )
|
||||
{
|
||||
char const* pScrollVarName = pKeyValues->GetString( "textureScrollVar" );
|
||||
if( !pScrollVarName )
|
||||
return false;
|
||||
|
||||
bool foundVar;
|
||||
m_pTextureScrollVar = pMaterial->FindVar( pScrollVarName, &foundVar, false );
|
||||
if( !foundVar )
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
C_BaseEntity *CConveyorMaterialProxy::BindArgToEntity( void *pArg )
|
||||
{
|
||||
IClientRenderable *pRend = (IClientRenderable *)pArg;
|
||||
return pRend->GetIClientUnknown()->GetBaseEntity();
|
||||
}
|
||||
|
||||
void CConveyorMaterialProxy::OnBind( void *pC_BaseEntity )
|
||||
{
|
||||
if( !pC_BaseEntity )
|
||||
return;
|
||||
|
||||
C_BaseEntity *pEntity = BindArgToEntity( pC_BaseEntity );
|
||||
|
||||
if ( !pEntity )
|
||||
return;
|
||||
|
||||
C_FuncConveyor *pConveyor = dynamic_cast<C_FuncConveyor*>(pEntity);
|
||||
|
||||
if ( !pConveyor )
|
||||
return;
|
||||
|
||||
if ( !m_pTextureScrollVar )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
float flConveyorSpeed = pConveyor->GetConveyorSpeed();
|
||||
float flRate = abs( flConveyorSpeed ) / 128.0;
|
||||
float flAngle = (flConveyorSpeed >= 0) ? 180 : 0;
|
||||
|
||||
float sOffset = gpGlobals->curtime * cos( flAngle * ( M_PI / 180.0f ) ) * flRate;
|
||||
float tOffset = gpGlobals->curtime * sin( flAngle * ( M_PI / 180.0f ) ) * flRate;
|
||||
|
||||
// make sure that we are positive
|
||||
if( sOffset < 0.0f )
|
||||
{
|
||||
sOffset += 1.0f + -( int )sOffset;
|
||||
}
|
||||
if( tOffset < 0.0f )
|
||||
{
|
||||
tOffset += 1.0f + -( int )tOffset;
|
||||
}
|
||||
|
||||
// make sure that we are in a [0,1] range
|
||||
sOffset = sOffset - ( int )sOffset;
|
||||
tOffset = tOffset - ( int )tOffset;
|
||||
|
||||
if (m_pTextureScrollVar->GetType() == MATERIAL_VAR_TYPE_MATRIX)
|
||||
{
|
||||
VMatrix mat;
|
||||
MatrixBuildTranslation( mat, sOffset, tOffset, 0.0f );
|
||||
m_pTextureScrollVar->SetMatrixValue( mat );
|
||||
}
|
||||
else
|
||||
{
|
||||
m_pTextureScrollVar->SetVecValue( sOffset, tOffset, 0.0f );
|
||||
}
|
||||
|
||||
if ( ToolsEnabled() )
|
||||
{
|
||||
ToolFramework_RecordMaterialParams( GetMaterial() );
|
||||
}
|
||||
}
|
||||
|
||||
IMaterial *CConveyorMaterialProxy::GetMaterial()
|
||||
{
|
||||
return m_pTextureScrollVar ? m_pTextureScrollVar->GetOwningMaterial() : NULL;
|
||||
}
|
||||
|
||||
EXPOSE_INTERFACE( CConveyorMaterialProxy, IMaterialProxy, "ConveyorScroll" IMATERIAL_PROXY_INTERFACE_VERSION );
|
||||
@@ -0,0 +1,365 @@
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
// $NoKeywords: $
|
||||
//=============================================================================//
|
||||
#include "cbase.h"
|
||||
#include "fx.h"
|
||||
#include "c_func_dust.h"
|
||||
#include "func_dust_shared.h"
|
||||
#include "c_te_particlesystem.h"
|
||||
#include "env_wind_shared.h"
|
||||
#include "engine/IEngineTrace.h"
|
||||
#include "tier0/vprof.h"
|
||||
#include "clienteffectprecachesystem.h"
|
||||
#include "particles_ez.h"
|
||||
|
||||
// memdbgon must be the last include file in a .cpp file!!!
|
||||
#include "tier0/memdbgon.h"
|
||||
|
||||
IMPLEMENT_CLIENTCLASS_DT_NOBASE( C_Func_Dust, DT_Func_Dust, CFunc_Dust )
|
||||
RecvPropInt( RECVINFO(m_Color) ),
|
||||
RecvPropInt( RECVINFO(m_SpawnRate) ),
|
||||
RecvPropFloat( RECVINFO(m_flSizeMin) ),
|
||||
RecvPropFloat( RECVINFO(m_flSizeMax) ),
|
||||
RecvPropInt( RECVINFO(m_LifetimeMin) ),
|
||||
RecvPropInt( RECVINFO(m_LifetimeMax) ),
|
||||
RecvPropInt( RECVINFO(m_DustFlags) ),
|
||||
RecvPropInt( RECVINFO(m_SpeedMax) ),
|
||||
RecvPropInt( RECVINFO(m_DistMax) ),
|
||||
RecvPropInt( RECVINFO( m_nModelIndex ) ),
|
||||
RecvPropFloat( RECVINFO( m_FallSpeed ) ),
|
||||
RecvPropDataTable( RECVINFO_DT( m_Collision ), 0, &REFERENCE_RECV_TABLE(DT_CollisionProperty) ),
|
||||
END_RECV_TABLE()
|
||||
|
||||
|
||||
|
||||
// ------------------------------------------------------------------------------------ //
|
||||
// CDustEffect implementation.
|
||||
// ------------------------------------------------------------------------------------ //
|
||||
#define DUST_ACCEL 50
|
||||
|
||||
|
||||
void CDustEffect::RenderParticles( CParticleRenderIterator *pIterator )
|
||||
{
|
||||
const CFuncDustParticle *pParticle = (const CFuncDustParticle*)pIterator->GetFirst();
|
||||
while ( pParticle )
|
||||
{
|
||||
// Velocity.
|
||||
float flAlpha;
|
||||
if( m_pDust->m_DustFlags & DUSTFLAGS_FROZEN )
|
||||
{
|
||||
flAlpha = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Alpha.
|
||||
float flAngle = (pParticle->m_flLifetime / pParticle->m_flDieTime) * M_PI * 2;
|
||||
flAlpha = sin( flAngle - (M_PI * 0.5f) ) * 0.5f + 0.5f;
|
||||
}
|
||||
|
||||
Vector tPos;
|
||||
TransformParticle( ParticleMgr()->GetModelView(), pParticle->m_Pos, tPos );
|
||||
float sortKey = (int) tPos.z;
|
||||
|
||||
if( -tPos.z <= m_pDust->m_DistMax )
|
||||
{
|
||||
flAlpha *= 1 + (tPos.z / m_pDust->m_DistMax);
|
||||
|
||||
// Draw it.
|
||||
float flSize = pParticle->m_flSize;
|
||||
if( m_pDust->m_DustFlags & DUSTFLAGS_SCALEMOTES )
|
||||
flSize *= -tPos.z;
|
||||
|
||||
RenderParticle_Color255Size(
|
||||
pIterator->GetParticleDraw(),
|
||||
tPos,
|
||||
Vector( m_pDust->m_Color.r, m_pDust->m_Color.g, m_pDust->m_Color.b ),
|
||||
flAlpha * m_pDust->m_Color.a,
|
||||
flSize
|
||||
);
|
||||
}
|
||||
|
||||
pParticle = (const CFuncDustParticle*)pIterator->GetNext( sortKey );
|
||||
}
|
||||
}
|
||||
|
||||
void CDustEffect::SimulateParticles( CParticleSimulateIterator *pIterator )
|
||||
{
|
||||
Vector vecWind;
|
||||
GetWindspeedAtTime( gpGlobals->curtime, vecWind );
|
||||
|
||||
|
||||
CFuncDustParticle *pParticle = (CFuncDustParticle*)pIterator->GetFirst();
|
||||
while ( pParticle )
|
||||
{
|
||||
// Velocity.
|
||||
if( !(m_pDust->m_DustFlags & DUSTFLAGS_FROZEN) )
|
||||
{
|
||||
// Kill the particle?
|
||||
pParticle->m_flLifetime += pIterator->GetTimeDelta();
|
||||
if( pParticle->m_flLifetime >= pParticle->m_flDieTime )
|
||||
{
|
||||
pIterator->RemoveParticle( pParticle );
|
||||
}
|
||||
else
|
||||
{
|
||||
for ( int i = 0 ; i < 2 ; i++ )
|
||||
{
|
||||
if ( pParticle->m_vVelocity[i] < vecWind[i] )
|
||||
{
|
||||
pParticle->m_vVelocity[i] += ( gpGlobals->frametime * DUST_ACCEL );
|
||||
|
||||
// clamp
|
||||
if ( pParticle->m_vVelocity[i] > vecWind[i] )
|
||||
pParticle->m_vVelocity[i] = vecWind[i];
|
||||
}
|
||||
else if (pParticle->m_vVelocity[i] > vecWind[i] )
|
||||
{
|
||||
pParticle->m_vVelocity[i] -= ( gpGlobals->frametime * DUST_ACCEL );
|
||||
|
||||
// clamp.
|
||||
if ( pParticle->m_vVelocity[i] < vecWind[i] )
|
||||
pParticle->m_vVelocity[i] = vecWind[i];
|
||||
}
|
||||
}
|
||||
|
||||
// Apply velocity.
|
||||
pParticle->m_Pos.MulAdd( pParticle->m_Pos, pParticle->m_vVelocity, pIterator->GetTimeDelta() );
|
||||
}
|
||||
}
|
||||
|
||||
pParticle = (CFuncDustParticle*)pIterator->GetNext();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// ------------------------------------------------------------------------------------ //
|
||||
// C_Func_Dust implementation.
|
||||
// ------------------------------------------------------------------------------------ //
|
||||
|
||||
C_Func_Dust::C_Func_Dust() : m_Effect( "C_Func_Dust" )
|
||||
{
|
||||
m_Effect.m_pDust = this;
|
||||
m_Effect.SetDynamicallyAllocated( false ); // So it doesn't try to delete itself.
|
||||
}
|
||||
|
||||
|
||||
C_Func_Dust::~C_Func_Dust()
|
||||
{
|
||||
}
|
||||
|
||||
void C_Func_Dust::OnDataChanged( DataUpdateType_t updateType )
|
||||
{
|
||||
BaseClass::OnDataChanged( updateType );
|
||||
|
||||
if( updateType == DATA_UPDATE_CREATED )
|
||||
{
|
||||
m_hMaterial = m_Effect.GetPMaterial( "particle/sparkles" );
|
||||
|
||||
m_Effect.SetSortOrigin( WorldSpaceCenter( ) );
|
||||
|
||||
// Let us think each frame.
|
||||
SetNextClientThink( CLIENT_THINK_ALWAYS );
|
||||
|
||||
// If we're setup to be frozen, just make a bunch of particles initially.
|
||||
if( m_DustFlags & DUSTFLAGS_FROZEN )
|
||||
{
|
||||
for( int i=0; i < m_SpawnRate; i++ )
|
||||
{
|
||||
AttemptSpawnNewParticle();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
m_Spawner.Init( m_SpawnRate ); // N particles per second
|
||||
}
|
||||
|
||||
|
||||
void C_Func_Dust::ClientThink()
|
||||
{
|
||||
// If frozen, don't make new particles.
|
||||
if( m_DustFlags & DUSTFLAGS_FROZEN )
|
||||
return;
|
||||
|
||||
// Spawn particles?
|
||||
if( m_DustFlags & DUSTFLAGS_ON )
|
||||
{
|
||||
float flDelta = MIN( gpGlobals->frametime, 0.1f );
|
||||
while( m_Spawner.NextEvent( flDelta ) )
|
||||
{
|
||||
AttemptSpawnNewParticle();
|
||||
}
|
||||
}
|
||||
|
||||
// Tell the particle manager our bbox.
|
||||
Vector vWorldMins, vWorldMaxs;
|
||||
CollisionProp()->WorldSpaceAABB( &vWorldMins, &vWorldMaxs );
|
||||
vWorldMins -= Vector( m_flSizeMax, m_flSizeMax, m_flSizeMax );
|
||||
vWorldMaxs += Vector( m_flSizeMax, m_flSizeMax, m_flSizeMax );
|
||||
m_Effect.GetBinding().SetBBox( vWorldMins, vWorldMaxs );
|
||||
}
|
||||
|
||||
|
||||
bool C_Func_Dust::ShouldDraw()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
void C_Func_Dust::AttemptSpawnNewParticle()
|
||||
{
|
||||
// Find a random spot inside our bmodel.
|
||||
static int nTests=10;
|
||||
|
||||
for( int iTest=0; iTest < nTests; iTest++ )
|
||||
{
|
||||
Vector vPercent = RandomVector( 0, 1 );
|
||||
Vector vTest = WorldAlignMins() + (WorldAlignMaxs() - WorldAlignMins()) * vPercent;
|
||||
|
||||
int contents = enginetrace->GetPointContents_Collideable( GetCollideable(), vTest );
|
||||
if( contents & CONTENTS_SOLID )
|
||||
{
|
||||
CFuncDustParticle *pParticle = (CFuncDustParticle*)m_Effect.AddParticle( 10, m_hMaterial, vTest );
|
||||
if( pParticle )
|
||||
{
|
||||
pParticle->m_vVelocity = RandomVector( -m_SpeedMax, m_SpeedMax );
|
||||
pParticle->m_vVelocity.z -= m_FallSpeed;
|
||||
|
||||
pParticle->m_flLifetime = 0;
|
||||
pParticle->m_flDieTime = RemapVal( rand(), 0, VALVE_RAND_MAX, m_LifetimeMin, m_LifetimeMax );
|
||||
|
||||
if( m_DustFlags & DUSTFLAGS_SCALEMOTES )
|
||||
pParticle->m_flSize = RemapVal( rand(), 0, VALVE_RAND_MAX, m_flSizeMin/10000.0f, m_flSizeMax/10000.0f );
|
||||
else
|
||||
pParticle->m_flSize = RemapVal( rand(), 0, VALVE_RAND_MAX, m_flSizeMin, m_flSizeMax );
|
||||
|
||||
pParticle->m_Color = m_Color;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Dust
|
||||
//
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Spew out dust!
|
||||
//-----------------------------------------------------------------------------
|
||||
void FX_Dust( const Vector &vecOrigin, const Vector &vecDirection, float flSize, float flSpeed )
|
||||
{
|
||||
VPROF_BUDGET( "FX_Dust", VPROF_BUDGETGROUP_PARTICLE_RENDERING );
|
||||
|
||||
int numPuffs = (flSize*0.5f);
|
||||
|
||||
if ( numPuffs < 1 )
|
||||
numPuffs = 1;
|
||||
if ( numPuffs > 32 )
|
||||
numPuffs = 32;
|
||||
|
||||
float speed = flSpeed * 0.1f;
|
||||
|
||||
if ( speed < 0 )
|
||||
speed = 1.0f;
|
||||
if (speed > 48.0f )
|
||||
speed = 48.0f;
|
||||
|
||||
//FIXME: Better sampling area
|
||||
Vector offset = vecOrigin + ( vecDirection * flSize );
|
||||
|
||||
//Find area ambient light color and use it to tint smoke
|
||||
Vector worldLight = WorldGetLightForPoint( offset, true );
|
||||
|
||||
// Throw puffs
|
||||
SimpleParticle particle;
|
||||
for ( int i = 0; i < numPuffs; i++ )
|
||||
{
|
||||
offset.Random( -(flSize*0.25f), flSize*0.25f );
|
||||
offset += vecOrigin + ( vecDirection * flSize );
|
||||
|
||||
particle.m_Pos = offset;
|
||||
particle.m_flLifetime = 0.0f;
|
||||
particle.m_flDieTime = random->RandomFloat( 0.4f, 1.0f );
|
||||
|
||||
particle.m_vecVelocity = vecDirection * random->RandomFloat( speed*0.5f, speed ) * i;
|
||||
particle.m_vecVelocity[2] = 0.0f;
|
||||
|
||||
int color = random->RandomInt( 48, 64 );
|
||||
|
||||
particle.m_uchColor[0] = (color+16) + ( worldLight[0] * (float) color );
|
||||
particle.m_uchColor[1] = (color+8) + ( worldLight[1] * (float) color );
|
||||
particle.m_uchColor[2] = color + ( worldLight[2] * (float) color );
|
||||
|
||||
particle.m_uchStartAlpha= random->RandomInt( 64, 128 );
|
||||
particle.m_uchEndAlpha = 0;
|
||||
particle.m_uchStartSize = random->RandomInt( 2, 8 );
|
||||
particle.m_uchEndSize = random->RandomInt( 24, 48 );
|
||||
particle.m_flRoll = random->RandomInt( 0, 360 );
|
||||
particle.m_flRollDelta = random->RandomFloat( -0.5f, 0.5f );
|
||||
|
||||
AddSimpleParticle( &particle, g_Mat_DustPuff[random->RandomInt(0,1)] );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
class C_TEDust: public C_TEParticleSystem
|
||||
{
|
||||
public:
|
||||
DECLARE_CLASS( C_TEDust, C_TEParticleSystem );
|
||||
DECLARE_CLIENTCLASS();
|
||||
|
||||
C_TEDust();
|
||||
virtual ~C_TEDust();
|
||||
|
||||
public:
|
||||
virtual void PostDataUpdate( DataUpdateType_t updateType );
|
||||
virtual bool ShouldDraw() { return true; }
|
||||
|
||||
public:
|
||||
|
||||
float m_flSize;
|
||||
float m_flSpeed;
|
||||
Vector m_vecDirection;
|
||||
|
||||
protected:
|
||||
void GetDustColor( Vector &color );
|
||||
};
|
||||
|
||||
IMPLEMENT_CLIENTCLASS_EVENT_DT( C_TEDust, DT_TEDust, CTEDust )
|
||||
RecvPropFloat(RECVINFO(m_flSize)),
|
||||
RecvPropFloat(RECVINFO(m_flSpeed)),
|
||||
RecvPropVector(RECVINFO(m_vecDirection)),
|
||||
END_RECV_TABLE()
|
||||
|
||||
//==================================================
|
||||
// C_TEDust
|
||||
//==================================================
|
||||
|
||||
C_TEDust::C_TEDust()
|
||||
{
|
||||
}
|
||||
|
||||
C_TEDust::~C_TEDust()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
// Input : bNewEntity - whether or not to start a new entity
|
||||
//-----------------------------------------------------------------------------
|
||||
void C_TEDust::PostDataUpdate( DataUpdateType_t updateType )
|
||||
{
|
||||
FX_Dust( m_vecOrigin, m_vecDirection, m_flSize, m_flSpeed );
|
||||
}
|
||||
|
||||
|
||||
void TE_Dust( IRecipientFilter& filter, float delay,
|
||||
const Vector &pos, const Vector &dir, float size, float speed )
|
||||
{
|
||||
FX_Dust( pos, dir, size, speed );
|
||||
}
|
||||
@@ -0,0 +1,112 @@
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
// $NoKeywords: $
|
||||
//=============================================================================//
|
||||
|
||||
#ifndef C_FUNC_DUST_H
|
||||
#define C_FUNC_DUST_H
|
||||
#ifdef _WIN32
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
|
||||
#include "c_baseentity.h"
|
||||
#include "particles_simple.h"
|
||||
#include "particle_util.h"
|
||||
#include "bspflags.h"
|
||||
|
||||
|
||||
|
||||
// ------------------------------------------------------------------------------------ //
|
||||
// CDustEffect particle renderer.
|
||||
// ------------------------------------------------------------------------------------ //
|
||||
|
||||
class C_Func_Dust;
|
||||
|
||||
class CFuncDustParticle : public Particle
|
||||
{
|
||||
public:
|
||||
Vector m_vVelocity;
|
||||
float m_flLifetime;
|
||||
float m_flDieTime;
|
||||
float m_flSize;
|
||||
color32 m_Color;
|
||||
};
|
||||
|
||||
class CDustEffect : public CParticleEffect
|
||||
{
|
||||
public:
|
||||
CDustEffect( const char *pDebugName ) : CParticleEffect( pDebugName ) {}
|
||||
|
||||
virtual void RenderParticles( CParticleRenderIterator *pIterator );
|
||||
virtual void SimulateParticles( CParticleSimulateIterator *pIterator );
|
||||
|
||||
C_Func_Dust *m_pDust;
|
||||
|
||||
private:
|
||||
CDustEffect( const CDustEffect & ); // not defined, not accessible
|
||||
};
|
||||
|
||||
|
||||
// ------------------------------------------------------------------------------------ //
|
||||
// C_Func_Dust class.
|
||||
// ------------------------------------------------------------------------------------ //
|
||||
|
||||
class C_Func_Dust : public C_BaseEntity
|
||||
{
|
||||
public:
|
||||
DECLARE_CLASS( C_Func_Dust, C_BaseEntity );
|
||||
DECLARE_CLIENTCLASS();
|
||||
|
||||
C_Func_Dust();
|
||||
virtual ~C_Func_Dust();
|
||||
virtual void OnDataChanged( DataUpdateType_t updateType );
|
||||
virtual void ClientThink();
|
||||
virtual bool ShouldDraw();
|
||||
|
||||
|
||||
private:
|
||||
|
||||
void AttemptSpawnNewParticle();
|
||||
|
||||
|
||||
|
||||
// Vars from server.
|
||||
public:
|
||||
|
||||
color32 m_Color;
|
||||
int m_SpawnRate;
|
||||
|
||||
float m_flSizeMin;
|
||||
float m_flSizeMax;
|
||||
|
||||
int m_SpeedMax;
|
||||
|
||||
int m_LifetimeMin;
|
||||
int m_LifetimeMax;
|
||||
|
||||
int m_DistMax;
|
||||
|
||||
float m_FallSpeed; // extra 'gravity'
|
||||
|
||||
|
||||
public:
|
||||
|
||||
int m_DustFlags; // Combination of DUSTFLAGS_
|
||||
|
||||
|
||||
|
||||
public:
|
||||
CDustEffect m_Effect;
|
||||
PMaterialHandle m_hMaterial;
|
||||
TimedEvent m_Spawner;
|
||||
|
||||
private:
|
||||
C_Func_Dust( const C_Func_Dust & ); // not defined, not accessible
|
||||
};
|
||||
|
||||
|
||||
|
||||
#endif // C_FUNC_DUST_H
|
||||
@@ -0,0 +1,67 @@
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
// $NoKeywords: $
|
||||
//
|
||||
//=============================================================================//
|
||||
#include "cbase.h"
|
||||
#include "view.h"
|
||||
#include "iviewrender.h"
|
||||
|
||||
// memdbgon must be the last include file in a .cpp file!!!
|
||||
#include "tier0/memdbgon.h"
|
||||
|
||||
class C_Func_LOD : public C_BaseEntity
|
||||
{
|
||||
public:
|
||||
DECLARE_CLASS( C_Func_LOD, C_BaseEntity );
|
||||
DECLARE_CLIENTCLASS();
|
||||
|
||||
C_Func_LOD();
|
||||
|
||||
// C_BaseEntity overrides.
|
||||
public:
|
||||
|
||||
unsigned char GetClientSideFade();
|
||||
|
||||
public:
|
||||
// Replicated vars from the server.
|
||||
// These are documented in the server-side entity.
|
||||
public:
|
||||
float m_fDisappearDist;
|
||||
};
|
||||
|
||||
|
||||
ConVar lod_TransitionDist("lod_TransitionDist", "800");
|
||||
|
||||
|
||||
// ------------------------------------------------------------------------- //
|
||||
// Tables.
|
||||
// ------------------------------------------------------------------------- //
|
||||
|
||||
// Datatable..
|
||||
IMPLEMENT_CLIENTCLASS_DT(C_Func_LOD, DT_Func_LOD, CFunc_LOD)
|
||||
RecvPropFloat(RECVINFO(m_fDisappearDist)),
|
||||
END_RECV_TABLE()
|
||||
|
||||
|
||||
|
||||
// ------------------------------------------------------------------------- //
|
||||
// C_Func_LOD implementation.
|
||||
// ------------------------------------------------------------------------- //
|
||||
|
||||
C_Func_LOD::C_Func_LOD()
|
||||
{
|
||||
m_fDisappearDist = 5000.0f;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Calculate a fade.
|
||||
//-----------------------------------------------------------------------------
|
||||
unsigned char C_Func_LOD::GetClientSideFade()
|
||||
{
|
||||
return UTIL_ComputeEntityFade( this, m_fDisappearDist, m_fDisappearDist + lod_TransitionDist.GetFloat(), 1.0f );
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,51 @@
|
||||
//========= 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_FuncOccluder : public C_BaseEntity
|
||||
{
|
||||
public:
|
||||
DECLARE_CLIENTCLASS();
|
||||
DECLARE_CLASS( C_FuncOccluder, C_BaseEntity );
|
||||
|
||||
// Overrides.
|
||||
public:
|
||||
virtual bool ShouldDraw();
|
||||
virtual int DrawModel( int flags );
|
||||
virtual void OnDataChanged( DataUpdateType_t updateType );
|
||||
|
||||
private:
|
||||
int m_nOccluderIndex;
|
||||
bool m_bActive;
|
||||
};
|
||||
|
||||
IMPLEMENT_CLIENTCLASS_DT( C_FuncOccluder, DT_FuncOccluder, CFuncOccluder )
|
||||
RecvPropBool( RECVINFO( m_bActive ) ),
|
||||
RecvPropInt( RECVINFO(m_nOccluderIndex) ),
|
||||
END_RECV_TABLE()
|
||||
|
||||
|
||||
void C_FuncOccluder::OnDataChanged( DataUpdateType_t updateType )
|
||||
{
|
||||
BaseClass::OnDataChanged( updateType );
|
||||
engine->ActivateOccluder( m_nOccluderIndex, m_bActive );
|
||||
}
|
||||
|
||||
bool C_FuncOccluder::ShouldDraw()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
int C_FuncOccluder::DrawModel( int flags )
|
||||
{
|
||||
Assert(0);
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,118 @@
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
// $NoKeywords: $
|
||||
//===========================================================================//
|
||||
#include "cbase.h"
|
||||
#include "view_shared.h"
|
||||
|
||||
// memdbgon must be the last include file in a .cpp file!!!
|
||||
#include "tier0/memdbgon.h"
|
||||
|
||||
class C_FuncReflectiveGlass : public C_BaseEntity
|
||||
{
|
||||
public:
|
||||
DECLARE_CLASS( C_FuncReflectiveGlass, C_BaseEntity );
|
||||
DECLARE_CLIENTCLASS();
|
||||
|
||||
// C_BaseEntity.
|
||||
public:
|
||||
C_FuncReflectiveGlass();
|
||||
virtual ~C_FuncReflectiveGlass();
|
||||
|
||||
virtual bool ShouldDraw();
|
||||
|
||||
C_FuncReflectiveGlass *m_pNext;
|
||||
};
|
||||
|
||||
IMPLEMENT_CLIENTCLASS_DT( C_FuncReflectiveGlass, DT_FuncReflectiveGlass, CFuncReflectiveGlass )
|
||||
END_RECV_TABLE()
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Globals
|
||||
//-----------------------------------------------------------------------------
|
||||
C_EntityClassList<C_FuncReflectiveGlass> g_ReflectiveGlassList;
|
||||
template<> C_FuncReflectiveGlass *C_EntityClassList<C_FuncReflectiveGlass>::m_pClassList = NULL;
|
||||
|
||||
C_FuncReflectiveGlass* GetReflectiveGlassList()
|
||||
{
|
||||
return g_ReflectiveGlassList.m_pClassList;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Constructor, destructor
|
||||
//-----------------------------------------------------------------------------
|
||||
C_FuncReflectiveGlass::C_FuncReflectiveGlass()
|
||||
{
|
||||
g_ReflectiveGlassList.Insert( this );
|
||||
}
|
||||
|
||||
C_FuncReflectiveGlass::~C_FuncReflectiveGlass()
|
||||
{
|
||||
g_ReflectiveGlassList.Remove( this );
|
||||
}
|
||||
|
||||
|
||||
bool C_FuncReflectiveGlass::ShouldDraw()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Do we have reflective glass in view?
|
||||
//-----------------------------------------------------------------------------
|
||||
bool IsReflectiveGlassInView( const CViewSetup& view, cplane_t &plane )
|
||||
{
|
||||
// Early out if no cameras
|
||||
C_FuncReflectiveGlass *pReflectiveGlass = GetReflectiveGlassList();
|
||||
if ( !pReflectiveGlass )
|
||||
return false;
|
||||
|
||||
Frustum_t frustum;
|
||||
GeneratePerspectiveFrustum( view.origin, view.angles, view.zNear, view.zFar, view.fov, view.m_flAspectRatio, frustum );
|
||||
|
||||
cplane_t localPlane;
|
||||
Vector vecOrigin, vecWorld, vecDelta, vecForward;
|
||||
AngleVectors( view.angles, &vecForward, NULL, NULL );
|
||||
|
||||
for ( ; pReflectiveGlass != NULL; pReflectiveGlass = pReflectiveGlass->m_pNext )
|
||||
{
|
||||
if ( pReflectiveGlass->IsDormant() )
|
||||
continue;
|
||||
|
||||
Vector vecMins, vecMaxs;
|
||||
pReflectiveGlass->GetRenderBoundsWorldspace( vecMins, vecMaxs );
|
||||
if ( R_CullBox( vecMins, vecMaxs, frustum ) )
|
||||
continue;
|
||||
|
||||
const model_t *pModel = pReflectiveGlass->GetModel();
|
||||
const matrix3x4_t& mat = pReflectiveGlass->EntityToWorldTransform();
|
||||
|
||||
int nCount = modelinfo->GetBrushModelPlaneCount( pModel );
|
||||
for ( int i = 0; i < nCount; ++i )
|
||||
{
|
||||
modelinfo->GetBrushModelPlane( pModel, i, localPlane, &vecOrigin );
|
||||
|
||||
MatrixTransformPlane( mat, localPlane, plane ); // Transform to world space
|
||||
VectorTransform( vecOrigin, mat, vecWorld );
|
||||
|
||||
if ( view.origin.Dot( plane.normal ) <= plane.dist ) // Check for view behind plane
|
||||
continue;
|
||||
|
||||
VectorSubtract( vecWorld, view.origin, vecDelta ); // Backface cull
|
||||
if ( vecDelta.Dot( plane.normal ) >= 0 )
|
||||
continue;
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,27 @@
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
// $NoKeywords: $
|
||||
//===========================================================================//
|
||||
|
||||
#ifndef C_FUNC_REFLECTIVE_GLASS
|
||||
#define C_FUNC_REFLECTIVE_GLASS
|
||||
|
||||
#ifdef _WIN32
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
struct cplane_t;
|
||||
class CViewSetup;
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Do we have reflective glass in view? If so, what's the reflection plane?
|
||||
//-----------------------------------------------------------------------------
|
||||
bool IsReflectiveGlassInView( const CViewSetup& view, cplane_t &plane );
|
||||
|
||||
|
||||
#endif // C_FUNC_REFLECTIVE_GLASS
|
||||
|
||||
|
||||
@@ -0,0 +1,43 @@
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
//===========================================================================//
|
||||
|
||||
#include "cbase.h"
|
||||
#include <KeyValues.h>
|
||||
|
||||
// memdbgon must be the last include file in a .cpp file!!!
|
||||
#include "tier0/memdbgon.h"
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
class C_FuncRotating : public C_BaseEntity
|
||||
{
|
||||
public:
|
||||
DECLARE_CLASS( C_FuncRotating, C_BaseEntity );
|
||||
DECLARE_CLIENTCLASS();
|
||||
|
||||
C_FuncRotating();
|
||||
|
||||
private:
|
||||
};
|
||||
|
||||
extern void RecvProxy_SimulationTime( const CRecvProxyData *pData, void *pStruct, void *pOut );
|
||||
|
||||
IMPLEMENT_CLIENTCLASS_DT( C_FuncRotating, DT_FuncRotating, CFuncRotating )
|
||||
RecvPropVector( RECVINFO_NAME( m_vecNetworkOrigin, m_vecOrigin ) ),
|
||||
RecvPropFloat( RECVINFO_NAME( m_angNetworkAngles[0], m_angRotation[0] ) ),
|
||||
RecvPropFloat( RECVINFO_NAME( m_angNetworkAngles[1], m_angRotation[1] ) ),
|
||||
RecvPropFloat( RECVINFO_NAME( m_angNetworkAngles[2], m_angRotation[2] ) ),
|
||||
RecvPropInt( RECVINFO(m_flSimulationTime), 0, RecvProxy_SimulationTime ),
|
||||
END_RECV_TABLE()
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
C_FuncRotating::C_FuncRotating()
|
||||
{
|
||||
}
|
||||
@@ -0,0 +1,638 @@
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
// $NoKeywords: $
|
||||
//=============================================================================//
|
||||
#include "cbase.h"
|
||||
#include "c_smoke_trail.h"
|
||||
#include "smoke_fog_overlay.h"
|
||||
#include "engine/IEngineTrace.h"
|
||||
|
||||
// memdbgon must be the last include file in a .cpp file!!!
|
||||
#include "tier0/memdbgon.h"
|
||||
|
||||
#define SF_EMISSIVE 0x00000001
|
||||
|
||||
// ------------------------------------------------------------------------- //
|
||||
// Definitions
|
||||
// ------------------------------------------------------------------------- //
|
||||
|
||||
static Vector s_FadePlaneDirections[] =
|
||||
{
|
||||
Vector( 1,0,0),
|
||||
Vector(-1,0,0),
|
||||
Vector(0, 1,0),
|
||||
Vector(0,-1,0),
|
||||
Vector(0,0, 1),
|
||||
Vector(0,0,-1)
|
||||
};
|
||||
#define NUM_FADE_PLANES (sizeof(s_FadePlaneDirections)/sizeof(s_FadePlaneDirections[0]))
|
||||
|
||||
// ------------------------------------------------------------------------- //
|
||||
// Classes
|
||||
// ------------------------------------------------------------------------- //
|
||||
class C_FuncSmokeVolume : public C_BaseParticleEntity, public IPrototypeAppEffect
|
||||
{
|
||||
public:
|
||||
DECLARE_CLASS( C_FuncSmokeVolume, C_BaseParticleEntity );
|
||||
DECLARE_CLIENTCLASS();
|
||||
|
||||
C_FuncSmokeVolume();
|
||||
~C_FuncSmokeVolume();
|
||||
|
||||
int IsEmissive( void ) { return ( m_spawnflags & SF_EMISSIVE ); }
|
||||
|
||||
private:
|
||||
class SmokeGrenadeParticle : public Particle
|
||||
{
|
||||
public:
|
||||
float m_RotationFactor;
|
||||
float m_CurRotation;
|
||||
float m_FadeAlpha; // Set as it moves around.
|
||||
unsigned char m_ColorInterp; // Amount between min and max colors.
|
||||
unsigned char m_Color[4];
|
||||
};
|
||||
|
||||
// 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 );
|
||||
virtual void NotifyRemove();
|
||||
|
||||
private:
|
||||
// The SmokeEmitter represents a grid in 3D space.
|
||||
class SmokeParticleInfo
|
||||
{
|
||||
public:
|
||||
SmokeGrenadeParticle *m_pParticle;
|
||||
int m_TradeIndex; // -1 if not exchanging yet.
|
||||
float m_TradeClock; // How long since they started trading.
|
||||
float m_TradeDuration; // How long the trade will take to finish.
|
||||
float m_FadeAlpha; // Calculated from nearby world geometry.
|
||||
unsigned char m_Color[4];
|
||||
};
|
||||
|
||||
inline int GetSmokeParticleIndex(int x, int y, int z)
|
||||
{
|
||||
Assert( IsValidXYZCoords( x, y, z ) );
|
||||
return z*m_xCount*m_yCount+y*m_xCount+x;
|
||||
}
|
||||
|
||||
inline SmokeParticleInfo *GetSmokeParticleInfo(int x, int y, int z)
|
||||
{
|
||||
Assert( IsValidXYZCoords( x, y, z ) );
|
||||
return &m_pSmokeParticleInfos[GetSmokeParticleIndex(x,y,z)];
|
||||
}
|
||||
|
||||
inline void GetParticleInfoXYZ(int index_, int &x, int &y, int &z)
|
||||
{
|
||||
Assert( index_ >= 0 && index_ < m_xCount * m_yCount * m_zCount );
|
||||
z = index_ / (m_xCount*m_yCount);
|
||||
int zIndex = z*m_xCount*m_yCount;
|
||||
y = (index_ - zIndex) / m_xCount;
|
||||
int yIndex = y*m_xCount;
|
||||
x = index_ - zIndex - yIndex;
|
||||
Assert( IsValidXYZCoords( x, y, z ) );
|
||||
}
|
||||
|
||||
inline bool IsValidXYZCoords(int x, int y, int z)
|
||||
{
|
||||
return x >= 0 && y >= 0 && z >= 0 && x < m_xCount && y < m_yCount && z < m_zCount;
|
||||
}
|
||||
|
||||
inline Vector GetSmokeParticlePos(int x, int y, int z )
|
||||
{
|
||||
return WorldAlignMins() +
|
||||
Vector( x * m_SpacingRadius * 2 + m_SpacingRadius,
|
||||
y * m_SpacingRadius * 2 + m_SpacingRadius,
|
||||
z * m_SpacingRadius * 2 + m_SpacingRadius );
|
||||
}
|
||||
|
||||
inline Vector GetSmokeParticlePosIndex(int index_ )
|
||||
{
|
||||
int x, y, z;
|
||||
GetParticleInfoXYZ( index_, x, y, z);
|
||||
return GetSmokeParticlePos(x, y, z);
|
||||
}
|
||||
|
||||
// Start filling the smoke volume
|
||||
void FillVolume();
|
||||
|
||||
private:
|
||||
// State variables from server.
|
||||
color32 m_Color1;
|
||||
color32 m_Color2;
|
||||
char m_MaterialName[255];
|
||||
float m_ParticleDrawWidth;
|
||||
float m_ParticleSpacingDistance;
|
||||
float m_DensityRampSpeed;
|
||||
float m_RotationSpeed;
|
||||
float m_MovementSpeed;
|
||||
float m_Density;
|
||||
int m_spawnflags;
|
||||
|
||||
private:
|
||||
C_FuncSmokeVolume( const C_FuncSmokeVolume & );
|
||||
|
||||
float m_CurrentDensity;
|
||||
float m_ParticleRadius;
|
||||
bool m_bStarted;
|
||||
|
||||
PMaterialHandle m_MaterialHandle;
|
||||
|
||||
SmokeParticleInfo *m_pSmokeParticleInfos;
|
||||
int m_xCount, m_yCount, m_zCount;
|
||||
float m_SpacingRadius;
|
||||
|
||||
Vector m_MinColor;
|
||||
Vector m_MaxColor;
|
||||
|
||||
Vector m_vLastOrigin;
|
||||
QAngle m_vLastAngles;
|
||||
bool m_bFirstUpdate;
|
||||
};
|
||||
|
||||
IMPLEMENT_CLIENTCLASS_DT( C_FuncSmokeVolume, DT_FuncSmokeVolume, CFuncSmokeVolume )
|
||||
RecvPropInt( RECVINFO( m_Color1 ), 0, RecvProxy_IntToColor32 ),
|
||||
RecvPropInt( RECVINFO( m_Color2 ), 0, RecvProxy_IntToColor32 ),
|
||||
RecvPropString( RECVINFO( m_MaterialName ) ),
|
||||
RecvPropFloat( RECVINFO( m_ParticleDrawWidth ) ),
|
||||
RecvPropFloat( RECVINFO( m_ParticleSpacingDistance ) ),
|
||||
RecvPropFloat( RECVINFO( m_DensityRampSpeed ) ),
|
||||
RecvPropFloat( RECVINFO( m_RotationSpeed ) ),
|
||||
RecvPropFloat( RECVINFO( m_MovementSpeed ) ),
|
||||
RecvPropFloat( RECVINFO( m_Density ) ),
|
||||
RecvPropInt( RECVINFO( m_spawnflags ) ),
|
||||
RecvPropDataTable( RECVINFO_DT( m_Collision ), 0, &REFERENCE_RECV_TABLE(DT_CollisionProperty) ),
|
||||
END_RECV_TABLE()
|
||||
|
||||
// Helpers.
|
||||
// ------------------------------------------------------------------------- //
|
||||
|
||||
static inline void InterpColor(unsigned char dest[4], unsigned char src1[4], unsigned char src2[4], float percent)
|
||||
{
|
||||
dest[0] = (unsigned char)(src1[0] + (src2[0] - src1[0]) * percent);
|
||||
dest[1] = (unsigned char)(src1[1] + (src2[1] - src1[1]) * percent);
|
||||
dest[2] = (unsigned char)(src1[2] + (src2[2] - src1[2]) * percent);
|
||||
}
|
||||
|
||||
|
||||
static inline int GetWorldPointContents(const Vector &vPos)
|
||||
{
|
||||
#if defined(PARTICLEPROTOTYPE_APP)
|
||||
return 0;
|
||||
#else
|
||||
return enginetrace->GetPointContents( vPos );
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline void WorldTraceLine( const Vector &start, const Vector &end, int contentsMask, trace_t *trace )
|
||||
{
|
||||
#if defined(PARTICLEPROTOTYPE_APP)
|
||||
trace->fraction = 1;
|
||||
#else
|
||||
UTIL_TraceLine(start, end, contentsMask, NULL, COLLISION_GROUP_NONE, trace);
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline Vector EngineGetLightForPoint(const Vector &vPos)
|
||||
{
|
||||
#if defined(PARTICLEPROTOTYPE_APP)
|
||||
return Vector(1,1,1);
|
||||
#else
|
||||
return engine->GetLightForPoint(vPos, true);
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline Vector& EngineGetVecRenderOrigin()
|
||||
{
|
||||
#if defined(PARTICLEPROTOTYPE_APP)
|
||||
static Vector dummy(0,0,0);
|
||||
return dummy;
|
||||
#else
|
||||
extern Vector g_vecRenderOrigin;
|
||||
return g_vecRenderOrigin;
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline float& EngineGetSmokeFogOverlayAlpha()
|
||||
{
|
||||
#if defined(PARTICLEPROTOTYPE_APP)
|
||||
static float dummy;
|
||||
return dummy;
|
||||
#else
|
||||
return g_SmokeFogOverlayAlpha;
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline C_BaseEntity* ParticleGetEntity( int index )
|
||||
{
|
||||
#if defined(PARTICLEPROTOTYPE_APP)
|
||||
return NULL;
|
||||
#else
|
||||
return cl_entitylist->GetEnt( index );
|
||||
#endif
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------- //
|
||||
// C_FuncSmokeVolume
|
||||
// ------------------------------------------------------------------------- //
|
||||
C_FuncSmokeVolume::C_FuncSmokeVolume()
|
||||
{
|
||||
m_bFirstUpdate = true;
|
||||
m_vLastOrigin.Init();
|
||||
m_vLastAngles.Init();
|
||||
|
||||
m_pSmokeParticleInfos = NULL;
|
||||
m_SpacingRadius = 0.0f;
|
||||
m_ParticleRadius = 0.0f;
|
||||
m_MinColor.Init( 1.0, 1.0, 1.0 );
|
||||
m_MaxColor.Init( 1.0, 1.0, 1.0 );
|
||||
}
|
||||
|
||||
C_FuncSmokeVolume::~C_FuncSmokeVolume()
|
||||
{
|
||||
delete [] m_pSmokeParticleInfos;
|
||||
}
|
||||
|
||||
static ConVar mat_reduceparticles( "mat_reduceparticles", "0" );
|
||||
|
||||
void C_FuncSmokeVolume::OnDataChanged( DataUpdateType_t updateType )
|
||||
{
|
||||
m_MinColor[0] = ( 1.0f / 255.0f ) * m_Color1.r;
|
||||
m_MinColor[1] = ( 1.0f / 255.0f ) * m_Color1.g;
|
||||
m_MinColor[2] = ( 1.0f / 255.0f ) * m_Color1.b;
|
||||
|
||||
m_MaxColor[0] = ( 1.0f / 255.0f ) * m_Color2.r;
|
||||
m_MaxColor[1] = ( 1.0f / 255.0f ) * m_Color2.g;
|
||||
m_MaxColor[2] = ( 1.0f / 255.0f ) * m_Color2.b;
|
||||
|
||||
if ( mat_reduceparticles.GetBool() )
|
||||
{
|
||||
m_Density *= 0.5f;
|
||||
m_ParticleSpacingDistance *= 1.5f;
|
||||
}
|
||||
|
||||
m_ParticleRadius = m_ParticleDrawWidth * 0.5f;
|
||||
m_SpacingRadius = m_ParticleSpacingDistance * 0.5f;
|
||||
|
||||
m_ParticleEffect.SetParticleCullRadius( m_ParticleRadius );
|
||||
|
||||
// Warning( "m_Density: %f\n", m_Density );
|
||||
// Warning( "m_MovementSpeed: %f\n", m_MovementSpeed );
|
||||
|
||||
if( updateType == DATA_UPDATE_CREATED )
|
||||
{
|
||||
Vector size = WorldAlignMaxs() - WorldAlignMins();
|
||||
m_xCount = 0.5f + ( size.x / ( m_SpacingRadius * 2.0f ) );
|
||||
m_yCount = 0.5f + ( size.y / ( m_SpacingRadius * 2.0f ) );
|
||||
m_zCount = 0.5f + ( size.z / ( m_SpacingRadius * 2.0f ) );
|
||||
m_CurrentDensity = m_Density;
|
||||
|
||||
delete [] m_pSmokeParticleInfos;
|
||||
m_pSmokeParticleInfos = new SmokeParticleInfo[m_xCount * m_yCount * m_zCount];
|
||||
Start( ParticleMgr(), NULL );
|
||||
}
|
||||
BaseClass::OnDataChanged( updateType );
|
||||
}
|
||||
|
||||
void C_FuncSmokeVolume::Start( CParticleMgr *pParticleMgr, IPrototypeArgAccess *pArgs )
|
||||
{
|
||||
if( !pParticleMgr->AddEffect( &m_ParticleEffect, this ) )
|
||||
return;
|
||||
|
||||
m_MaterialHandle = m_ParticleEffect.FindOrAddMaterial( m_MaterialName );
|
||||
FillVolume();
|
||||
|
||||
m_bStarted = true;
|
||||
}
|
||||
|
||||
|
||||
void C_FuncSmokeVolume::Update( float fTimeDelta )
|
||||
{
|
||||
// Update our world space bbox if we've moved at all.
|
||||
// We do this manually because sometimes people make HUGE bboxes, and if they're constantly changing because their
|
||||
// particles wander outside the current bounds sometimes, it'll be linking them into all the leaves repeatedly.
|
||||
const Vector &curOrigin = GetAbsOrigin();
|
||||
const QAngle &curAngles = GetAbsAngles();
|
||||
if ( !VectorsAreEqual( curOrigin, m_vLastOrigin, 0.1 ) ||
|
||||
fabs( curAngles.x - m_vLastAngles.x ) > 0.1 ||
|
||||
fabs( curAngles.y - m_vLastAngles.y ) > 0.1 ||
|
||||
fabs( curAngles.z - m_vLastAngles.z ) > 0.1 ||
|
||||
m_bFirstUpdate )
|
||||
{
|
||||
m_bFirstUpdate = false;
|
||||
m_vLastAngles = curAngles;
|
||||
m_vLastOrigin = curOrigin;
|
||||
|
||||
Vector vWorldMins, vWorldMaxs;
|
||||
CollisionProp()->WorldSpaceAABB( &vWorldMins, &vWorldMaxs );
|
||||
vWorldMins -= Vector( m_ParticleRadius, m_ParticleRadius, m_ParticleRadius );
|
||||
vWorldMaxs += Vector( m_ParticleRadius, m_ParticleRadius, m_ParticleRadius );
|
||||
|
||||
m_ParticleEffect.SetBBox( vWorldMins, vWorldMaxs );
|
||||
}
|
||||
|
||||
// lerp m_CurrentDensity towards m_Density at a rate of m_DensityRampSpeed
|
||||
if( m_CurrentDensity < m_Density )
|
||||
{
|
||||
m_CurrentDensity += m_DensityRampSpeed * fTimeDelta;
|
||||
if( m_CurrentDensity > m_Density )
|
||||
{
|
||||
m_CurrentDensity = m_Density;
|
||||
}
|
||||
}
|
||||
else if( m_CurrentDensity > m_Density )
|
||||
{
|
||||
m_CurrentDensity -= m_DensityRampSpeed * fTimeDelta;
|
||||
if( m_CurrentDensity < m_Density )
|
||||
{
|
||||
m_CurrentDensity = m_Density;
|
||||
}
|
||||
}
|
||||
|
||||
if( m_CurrentDensity == 0.0f )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// This is used to randomize the direction it chooses to move a particle in.
|
||||
|
||||
int offsetLookup[3] = {-1,0,1};
|
||||
|
||||
float tradeDurationMax = m_ParticleSpacingDistance / ( m_MovementSpeed + 0.1f );
|
||||
float tradeDurationMin = tradeDurationMax * 0.5f;
|
||||
|
||||
if ( IS_NAN( tradeDurationMax ) || IS_NAN( tradeDurationMin ) )
|
||||
return;
|
||||
|
||||
// Warning( "tradeDuration: [%f,%f]\n", tradeDurationMin, tradeDurationMax );
|
||||
|
||||
// Update all the moving traders and establish new ones.
|
||||
int nTotal = m_xCount * m_yCount * m_zCount;
|
||||
for( int i=0; i < nTotal; i++ )
|
||||
{
|
||||
SmokeParticleInfo *pInfo = &m_pSmokeParticleInfos[i];
|
||||
|
||||
if(!pInfo->m_pParticle)
|
||||
continue;
|
||||
|
||||
if(pInfo->m_TradeIndex == -1)
|
||||
{
|
||||
pInfo->m_pParticle->m_FadeAlpha = pInfo->m_FadeAlpha;
|
||||
pInfo->m_pParticle->m_Color[0] = pInfo->m_Color[0];
|
||||
pInfo->m_pParticle->m_Color[1] = pInfo->m_Color[1];
|
||||
pInfo->m_pParticle->m_Color[2] = pInfo->m_Color[2];
|
||||
|
||||
// Is there an adjacent one that's not trading?
|
||||
int x, y, z;
|
||||
GetParticleInfoXYZ(i, x, y, z);
|
||||
|
||||
int xCountOffset = rand();
|
||||
int yCountOffset = rand();
|
||||
int zCountOffset = rand();
|
||||
|
||||
bool bFound = false;
|
||||
for(int xCount=0; xCount < 3 && !bFound; xCount++)
|
||||
{
|
||||
for(int yCount=0; yCount < 3 && !bFound; yCount++)
|
||||
{
|
||||
for(int zCount=0; zCount < 3; zCount++)
|
||||
{
|
||||
int testX = x + offsetLookup[(xCount+xCountOffset) % 3];
|
||||
int testY = y + offsetLookup[(yCount+yCountOffset) % 3];
|
||||
int testZ = z + offsetLookup[(zCount+zCountOffset) % 3];
|
||||
|
||||
if(testX == x && testY == y && testZ == z)
|
||||
continue;
|
||||
|
||||
if(IsValidXYZCoords(testX, testY, testZ))
|
||||
{
|
||||
SmokeParticleInfo *pOther = GetSmokeParticleInfo(testX, testY, testZ);
|
||||
if(pOther->m_pParticle && pOther->m_TradeIndex == -1)
|
||||
{
|
||||
// Ok, this one is looking to trade also.
|
||||
pInfo->m_TradeIndex = GetSmokeParticleIndex(testX, testY, testZ);
|
||||
pOther->m_TradeIndex = i;
|
||||
pInfo->m_TradeClock = pOther->m_TradeClock = 0;
|
||||
pOther->m_TradeDuration = pInfo->m_TradeDuration = FRand( tradeDurationMin, tradeDurationMax );
|
||||
|
||||
bFound = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
SmokeParticleInfo *pOther = &m_pSmokeParticleInfos[pInfo->m_TradeIndex];
|
||||
assert(pOther->m_TradeIndex == i);
|
||||
|
||||
// This makes sure the trade only gets updated once per frame.
|
||||
if(pInfo < pOther)
|
||||
{
|
||||
// Increment the trade clock..
|
||||
pInfo->m_TradeClock = (pOther->m_TradeClock += fTimeDelta);
|
||||
int x, y, z;
|
||||
GetParticleInfoXYZ(i, x, y, z);
|
||||
Vector myPos = GetSmokeParticlePos(x, y, z);
|
||||
|
||||
int otherX, otherY, otherZ;
|
||||
GetParticleInfoXYZ(pInfo->m_TradeIndex, otherX, otherY, otherZ);
|
||||
Vector otherPos = GetSmokeParticlePos(otherX, otherY, otherZ);
|
||||
|
||||
// Is the trade finished?
|
||||
if(pInfo->m_TradeClock >= pInfo->m_TradeDuration)
|
||||
{
|
||||
pInfo->m_TradeIndex = pOther->m_TradeIndex = -1;
|
||||
|
||||
pInfo->m_pParticle->m_Pos = otherPos;
|
||||
pOther->m_pParticle->m_Pos = myPos;
|
||||
|
||||
SmokeGrenadeParticle *temp = pInfo->m_pParticle;
|
||||
pInfo->m_pParticle = pOther->m_pParticle;
|
||||
pOther->m_pParticle = temp;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Ok, move them closer.
|
||||
float percent = (float)cos(pInfo->m_TradeClock * 2 * 1.57079632f / pInfo->m_TradeDuration);
|
||||
percent = percent * 0.5 + 0.5;
|
||||
|
||||
pInfo->m_pParticle->m_FadeAlpha = pInfo->m_FadeAlpha + (pOther->m_FadeAlpha - pInfo->m_FadeAlpha) * (1 - percent);
|
||||
pOther->m_pParticle->m_FadeAlpha = pInfo->m_FadeAlpha + (pOther->m_FadeAlpha - pInfo->m_FadeAlpha) * percent;
|
||||
|
||||
InterpColor(pInfo->m_pParticle->m_Color, pInfo->m_Color, pOther->m_Color, 1-percent);
|
||||
InterpColor(pOther->m_pParticle->m_Color, pInfo->m_Color, pOther->m_Color, percent);
|
||||
|
||||
pInfo->m_pParticle->m_Pos = myPos + (otherPos - myPos) * (1 - percent);
|
||||
pOther->m_pParticle->m_Pos = myPos + (otherPos - myPos) * percent;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void C_FuncSmokeVolume::RenderParticles( CParticleRenderIterator *pIterator )
|
||||
{
|
||||
if ( m_CurrentDensity == 0 )
|
||||
return;
|
||||
|
||||
const SmokeGrenadeParticle *pParticle = (const SmokeGrenadeParticle*)pIterator->GetFirst();
|
||||
while ( pParticle )
|
||||
{
|
||||
Vector renderPos = pParticle->m_Pos;
|
||||
|
||||
// Fade out globally.
|
||||
float alpha = m_CurrentDensity;
|
||||
|
||||
// Apply the precalculated fade alpha from world geometry.
|
||||
alpha *= pParticle->m_FadeAlpha;
|
||||
|
||||
// TODO: optimize this whole routine!
|
||||
Vector color = m_MinColor + (m_MaxColor - m_MinColor) * (pParticle->m_ColorInterp / 255.1f);
|
||||
if ( IsEmissive() )
|
||||
{
|
||||
color.x += pParticle->m_Color[0] / 255.0f;
|
||||
color.y += pParticle->m_Color[1] / 255.0f;
|
||||
color.z += pParticle->m_Color[2] / 255.0f;
|
||||
|
||||
color.x = clamp( color.x, 0.0f, 1.0f );
|
||||
color.y = clamp( color.y, 0.0f, 1.0f );
|
||||
color.z = clamp( color.z, 0.0f, 1.0f );
|
||||
}
|
||||
else
|
||||
{
|
||||
color.x *= pParticle->m_Color[0] / 255.0f;
|
||||
color.y *= pParticle->m_Color[1] / 255.0f;
|
||||
color.z *= pParticle->m_Color[2] / 255.0f;
|
||||
}
|
||||
|
||||
Vector tRenderPos;
|
||||
TransformParticle( ParticleMgr()->GetModelView(), renderPos, tRenderPos );
|
||||
float sortKey = 1;//tRenderPos.z;
|
||||
|
||||
// If we're reducing particle cost, only render sufficiently opaque particles
|
||||
if ( ( alpha > 0.05f ) || !mat_reduceparticles.GetBool() )
|
||||
{
|
||||
RenderParticle_ColorSizeAngle(
|
||||
pIterator->GetParticleDraw(),
|
||||
tRenderPos,
|
||||
color,
|
||||
alpha * GetAlphaDistanceFade(tRenderPos, 10, 30), // Alpha
|
||||
m_ParticleRadius,
|
||||
pParticle->m_CurRotation
|
||||
);
|
||||
}
|
||||
|
||||
pParticle = (const SmokeGrenadeParticle*)pIterator->GetNext( sortKey );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void C_FuncSmokeVolume::SimulateParticles( CParticleSimulateIterator *pIterator )
|
||||
{
|
||||
if ( m_CurrentDensity == 0 )
|
||||
return;
|
||||
|
||||
SmokeGrenadeParticle *pParticle = (SmokeGrenadeParticle*)pIterator->GetFirst();
|
||||
while ( pParticle )
|
||||
{
|
||||
pParticle->m_CurRotation += pParticle->m_RotationFactor * ( M_PI / 180.0f ) * m_RotationSpeed * pIterator->GetTimeDelta();
|
||||
pParticle = (SmokeGrenadeParticle*)pIterator->GetNext();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void C_FuncSmokeVolume::NotifyRemove()
|
||||
{
|
||||
m_xCount = m_yCount = m_zCount = 0;
|
||||
}
|
||||
|
||||
|
||||
void C_FuncSmokeVolume::FillVolume()
|
||||
{
|
||||
Vector vPos;
|
||||
for(int x=0; x < m_xCount; x++)
|
||||
{
|
||||
for(int y=0; y < m_yCount; y++)
|
||||
{
|
||||
for(int z=0; z < m_zCount; z++)
|
||||
{
|
||||
vPos = GetSmokeParticlePos( x, y, z );
|
||||
if(SmokeParticleInfo *pInfo = GetSmokeParticleInfo(x,y,z))
|
||||
{
|
||||
int contents = GetWorldPointContents(vPos);
|
||||
if(contents & CONTENTS_SOLID)
|
||||
{
|
||||
pInfo->m_pParticle = NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
SmokeGrenadeParticle *pParticle =
|
||||
(SmokeGrenadeParticle*)m_ParticleEffect.AddParticle(sizeof(SmokeGrenadeParticle), m_MaterialHandle);
|
||||
|
||||
if(pParticle)
|
||||
{
|
||||
pParticle->m_Pos = vPos;
|
||||
pParticle->m_ColorInterp = (unsigned char)((rand() * 255) / VALVE_RAND_MAX);
|
||||
pParticle->m_RotationFactor = FRand( -1.0f, 1.0f ); // Rotation factor.
|
||||
pParticle->m_CurRotation = FRand( -m_RotationSpeed, m_RotationSpeed );
|
||||
}
|
||||
|
||||
#ifdef _DEBUG
|
||||
int testX, testY, testZ;
|
||||
int index_ = GetSmokeParticleIndex(x,y,z);
|
||||
GetParticleInfoXYZ( index_, testX, testY, testZ);
|
||||
assert(testX == x && testY == y && testZ == z);
|
||||
#endif
|
||||
|
||||
Vector vColor = EngineGetLightForPoint(vPos);
|
||||
pInfo->m_Color[0] = LinearToTexture( vColor.x );
|
||||
pInfo->m_Color[1] = LinearToTexture( vColor.y );
|
||||
pInfo->m_Color[2] = LinearToTexture( vColor.z );
|
||||
|
||||
// Cast some rays and if it's too close to anything, fade its alpha down.
|
||||
pInfo->m_FadeAlpha = 1;
|
||||
|
||||
for(int i=0; i < NUM_FADE_PLANES; i++)
|
||||
{
|
||||
trace_t trace;
|
||||
WorldTraceLine(vPos, vPos + s_FadePlaneDirections[i] * 100, MASK_SOLID_BRUSHONLY, &trace);
|
||||
if(trace.fraction < 1.0f)
|
||||
{
|
||||
float dist = DotProduct(trace.plane.normal, vPos) - trace.plane.dist;
|
||||
if(dist < 0)
|
||||
{
|
||||
pInfo->m_FadeAlpha = 0;
|
||||
}
|
||||
else if(dist < m_ParticleRadius)
|
||||
{
|
||||
float alphaScale = dist / m_ParticleRadius;
|
||||
alphaScale *= alphaScale * alphaScale;
|
||||
pInfo->m_FadeAlpha *= alphaScale;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pInfo->m_pParticle = pParticle;
|
||||
pInfo->m_TradeIndex = -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,122 @@
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
// $NoKeywords: $
|
||||
//=============================================================================//
|
||||
|
||||
#include "cbase.h"
|
||||
#include "c_baseentity.h"
|
||||
#include "soundinfo.h"
|
||||
|
||||
// memdbgon must be the last include file in a .cpp file!!!
|
||||
#include "tier0/memdbgon.h"
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// An entity which emits other entities at points
|
||||
//-----------------------------------------------------------------------------
|
||||
class C_FuncTrackTrain : public C_BaseEntity
|
||||
{
|
||||
public:
|
||||
DECLARE_CLASS( C_FuncTrackTrain, C_BaseEntity );
|
||||
DECLARE_CLIENTCLASS();
|
||||
|
||||
public:
|
||||
virtual void OnDataChanged( DataUpdateType_t updateType );
|
||||
virtual bool GetSoundSpatialization( SpatializationInfo_t& info );
|
||||
|
||||
virtual bool IsBaseTrain( void ) const { return true; }
|
||||
|
||||
|
||||
private:
|
||||
int m_nLongAxis;
|
||||
float m_flRadius;
|
||||
float m_flLineLength;
|
||||
};
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Datatable
|
||||
//-----------------------------------------------------------------------------
|
||||
IMPLEMENT_CLIENTCLASS_DT( C_FuncTrackTrain, DT_FuncTrackTrain, CFuncTrackTrain )
|
||||
END_RECV_TABLE()
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Sound spatialization
|
||||
//-----------------------------------------------------------------------------
|
||||
void C_FuncTrackTrain::OnDataChanged( DataUpdateType_t updateType )
|
||||
{
|
||||
BaseClass::OnDataChanged( updateType );
|
||||
|
||||
if (updateType == DATA_UPDATE_CREATED)
|
||||
{
|
||||
// Compute the cross-sectional area and dimension and length of the line segment
|
||||
int nIndex1, nIndex2;
|
||||
const Vector &vecOBBSize = CollisionProp()->OBBSize();
|
||||
if ( ( vecOBBSize.x > vecOBBSize.y ) && ( vecOBBSize.x > vecOBBSize.z ) )
|
||||
{
|
||||
m_nLongAxis = 0;
|
||||
nIndex1 = 1; nIndex2 = 2;
|
||||
}
|
||||
else if ( vecOBBSize.y > vecOBBSize.z )
|
||||
{
|
||||
m_nLongAxis = 1;
|
||||
nIndex1 = 0; nIndex2 = 2;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_nLongAxis = 2;
|
||||
nIndex1 = 0; nIndex2 = 1;
|
||||
}
|
||||
|
||||
m_flRadius = sqrt( vecOBBSize[nIndex1] * vecOBBSize[nIndex1] + vecOBBSize[nIndex2] * vecOBBSize[nIndex2] ) * 0.5f;
|
||||
m_flLineLength = vecOBBSize[m_nLongAxis];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Sound spatialization
|
||||
//-----------------------------------------------------------------------------
|
||||
bool C_FuncTrackTrain::GetSoundSpatialization( SpatializationInfo_t& info )
|
||||
{
|
||||
// Out of PVS
|
||||
if ( IsDormant() )
|
||||
return false;
|
||||
|
||||
if ( info.pflRadius )
|
||||
{
|
||||
*info.pflRadius = m_flRadius;
|
||||
}
|
||||
|
||||
if ( info.pOrigin )
|
||||
{
|
||||
Vector vecStart, vecEnd, vecWorldDir;
|
||||
Vector vecDir = vec3_origin;
|
||||
vecDir[m_nLongAxis] = 1.0f;
|
||||
VectorRotate( vecDir, EntityToWorldTransform(), vecWorldDir );
|
||||
VectorMA( WorldSpaceCenter(), -0.5f * m_flLineLength, vecWorldDir, vecStart );
|
||||
VectorMA( vecStart, m_flLineLength, vecWorldDir, vecEnd );
|
||||
|
||||
float t;
|
||||
CalcClosestPointOnLine( info.info.vListenerOrigin, vecStart, vecEnd, *info.pOrigin, &t );
|
||||
if ( t < 0.0f )
|
||||
{
|
||||
*info.pOrigin = vecStart;
|
||||
}
|
||||
else if ( t > 1.0f )
|
||||
{
|
||||
*info.pOrigin = vecEnd;
|
||||
}
|
||||
}
|
||||
|
||||
if ( info.pAngles )
|
||||
{
|
||||
VectorCopy( CollisionProp()->GetCollisionAngles(), *info.pAngles );
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,133 @@
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
//=============================================================================//
|
||||
|
||||
#include "cbase.h"
|
||||
#include "vcollide_parse.h"
|
||||
#include "c_gib.h"
|
||||
|
||||
// memdbgon must be the last include file in a .cpp file!!!
|
||||
#include "tier0/memdbgon.h"
|
||||
|
||||
//NOTENOTE: This is not yet coupled with the server-side implementation of CGib
|
||||
// This is only a client-side version of gibs at the moment
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
C_Gib::~C_Gib( void )
|
||||
{
|
||||
VPhysicsDestroyObject();
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
// Input : *pszModelName -
|
||||
// vecOrigin -
|
||||
// vecForceDir -
|
||||
// vecAngularImp -
|
||||
// Output : Returns true on success, false on failure.
|
||||
//-----------------------------------------------------------------------------
|
||||
C_Gib *C_Gib::CreateClientsideGib( const char *pszModelName, Vector vecOrigin, Vector vecForceDir, AngularImpulse vecAngularImp, float flLifetime )
|
||||
{
|
||||
C_Gib *pGib = new C_Gib;
|
||||
|
||||
if ( pGib == NULL )
|
||||
return NULL;
|
||||
|
||||
if ( pGib->InitializeGib( pszModelName, vecOrigin, vecForceDir, vecAngularImp, flLifetime ) == false )
|
||||
return NULL;
|
||||
|
||||
return pGib;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
// Input : *pszModelName -
|
||||
// vecOrigin -
|
||||
// vecForceDir -
|
||||
// vecAngularImp -
|
||||
// Output : Returns true on success, false on failure.
|
||||
//-----------------------------------------------------------------------------
|
||||
bool C_Gib::InitializeGib( const char *pszModelName, Vector vecOrigin, Vector vecForceDir, AngularImpulse vecAngularImp, float flLifetime )
|
||||
{
|
||||
if ( InitializeAsClientEntity( pszModelName, RENDER_GROUP_OPAQUE_ENTITY ) == false )
|
||||
{
|
||||
Release();
|
||||
return false;
|
||||
}
|
||||
|
||||
SetAbsOrigin( vecOrigin );
|
||||
SetCollisionGroup( COLLISION_GROUP_DEBRIS );
|
||||
|
||||
solid_t tmpSolid;
|
||||
PhysModelParseSolid( tmpSolid, this, GetModelIndex() );
|
||||
|
||||
m_pPhysicsObject = VPhysicsInitNormal( SOLID_VPHYSICS, 0, false, &tmpSolid );
|
||||
|
||||
if ( m_pPhysicsObject )
|
||||
{
|
||||
float flForce = m_pPhysicsObject->GetMass();
|
||||
vecForceDir *= flForce;
|
||||
|
||||
m_pPhysicsObject->ApplyForceOffset( vecForceDir, GetAbsOrigin() );
|
||||
m_pPhysicsObject->SetCallbackFlags( m_pPhysicsObject->GetCallbackFlags() | CALLBACK_GLOBAL_TOUCH | CALLBACK_GLOBAL_TOUCH_STATIC );
|
||||
}
|
||||
else
|
||||
{
|
||||
// failed to create a physics object
|
||||
Release();
|
||||
return false;
|
||||
}
|
||||
|
||||
SetNextClientThink( gpGlobals->curtime + flLifetime );
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
void C_Gib::ClientThink( void )
|
||||
{
|
||||
SetRenderMode( kRenderTransAlpha );
|
||||
m_nRenderFX = kRenderFxFadeFast;
|
||||
|
||||
if ( m_clrRender->a == 0 )
|
||||
{
|
||||
#ifdef HL2_CLIENT_DLL
|
||||
s_AntlionGibManager.RemoveGib( this );
|
||||
#endif
|
||||
Release();
|
||||
return;
|
||||
}
|
||||
|
||||
SetNextClientThink( gpGlobals->curtime + 1.0f );
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
// Input : *pOther -
|
||||
//-----------------------------------------------------------------------------
|
||||
void C_Gib::StartTouch( C_BaseEntity *pOther )
|
||||
{
|
||||
// Limit the amount of times we can bounce
|
||||
if ( m_flTouchDelta < gpGlobals->curtime )
|
||||
{
|
||||
HitSurface( pOther );
|
||||
m_flTouchDelta = gpGlobals->curtime + 0.1f;
|
||||
}
|
||||
|
||||
BaseClass::StartTouch( pOther );
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
// Input : *pOther -
|
||||
//-----------------------------------------------------------------------------
|
||||
void C_Gib::HitSurface( C_BaseEntity *pOther )
|
||||
{
|
||||
//TODO: Implement splatter or effects in child versions
|
||||
}
|
||||
@@ -0,0 +1,64 @@
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
//=============================================================================//
|
||||
|
||||
#ifndef C_GIB_H
|
||||
#define C_GIB_H
|
||||
#ifdef _WIN32
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
#define DEFAULT_GIB_LIFETIME 4.0f
|
||||
|
||||
// Base client gibs
|
||||
|
||||
class C_Gib : public C_BaseAnimating
|
||||
{
|
||||
typedef C_BaseAnimating BaseClass;
|
||||
public:
|
||||
|
||||
~C_Gib( void );
|
||||
|
||||
static C_Gib *CreateClientsideGib( const char *pszModelName, Vector vecOrigin, Vector vecForceDir, AngularImpulse vecAngularImp, float flLifetime = DEFAULT_GIB_LIFETIME );
|
||||
|
||||
bool InitializeGib( const char *pszModelName, Vector vecOrigin, Vector vecForceDir, AngularImpulse vecAngularImp, float flLifetime = DEFAULT_GIB_LIFETIME );
|
||||
void ClientThink( void );
|
||||
void StartTouch( C_BaseEntity *pOther );
|
||||
|
||||
virtual void HitSurface( C_BaseEntity *pOther );
|
||||
|
||||
protected:
|
||||
|
||||
float m_flTouchDelta; // Amount of time that must pass before another touch function can be called
|
||||
};
|
||||
|
||||
#ifdef HL2_CLIENT_DLL
|
||||
class CAntlionGibManager : public CAutoGameSystemPerFrame
|
||||
{
|
||||
public:
|
||||
CAntlionGibManager( char const *name ) : CAutoGameSystemPerFrame( name )
|
||||
{
|
||||
}
|
||||
|
||||
// Methods of IGameSystem
|
||||
virtual void Update( float frametime );
|
||||
virtual void LevelInitPreEntity( void );
|
||||
|
||||
void AddGib( C_BaseEntity *pEntity );
|
||||
void RemoveGib( C_BaseEntity *pEntity );
|
||||
|
||||
private:
|
||||
typedef CHandle<C_BaseEntity> CGibHandle;
|
||||
CUtlLinkedList< CGibHandle > m_LRU;
|
||||
|
||||
};
|
||||
|
||||
|
||||
extern CAntlionGibManager s_AntlionGibManager;
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
#endif // C_GIB_H
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user