diff options
| author | John Schoenick <[email protected]> | 2015-09-09 18:35:41 -0700 |
|---|---|---|
| committer | John Schoenick <[email protected]> | 2015-09-09 18:35:41 -0700 |
| commit | 0d8dceea4310fde5706b3ce1c70609d72a38efdf (patch) | |
| tree | c831ef32c2c801a5c5a80401736b52c7b5a528ec /mp/src/game/client | |
| parent | Updated the SDK with the latest code from the TF and HL2 branches. (diff) | |
| download | source-sdk-2013-master.tar.xz source-sdk-2013-master.zip | |
Diffstat (limited to 'mp/src/game/client')
70 files changed, 1531 insertions, 459 deletions
diff --git a/mp/src/game/client/baseanimatedtextureproxy.cpp b/mp/src/game/client/baseanimatedtextureproxy.cpp index 4365e866..b7151114 100644 --- a/mp/src/game/client/baseanimatedtextureproxy.cpp +++ b/mp/src/game/client/baseanimatedtextureproxy.cpp @@ -11,6 +11,8 @@ #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" @@ -39,25 +41,33 @@ CBaseAnimatedTextureProxy::~CBaseAnimatedTextureProxy() bool CBaseAnimatedTextureProxy::Init( IMaterial *pMaterial, KeyValues *pKeyValues ) { char const* pAnimatedTextureVarName = pKeyValues->GetString( "animatedTextureVar" ); - if( !pAnimatedTextureVarName ) - return false; - bool foundVar; - m_AnimatedTextureVar = pMaterial->FindVar( pAnimatedTextureVarName, &foundVar, false ); - if( !foundVar ) - return false; - - char const* pAnimatedTextureFrameNumVarName = pKeyValues->GetString( "animatedTextureFrameNumVar" ); - if( !pAnimatedTextureFrameNumVarName ) - return false; + if( pAnimatedTextureVarName ) + { + bool foundVar; - m_AnimatedTextureFrameNumVar = pMaterial->FindVar( pAnimatedTextureFrameNumVarName, &foundVar, false ); - if( !foundVar ) - return false; + 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; + } + } + } + } - m_FrameRate = pKeyValues->GetFloat( "animatedTextureFrameRate", 15 ); - m_WrapAnimation = !pKeyValues->GetInt( "animationNoWrap", 0 ); - return true; + // Error - null out pointers. + Cleanup(); + return false; } void CBaseAnimatedTextureProxy::Cleanup() diff --git a/mp/src/game/client/bsp_utils.cpp b/mp/src/game/client/bsp_utils.cpp new file mode 100644 index 00000000..c21c2ada --- /dev/null +++ b/mp/src/game/client/bsp_utils.cpp @@ -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 ); + } +} diff --git a/mp/src/game/client/bsp_utils.h b/mp/src/game/client/bsp_utils.h new file mode 100644 index 00000000..1cdfaf50 --- /dev/null +++ b/mp/src/game/client/bsp_utils.h @@ -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 ) ); diff --git a/mp/src/game/client/c_ai_basenpc.cpp b/mp/src/game/client/c_ai_basenpc.cpp index 1b1e2e65..69b675b3 100644 --- a/mp/src/game/client/c_ai_basenpc.cpp +++ b/mp/src/game/client/c_ai_basenpc.cpp @@ -153,9 +153,13 @@ void C_AI_BaseNPC::OnDataChanged( DataUpdateType_t type ) } } -void C_AI_BaseNPC::GetRagdollInitBoneArrays( matrix3x4_t *pDeltaBones0, matrix3x4_t *pDeltaBones1, matrix3x4_t *pCurrentBones, float boneDt ) +bool C_AI_BaseNPC::GetRagdollInitBoneArrays( matrix3x4_t *pDeltaBones0, matrix3x4_t *pDeltaBones1, matrix3x4_t *pCurrentBones, float boneDt ) { - ForceSetupBonesAtTime( pDeltaBones0, gpGlobals->curtime - 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 ) @@ -164,11 +168,15 @@ void C_AI_BaseNPC::GetRagdollInitBoneArrays( matrix3x4_t *pDeltaBones0, matrix3x // 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 - ForceSetupBonesAtTime( pCurrentBones, ragdollCreateTime ); + if ( !ForceSetupBonesAtTime( pCurrentBones, ragdollCreateTime ) ) + bRet = false; } else { - SetupBones( pCurrentBones, MAXSTUDIOBONES, BONE_USED_BY_ANYTHING, gpGlobals->curtime ); + if ( !SetupBones( pCurrentBones, MAXSTUDIOBONES, BONE_USED_BY_ANYTHING, gpGlobals->curtime ) ) + bRet = false; } + + return bRet; } diff --git a/mp/src/game/client/c_ai_basenpc.h b/mp/src/game/client/c_ai_basenpc.h index 64636c45..834be64d 100644 --- a/mp/src/game/client/c_ai_basenpc.h +++ b/mp/src/game/client/c_ai_basenpc.h @@ -14,7 +14,7 @@ #include "c_basecombatcharacter.h" -// NOTE: MOved all controller code into c_basestudiomodel +// NOTE: Moved all controller code into c_basestudiomodel class C_AI_BaseNPC : public C_BaseCombatCharacter { DECLARE_CLASS( C_AI_BaseNPC, C_BaseCombatCharacter ); @@ -29,7 +29,7 @@ public: bool ShouldAvoidObstacle( void ){ return m_bPerformAvoidance; } virtual bool AddRagdollToFadeQueue( void ) { return m_bFadeCorpse; } - virtual void GetRagdollInitBoneArrays( matrix3x4_t *pDeltaBones0, matrix3x4_t *pDeltaBones1, matrix3x4_t *pCurrentBones, float boneDt ); + virtual bool GetRagdollInitBoneArrays( matrix3x4_t *pDeltaBones0, matrix3x4_t *pDeltaBones1, matrix3x4_t *pCurrentBones, float boneDt ) OVERRIDE; int GetDeathPose( void ) { return m_iDeathPose; } diff --git a/mp/src/game/client/c_baseanimating.cpp b/mp/src/game/client/c_baseanimating.cpp index 75c9d7a8..78bc38be 100644 --- a/mp/src/game/client/c_baseanimating.cpp +++ b/mp/src/game/client/c_baseanimating.cpp @@ -79,6 +79,11 @@ const float RUN_SPEED_ESTIMATE_SQR = 150.0f * 150.0f; static ConVar dbganimmodel( "dbganimmodel", "" ); #endif +#if defined( STAGING_ONLY ) + static ConVar dbg_bonestack_perturb( "dbg_bonestack_perturb", "0", 0); + static CInterlockedInt dbg_bonestack_reentrant_count = 0; +#endif // STAGING_ONLY + mstudioevent_t *GetEventIndexForSequence( mstudioseqdesc_t &seqdesc ); C_EntityDissolve *DissolveEffect( C_BaseEntity *pTarget, float flTime ); @@ -632,7 +637,10 @@ void C_ClientRagdoll::Release( void ) } ClientEntityList().RemoveEntity( GetClientHandle() ); - partition->Remove( PARTITION_CLIENT_SOLID_EDICTS | PARTITION_CLIENT_RESPONSIVE_EDICTS | PARTITION_CLIENT_NON_STATIC_EDICTS, CollisionProp()->GetPartitionHandle() ); + if ( CollisionProp()->GetPartitionHandle() != PARTITION_INVALID_HANDLE ) + { + partition->Remove( PARTITION_CLIENT_SOLID_EDICTS | PARTITION_CLIENT_RESPONSIVE_EDICTS | PARTITION_CLIENT_NON_STATIC_EDICTS, CollisionProp()->GetPartitionHandle() ); + } RemoveFromLeafSystem(); BaseClass::Release(); @@ -744,15 +752,25 @@ C_BaseAnimating::~C_BaseAnimating() int i = g_PreviousBoneSetups.Find( this ); if ( i != -1 ) g_PreviousBoneSetups.FastRemove( i ); - RemoveFromClientSideAnimationList(); TermRopes(); + + Assert( !m_pRagdoll ); + delete m_pRagdollInfo; - Assert(!m_pRagdoll); + m_pRagdollInfo = NULL; + delete m_pIk; + m_pIk = NULL; + delete m_pBoneMergeCache; + m_pBoneMergeCache = NULL; + Studio_DestroyBoneCache( m_hitboxBoneCacheHandle ); + delete m_pJiggleBones; + m_pJiggleBones = NULL; + InvalidateMdlCache(); // Kill off anything bone attached to us. @@ -852,7 +870,7 @@ void C_BaseAnimating::UpdateRelevantInterpolatedVars() { MDLCACHE_CRITICAL_SECTION(); // Remove any interpolated vars that need to be removed. - if ( !GetPredictable() && !IsClientCreated() && GetModelPtr() && GetModelPtr()->SequencesAvailable() ) + if ( !IsMarkedForDeletion() && !GetPredictable() && !IsClientCreated() && GetModelPtr() && GetModelPtr()->SequencesAvailable() ) { AddBaseAnimatingInterpolatedVars(); } @@ -892,6 +910,17 @@ void C_BaseAnimating::RemoveBaseAnimatingInterpolatedVars() } } +/* + From Ken: Lock() and Unlock() are render frame only, it’s just so the mdlcache + doesn’t toss the memory when it reshuffles the data, or at least used to. I + don't have any idea if mdlcache even does that anymore, but at one point it would + happily throw away the animation data if you ran out of memory on the + consoles. Jay adds: Ken is correct and the pointer should be valid until the end + of the frame lock (provided you are within a MDLCACHE_LOCK() block or whatever + + Jay also recommends running with a forced small cache size (1MB) to put maximum + pressure on the cache when testing changes. Look for datacache ConVar in datacache.cpp. + */ void C_BaseAnimating::LockStudioHdr() { Assert( m_hStudioHdr == MDLHANDLE_INVALID && m_pStudioHdr == NULL ); @@ -963,6 +992,9 @@ void C_BaseAnimating::UnlockStudioHdr() mdlcache->UnlockStudioHdr( m_hStudioHdr ); } m_hStudioHdr = MDLHANDLE_INVALID; + + delete m_pStudioHdr; + m_pStudioHdr = NULL; } } @@ -1511,10 +1543,21 @@ void C_BaseAnimating::BuildTransformations( CStudioHdr *hdr, Vector *pos, Quater if (pbones[i].parent == -1) { ConcatTransforms( cameraTransform, bonematrix, goalMX ); - } + } else { - ConcatTransforms( GetBone( pbones[i].parent ), bonematrix, goalMX ); + // If the parent bone has been scaled (like with BuildBigHeadTransformations) + // scale it back down so the jiggly bones show up non-scaled in the correct location. + matrix3x4_t parentMX = GetBone( pbones[i].parent ); + + float fScale = Square( parentMX[0][0] ) + Square( parentMX[1][0] ) + Square( parentMX[2][0] ); + if ( fScale > Square( 1.0001f ) ) + { + fScale = 1.0f / FastSqrt( fScale ); + MatrixScaleBy( fScale, parentMX ); + } + + ConcatTransforms( parentMX, bonematrix, goalMX ); } // get jiggle properties from QC data @@ -1995,10 +2038,10 @@ bool C_BaseAnimating::PutAttachment( int number, const matrix3x4_t &attachmentTo } -void C_BaseAnimating::SetupBones_AttachmentHelper( CStudioHdr *hdr ) +bool C_BaseAnimating::SetupBones_AttachmentHelper( CStudioHdr *hdr ) { - if ( !hdr || !hdr->GetNumAttachments() ) - return; + if ( !hdr ) + return false; // calculate attachment points matrix3x4_t world; @@ -2024,6 +2067,8 @@ void C_BaseAnimating::SetupBones_AttachmentHelper( CStudioHdr *hdr ) FormatViewModelAttachment( i, world ); PutAttachment( i + 1, world ); } + + return true; } bool C_BaseAnimating::CalcAttachments() @@ -2214,18 +2259,36 @@ bool C_BaseAnimating::GetSoundSpatialization( SpatializationInfo_t& info ) return true; } - +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- bool C_BaseAnimating::IsViewModel() const { return false; } +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void C_BaseAnimating::UpdateOnRemove( void ) +{ + RemoveFromClientSideAnimationList( true ); + + BaseClass::UpdateOnRemove(); +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- bool C_BaseAnimating::IsMenuModel() const { return false; } // UNDONE: Seems kind of silly to have this when we also have the cached bones in C_BaseAnimating +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- CBoneCache *C_BaseAnimating::GetBoneCache( CStudioHdr *pStudioHdr ) { int boneMask = BONE_USED_BY_HITBOX; @@ -2908,10 +2971,14 @@ bool C_BaseAnimating::SetupBones( matrix3x4_t *pBoneToWorldOut, int nMaxBones, i if( !( oldReadableBones & BONE_USED_BY_ATTACHMENT ) && ( boneMask & BONE_USED_BY_ATTACHMENT ) ) { - SetupBones_AttachmentHelper( hdr ); + if ( !SetupBones_AttachmentHelper( hdr ) ) + { + DevWarning( 2, "SetupBones: SetupBones_AttachmentHelper failed.\n" ); + return false; + } } } - + // Do they want to get at the bone transforms? If it's just making sure an aiment has // its bones setup, it doesn't need the transforms yet. if ( pBoneToWorldOut ) @@ -2922,7 +2989,7 @@ bool C_BaseAnimating::SetupBones( matrix3x4_t *pBoneToWorldOut, int nMaxBones, i } else { - Warning( "SetupBones: invalid bone array size (%d - needs %d)\n", nMaxBones, m_CachedBoneData.Count() ); + ExecuteNTimes( 25, Warning( "SetupBones: invalid bone array size (%d - needs %d)\n", nMaxBones, m_CachedBoneData.Count() ) ); return false; } } @@ -2989,6 +3056,9 @@ struct BoneAccess char const *tag; }; +// the modelcache critical section is insufficient for preventing us from getting into the bone cache at the same time. +// The bonecache itself is protected by a mutex, but the actual bone access stack needs to be protected separately. +static CThreadFastMutex g_BoneAccessMutex; static CUtlVector< BoneAccess > g_BoneAccessStack; static BoneAccess g_BoneAcessBase; @@ -3003,6 +3073,9 @@ bool C_BaseAnimating::IsBoneAccessAllowed() const // (static function) void C_BaseAnimating::PushAllowBoneAccess( bool bAllowForNormalModels, bool bAllowForViewModels, char const *tagPush ) { + AUTO_LOCK( g_BoneAccessMutex ); + STAGING_ONLY_EXEC( ReentrancyVerifier rv( &dbg_bonestack_reentrant_count, dbg_bonestack_perturb.GetInt() ) ); + BoneAccess save = g_BoneAcessBase; g_BoneAccessStack.AddToTail( save ); @@ -3014,6 +3087,9 @@ void C_BaseAnimating::PushAllowBoneAccess( bool bAllowForNormalModels, bool bAll void C_BaseAnimating::PopBoneAccess( char const *tagPop ) { + AUTO_LOCK( g_BoneAccessMutex ); + STAGING_ONLY_EXEC( ReentrancyVerifier rv( &dbg_bonestack_reentrant_count, dbg_bonestack_perturb.GetInt() ) ); + // Validate that pop matches the push Assert( ( g_BoneAcessBase.tag == tagPop ) || ( g_BoneAcessBase.tag && g_BoneAcessBase.tag != ( char const * ) 1 && tagPop && tagPop != ( char const * ) 1 && !strcmp( g_BoneAcessBase.tag, tagPop ) ) ); int lastIndex = g_BoneAccessStack.Count() - 1; @@ -3481,7 +3557,7 @@ void C_BaseAnimating::DoAnimationEvents( CStudioHdr *pStudioHdr ) } // Necessary to get the next loop working - m_flPrevEventCycle = -0.01; + m_flPrevEventCycle = flEventCycle - 0.001f; } for (int i = 0; i < (int)seqdesc.numevents; i++) @@ -4496,7 +4572,7 @@ void C_BaseAnimating::OnPreDataChanged( DataUpdateType_t updateType ) m_bLastClientSideFrameReset = m_bClientSideFrameReset; } -void C_BaseAnimating::ForceSetupBonesAtTime( matrix3x4_t *pBonesOut, float flTime ) +bool C_BaseAnimating::ForceSetupBonesAtTime( matrix3x4_t *pBonesOut, float flTime ) { // blow the cached prev bones InvalidateBoneCache(); @@ -4505,13 +4581,18 @@ void C_BaseAnimating::ForceSetupBonesAtTime( matrix3x4_t *pBonesOut, float flTim Interpolate( flTime ); // Setup bone state at the given time - SetupBones( pBonesOut, MAXSTUDIOBONES, BONE_USED_BY_ANYTHING, flTime ); + return SetupBones( pBonesOut, MAXSTUDIOBONES, BONE_USED_BY_ANYTHING, flTime ); } -void C_BaseAnimating::GetRagdollInitBoneArrays( matrix3x4_t *pDeltaBones0, matrix3x4_t *pDeltaBones1, matrix3x4_t *pCurrentBones, float boneDt ) +bool C_BaseAnimating::GetRagdollInitBoneArrays( matrix3x4_t *pDeltaBones0, matrix3x4_t *pDeltaBones1, matrix3x4_t *pCurrentBones, float boneDt ) { - ForceSetupBonesAtTime( pDeltaBones0, gpGlobals->curtime - boneDt ); - ForceSetupBonesAtTime( pDeltaBones1, gpGlobals->curtime ); + bool bSuccess = true; + + if ( !ForceSetupBonesAtTime( pDeltaBones0, gpGlobals->curtime - boneDt ) ) + bSuccess = false; + if ( !ForceSetupBonesAtTime( pDeltaBones1, gpGlobals->curtime ) ) + bSuccess = false; + float ragdollCreateTime = PhysGetSyncCreateTime(); if ( ragdollCreateTime != gpGlobals->curtime ) { @@ -4519,12 +4600,15 @@ void C_BaseAnimating::GetRagdollInitBoneArrays( matrix3x4_t *pDeltaBones0, matri // 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 - ForceSetupBonesAtTime( pCurrentBones, ragdollCreateTime ); + if ( !ForceSetupBonesAtTime( pCurrentBones, ragdollCreateTime ) ) + bSuccess = false; } else { memcpy( pCurrentBones, m_CachedBoneData.Base(), sizeof( matrix3x4_t ) * m_CachedBoneData.Count() ); } + + return bSuccess; } C_BaseAnimating *C_BaseAnimating::CreateRagdollCopy() @@ -4592,14 +4676,32 @@ C_BaseAnimating *C_BaseAnimating::BecomeRagdollOnClient() { MoveToLastReceivedPosition( true ); GetAbsOrigin(); + C_BaseAnimating *pRagdoll = CreateRagdollCopy(); + if ( pRagdoll ) + { + matrix3x4_t boneDelta0[MAXSTUDIOBONES]; + matrix3x4_t boneDelta1[MAXSTUDIOBONES]; + matrix3x4_t currentBones[MAXSTUDIOBONES]; + const float boneDt = 0.1f; + + bool bInitAsClient = false; + bool bInitBoneArrays = GetRagdollInitBoneArrays( boneDelta0, boneDelta1, currentBones, boneDt ); + + if ( bInitBoneArrays ) + { + bInitAsClient = pRagdoll->InitAsClientRagdoll( boneDelta0, boneDelta1, currentBones, boneDt ); + } + + if ( !bInitAsClient || !bInitBoneArrays ) + { + Warning( "C_BaseAnimating::BecomeRagdollOnClient failed. pRagdoll:%p bInitBoneArrays:%d bInitAsClient:%d\n", + pRagdoll, bInitBoneArrays, bInitAsClient ); + pRagdoll->Release(); + return NULL; + } + } - matrix3x4_t boneDelta0[MAXSTUDIOBONES]; - matrix3x4_t boneDelta1[MAXSTUDIOBONES]; - matrix3x4_t currentBones[MAXSTUDIOBONES]; - const float boneDt = 0.1f; - GetRagdollInitBoneArrays( boneDelta0, boneDelta1, currentBones, boneDt ); - pRagdoll->InitAsClientRagdoll( boneDelta0, boneDelta1, currentBones, boneDt ); return pRagdoll; } @@ -5512,6 +5614,13 @@ int C_BaseAnimating::SelectWeightedSequence ( int activity ) } +int C_BaseAnimating::SelectWeightedSequenceFromModifiers( Activity activity, CUtlSymbol *pActivityModifiers, int iModifierCount ) +{ + Assert( activity != ACT_INVALID ); + Assert( GetModelPtr() ); + return GetModelPtr()->SelectWeightedSequenceFromModifiers( activity, pActivityModifiers, iModifierCount ); +} + //========================================================= //========================================================= int C_BaseAnimating::LookupPoseParameter( CStudioHdr *pstudiohdr, const char *szName ) @@ -6018,7 +6127,7 @@ void C_BaseAnimating::AddToClientSideAnimationList() UpdateRelevantInterpolatedVars(); } -void C_BaseAnimating::RemoveFromClientSideAnimationList() +void C_BaseAnimating::RemoveFromClientSideAnimationList( bool bBeingDestroyed /*= false*/ ) { // Not in list yet if ( INVALID_CLIENTSIDEANIMATION_LIST_HANDLE == m_ClientSideAnimationListHandle ) @@ -6049,7 +6158,10 @@ void C_BaseAnimating::RemoveFromClientSideAnimationList() // Invalidate our handle no matter what. m_ClientSideAnimationListHandle = INVALID_CLIENTSIDEANIMATION_LIST_HANDLE; - UpdateRelevantInterpolatedVars(); + if ( !bBeingDestroyed ) + { + UpdateRelevantInterpolatedVars(); + } } diff --git a/mp/src/game/client/c_baseanimating.h b/mp/src/game/client/c_baseanimating.h index f91745ef..f1b0467c 100644 --- a/mp/src/game/client/c_baseanimating.h +++ b/mp/src/game/client/c_baseanimating.h @@ -247,7 +247,7 @@ public: void ForceClientSideAnimationOn(); void AddToClientSideAnimationList(); - void RemoveFromClientSideAnimationList(); + void RemoveFromClientSideAnimationList( bool bBeingDestroyed = false ); virtual bool IsSelfAnimating(); virtual void ResetLatched(); @@ -298,8 +298,8 @@ public: virtual void Clear( void ); void ClearRagdoll(); void CreateUnragdollInfo( C_BaseAnimating *pRagdoll ); - void ForceSetupBonesAtTime( matrix3x4_t *pBonesOut, float flTime ); - virtual void GetRagdollInitBoneArrays( matrix3x4_t *pDeltaBones0, matrix3x4_t *pDeltaBones1, matrix3x4_t *pCurrentBones, float boneDt ); + 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; } @@ -429,6 +429,7 @@ public: // 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 ); @@ -444,6 +445,7 @@ public: 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 @@ -605,7 +607,7 @@ private: // Calculated attachment points CUtlVector<CAttachmentData> m_Attachments; - void SetupBones_AttachmentHelper( CStudioHdr *pStudioHdr ); + bool SetupBones_AttachmentHelper( CStudioHdr *pStudioHdr ); EHANDLE m_hLightingOrigin; EHANDLE m_hLightingOriginRelative; @@ -758,19 +760,12 @@ inline CStudioHdr *C_BaseAnimating::GetModelPtr() const inline void C_BaseAnimating::InvalidateMdlCache() { - if ( m_pStudioHdr ) - { - UnlockStudioHdr(); - delete m_pStudioHdr; - m_pStudioHdr = NULL; - } + UnlockStudioHdr(); } - -inline bool C_BaseAnimating::IsModelScaleFractional() const /// very fast way to ask if the model scale is < 1.0f +inline bool C_BaseAnimating::IsModelScaleFractional() const { - COMPILE_TIME_ASSERT( sizeof( m_flModelScale ) == sizeof( int ) ); - return *((const int *) &m_flModelScale) < 0x3f800000; + return ( m_flModelScale < 1.0f ); } inline bool C_BaseAnimating::IsModelScaled() const diff --git a/mp/src/game/client/c_basecombatcharacter.cpp b/mp/src/game/client/c_basecombatcharacter.cpp index fee63118..846901a5 100644 --- a/mp/src/game/client/c_basecombatcharacter.cpp +++ b/mp/src/game/client/c_basecombatcharacter.cpp @@ -34,6 +34,7 @@ C_BaseCombatCharacter::C_BaseCombatCharacter() m_pGlowEffect = NULL; m_bGlowEnabled = false; m_bOldGlowEnabled = false; + m_bClientSideGlowEnabled = false; #endif // GLOWS_ENABLE } @@ -116,6 +117,22 @@ void C_BaseCombatCharacter::GetGlowEffectColor( float *r, float *g, float *b ) //----------------------------------------------------------------------------- // 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 @@ -125,7 +142,7 @@ void C_BaseCombatCharacter::UpdateGlowEffect( void ) } // create a new effect - if ( m_bGlowEnabled ) + if ( m_bGlowEnabled || m_bClientSideGlowEnabled ) { float r, g, b; GetGlowEffectColor( &r, &g, &b ); diff --git a/mp/src/game/client/c_basecombatcharacter.h b/mp/src/game/client/c_basecombatcharacter.h index 1d84e4ce..0a135b05 100644 --- a/mp/src/game/client/c_basecombatcharacter.h +++ b/mp/src/game/client/c_basecombatcharacter.h @@ -97,6 +97,10 @@ public: #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: @@ -121,7 +125,8 @@ private: CHandle< C_BaseCombatWeapon > m_hActiveWeapon; #ifdef GLOWS_ENABLE - bool m_bGlowEnabled; + bool m_bClientSideGlowEnabled; // client-side only value used for spectator + bool m_bGlowEnabled; // networked value bool m_bOldGlowEnabled; CGlowObject *m_pGlowEffect; #endif // GLOWS_ENABLE diff --git a/mp/src/game/client/c_basecombatweapon.cpp b/mp/src/game/client/c_basecombatweapon.cpp index 55d21b39..ef4c845e 100644 --- a/mp/src/game/client/c_basecombatweapon.cpp +++ b/mp/src/game/client/c_basecombatweapon.cpp @@ -163,7 +163,10 @@ void C_BaseCombatWeapon::OnDataChanged( DataUpdateType_t updateType ) } } - UpdateVisibility(); + if ( updateType == DATA_UPDATE_CREATED ) + { + UpdateVisibility(); + } m_iOldState = m_iState; diff --git a/mp/src/game/client/c_baseentity.cpp b/mp/src/game/client/c_baseentity.cpp index 25b089cd..338f986c 100644 --- a/mp/src/game/client/c_baseentity.cpp +++ b/mp/src/game/client/c_baseentity.cpp @@ -1150,6 +1150,13 @@ bool C_BaseEntity::InitializeAsClientEntityByIndex( int iIndex, RenderGroup_t re return true; } +void C_BaseEntity::TrackAngRotation( bool bTrack ) +{ + if ( bTrack ) + AddVar( &m_angRotation, &m_iv_angRotation, LATCH_SIMULATION_VAR ); + else + RemoveVar( &m_angRotation, false ); +} void C_BaseEntity::Term() { @@ -2459,37 +2466,36 @@ void C_BaseEntity::UnlinkFromHierarchy() void C_BaseEntity::ValidateModelIndex( void ) { #ifdef TF_CLIENT_DLL - if ( m_nModelIndexOverrides[VISION_MODE_NONE] > 0 ) + if ( IsLocalPlayerUsingVisionFilterFlags( TF_VISION_FILTER_HALLOWEEN ) ) { - if ( IsLocalPlayerUsingVisionFilterFlags( TF_VISION_FILTER_HALLOWEEN ) ) + if ( m_nModelIndexOverrides[VISION_MODE_HALLOWEEN] > 0 ) { - if ( m_nModelIndexOverrides[VISION_MODE_HALLOWEEN] > 0 ) - { - SetModelByIndex( m_nModelIndexOverrides[VISION_MODE_HALLOWEEN] ); - return; - } + SetModelByIndex( m_nModelIndexOverrides[VISION_MODE_HALLOWEEN] ); + return; } + } - if ( IsLocalPlayerUsingVisionFilterFlags( TF_VISION_FILTER_PYRO ) ) + if ( IsLocalPlayerUsingVisionFilterFlags( TF_VISION_FILTER_PYRO ) ) + { + if ( m_nModelIndexOverrides[VISION_MODE_PYRO] > 0 ) { - if ( m_nModelIndexOverrides[VISION_MODE_PYRO] > 0 ) - { - SetModelByIndex( m_nModelIndexOverrides[VISION_MODE_PYRO] ); - return; - } + SetModelByIndex( m_nModelIndexOverrides[VISION_MODE_PYRO] ); + return; } + } - if ( IsLocalPlayerUsingVisionFilterFlags( TF_VISION_FILTER_ROME ) ) + if ( IsLocalPlayerUsingVisionFilterFlags( TF_VISION_FILTER_ROME ) ) + { + if ( m_nModelIndexOverrides[VISION_MODE_ROME] > 0 ) { - if ( m_nModelIndexOverrides[VISION_MODE_ROME] > 0 ) - { - SetModelByIndex( m_nModelIndexOverrides[VISION_MODE_ROME] ); - return; - } + SetModelByIndex( m_nModelIndexOverrides[VISION_MODE_ROME] ); + return; } + } + if ( m_nModelIndexOverrides[VISION_MODE_NONE] > 0 ) + { SetModelByIndex( m_nModelIndexOverrides[VISION_MODE_NONE] ); - return; } #endif @@ -2621,14 +2627,6 @@ void C_BaseEntity::PostDataUpdate( DataUpdateType_t updateType ) //----------------------------------------------------------------------------- void C_BaseEntity::OnDataUnchangedInPVS() { - Interp_RestoreToLastNetworked( GetVarMapping() ); - - // For non-predicted and non-client only ents, we need to latch network values into the interpolation histories - if ( !GetPredictable() && !IsClientCreated() ) - { - OnLatchInterpolatedVariables( LATCH_SIMULATION_VAR ); - } - Assert( m_hNetworkMoveParent.Get() || !m_hNetworkMoveParent.IsValid() ); HierarchySetParent(m_hNetworkMoveParent); @@ -6308,6 +6306,9 @@ bool C_BaseEntity::ValidateEntityAttachedToPlayer( bool &bShouldRetry ) if ( FStrEq( pszModel, "models/flag/briefcase.mdl" ) ) return true; + if ( FStrEq( pszModel, "models/passtime/ball/passtime_ball.mdl" ) ) + return true; + if ( FStrEq( pszModel, "models/props_doomsday/australium_container.mdl" ) ) return true; @@ -6323,6 +6324,13 @@ bool C_BaseEntity::ValidateEntityAttachedToPlayer( bool &bShouldRetry ) if ( FStrEq( pszModel, "models/props_moonbase/powersupply_flag.mdl" ) ) return true; + + // The Halloween 2014 doomsday flag replacement + if ( FStrEq( pszModel, "models/flag/ticket_case.mdl" ) ) + return true; + + if ( FStrEq( pszModel, "models/weapons/c_models/c_grapple_proj/c_grapple_proj.mdl" ) ) + return true; } // Any entity that's not an item parented to a player is invalid. diff --git a/mp/src/game/client/c_baseentity.h b/mp/src/game/client/c_baseentity.h index f062760d..e90d1e32 100644 --- a/mp/src/game/client/c_baseentity.h +++ b/mp/src/game/client/c_baseentity.h @@ -1226,7 +1226,7 @@ protected: public: // Accessors for above - static int GetPredictionRandomSeed( void ); + static int GetPredictionRandomSeed( bool bUseUnSyncedServerPlatTime = false ); static void SetPredictionRandomSeed( const CUserCmd *cmd ); static C_BasePlayer *GetPredictionPlayer( void ); static void SetPredictionPlayer( C_BasePlayer *player ); @@ -1394,6 +1394,7 @@ public: virtual bool IsDeflectable() { return false; } + bool IsCombatCharacter() { return MyCombatCharacterPointer() == NULL ? false : true; } protected: int m_nFXComputeFrame; @@ -1442,6 +1443,8 @@ public: // a render handle, and is put into the spatial partition. bool InitializeAsClientEntityByIndex( int iIndex, RenderGroup_t renderGroup ); + void TrackAngRotation( bool bTrack ); + private: friend void OnRenderStart(); diff --git a/mp/src/game/client/c_baseplayer.cpp b/mp/src/game/client/c_baseplayer.cpp index 942f7a37..a6c682d0 100644 --- a/mp/src/game/client/c_baseplayer.cpp +++ b/mp/src/game/client/c_baseplayer.cpp @@ -122,6 +122,9 @@ ConVar demo_fov_override( "demo_fov_override", "0", FCVAR_CLIENTDLL | FCVAR_DONT ConVar cl_meathook_neck_pivot_ingame_up( "cl_meathook_neck_pivot_ingame_up", "7.0" ); ConVar cl_meathook_neck_pivot_ingame_fwd( "cl_meathook_neck_pivot_ingame_fwd", "3.0" ); +static ConVar cl_clean_textures_on_death( "cl_clean_textures_on_death", "0", FCVAR_DEVELOPMENTONLY, "If enabled, attempts to purge unused textures every time a freeze cam is shown" ); + + void RecvProxy_LocalVelocityX( const CRecvProxyData *pData, void *pStruct, void *pOut ); void RecvProxy_LocalVelocityY( const CRecvProxyData *pData, void *pStruct, void *pOut ); void RecvProxy_LocalVelocityZ( const CRecvProxyData *pData, void *pStruct, void *pOut ); @@ -436,6 +439,7 @@ C_BasePlayer::C_BasePlayer() : m_iv_vecViewOffset( "C_BasePlayer::m_iv_vecViewOf m_bFiredWeapon = false; m_nForceVisionFilterFlags = 0; + m_nLocalPlayerVisionFlags = 0; ListenForGameEvent( "base_player_teleported" ); } @@ -541,6 +545,7 @@ CBaseEntity *C_BasePlayer::GetObserverTarget() const // returns players target o case OBS_MODE_FIXED: // view from a fixed camera position case OBS_MODE_IN_EYE: // follow a player in first person view case OBS_MODE_CHASE: // follow a player in third person view + case OBS_MODE_POI: // PASSTIME point of interest - game objective, big fight, anything interesting case OBS_MODE_ROAMING: // free roaming return m_hObserverTarget; break; @@ -635,6 +640,7 @@ int C_BasePlayer::GetObserverMode() const case OBS_MODE_FIXED: // view from a fixed camera position case OBS_MODE_IN_EYE: // follow a player in first person view case OBS_MODE_CHASE: // follow a player in third person view + case OBS_MODE_POI: // PASSTIME point of interest - game objective, big fight, anything interesting case OBS_MODE_ROAMING: // free roaming return m_iObserverMode; break; @@ -880,6 +886,10 @@ void C_BasePlayer::PostDataUpdate( DataUpdateType_t updateType ) // Force the sound mixer to the freezecam mixer ConVar *pVar = (ConVar *)cvar->FindVar( "snd_soundmixer" ); pVar->SetValue( "FreezeCam_Only" ); + + // When we start, give unused textures an opportunity to unload + if ( cl_clean_textures_on_death.GetBool() ) + g_pMaterialSystem->UncacheUnusedMaterials( false ); } else if ( m_bWasFreezeFraming && GetObserverMode() != OBS_MODE_FREEZECAM ) { @@ -897,6 +907,14 @@ void C_BasePlayer::PostDataUpdate( DataUpdateType_t updateType ) m_nForceVisionFilterFlags = 0; CalculateVisionUsingCurrentFlags(); } + + // force calculate vision when the local vision flags changed + int nCurrentLocalPlayerVisionFlags = GetLocalPlayerVisionFilterFlags(); + if ( m_nLocalPlayerVisionFlags != nCurrentLocalPlayerVisionFlags ) + { + CalculateVisionUsingCurrentFlags(); + m_nLocalPlayerVisionFlags = nCurrentLocalPlayerVisionFlags; + } } // If we are updated while paused, allow the player origin to be snapped by the @@ -2078,7 +2096,7 @@ void C_BasePlayer::GetToolRecordingState( KeyValues *msg ) // then this code can (should!) be removed if ( state.m_bThirdPerson ) { - Vector cam_ofs = g_ThirdPersonManager.GetCameraOffsetAngles(); + const Vector& cam_ofs = g_ThirdPersonManager.GetCameraOffsetAngles(); QAngle camAngles; camAngles[ PITCH ] = cam_ofs[ PITCH ]; @@ -2594,7 +2612,7 @@ void C_BasePlayer::NotePredictionError( const Vector &vDelta ) // offset curtime and setup bones at that time using fake interpolation // fake interpolation means we don't have reliable interpolation history (the local player doesn't animate locally) // so we just modify cycle and origin directly and use that as a fake guess -void C_BasePlayer::ForceSetupBonesAtTimeFakeInterpolation( matrix3x4_t *pBonesOut, float curtimeOffset ) +bool C_BasePlayer::ForceSetupBonesAtTimeFakeInterpolation( matrix3x4_t *pBonesOut, float curtimeOffset ) { // we don't have any interpolation data, so fake it float cycle = m_flCycle; @@ -2609,30 +2627,37 @@ void C_BasePlayer::ForceSetupBonesAtTimeFakeInterpolation( matrix3x4_t *pBonesOu m_flCycle = fmod( 10 + cycle + m_flPlaybackRate * curtimeOffset, 1.0f ); SetLocalOrigin( origin + curtimeOffset * GetLocalVelocity() ); // Setup bone state to extrapolate physics velocity - SetupBones( pBonesOut, MAXSTUDIOBONES, BONE_USED_BY_ANYTHING, gpGlobals->curtime + curtimeOffset ); + bool bSuccess = SetupBones( pBonesOut, MAXSTUDIOBONES, BONE_USED_BY_ANYTHING, gpGlobals->curtime + curtimeOffset ); m_flCycle = cycle; SetLocalOrigin( origin ); + return bSuccess; } -void C_BasePlayer::GetRagdollInitBoneArrays( matrix3x4_t *pDeltaBones0, matrix3x4_t *pDeltaBones1, matrix3x4_t *pCurrentBones, float boneDt ) +bool C_BasePlayer::GetRagdollInitBoneArrays( matrix3x4_t *pDeltaBones0, matrix3x4_t *pDeltaBones1, matrix3x4_t *pCurrentBones, float boneDt ) { if ( !IsLocalPlayer() ) - { - BaseClass::GetRagdollInitBoneArrays(pDeltaBones0, pDeltaBones1, pCurrentBones, boneDt); - return; - } - ForceSetupBonesAtTimeFakeInterpolation( pDeltaBones0, -boneDt ); - ForceSetupBonesAtTimeFakeInterpolation( pDeltaBones1, 0 ); + return BaseClass::GetRagdollInitBoneArrays(pDeltaBones0, pDeltaBones1, pCurrentBones, boneDt); + + bool bSuccess = true; + + if ( !ForceSetupBonesAtTimeFakeInterpolation( pDeltaBones0, -boneDt ) ) + bSuccess = false; + if ( !ForceSetupBonesAtTimeFakeInterpolation( pDeltaBones1, 0 ) ) + bSuccess = false; + float ragdollCreateTime = PhysGetSyncCreateTime(); if ( ragdollCreateTime != gpGlobals->curtime ) { - ForceSetupBonesAtTimeFakeInterpolation( pCurrentBones, ragdollCreateTime - gpGlobals->curtime ); + if ( !ForceSetupBonesAtTimeFakeInterpolation( pCurrentBones, ragdollCreateTime - gpGlobals->curtime ) ) + bSuccess = false; } else { - SetupBones( pCurrentBones, MAXSTUDIOBONES, BONE_USED_BY_ANYTHING, gpGlobals->curtime ); + if ( !SetupBones( pCurrentBones, MAXSTUDIOBONES, BONE_USED_BY_ANYTHING, gpGlobals->curtime ) ) + bSuccess = false; } + return bSuccess; } @@ -2838,6 +2863,7 @@ void C_BasePlayer::UpdateWearables( void ) { pItem->ValidateModelIndex(); pItem->UpdateVisibility(); + pItem->CreateShadow(); } } } diff --git a/mp/src/game/client/c_baseplayer.h b/mp/src/game/client/c_baseplayer.h index 9d3657bf..5e4372bc 100644 --- a/mp/src/game/client/c_baseplayer.h +++ b/mp/src/game/client/c_baseplayer.h @@ -169,7 +169,7 @@ public: virtual IRagdoll* GetRepresentativeRagdoll() const; // override the initial bone position for ragdolls - virtual void GetRagdollInitBoneArrays( matrix3x4_t *pDeltaBones0, matrix3x4_t *pDeltaBones1, matrix3x4_t *pCurrentBones, float boneDt ); + 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 ); @@ -388,7 +388,7 @@ public: #if defined USES_ECON_ITEMS // Wearables - void UpdateWearables(); + virtual void UpdateWearables(); C_EconWearable *GetWearable( int i ) { return m_hMyWearables[i]; } int GetNumWearables( void ) { return m_hMyWearables.Count(); } #endif @@ -585,7 +585,7 @@ 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; } - void ForceSetupBonesAtTimeFakeInterpolation( matrix3x4_t *pBonesOut, float curtimeOffset ); + bool ForceSetupBonesAtTimeFakeInterpolation( matrix3x4_t *pBonesOut, float curtimeOffset ); float m_flLaggedMovementValue; @@ -611,6 +611,7 @@ protected: float m_flNextAchievementAnnounceTime; int m_nForceVisionFilterFlags; // Force our vision filter to a specific setting + int m_nLocalPlayerVisionFlags; #if defined USES_ECON_ITEMS // Wearables diff --git a/mp/src/game/client/c_baseviewmodel.cpp b/mp/src/game/client/c_baseviewmodel.cpp index 8ae21f63..28c804fb 100644 --- a/mp/src/game/client/c_baseviewmodel.cpp +++ b/mp/src/game/client/c_baseviewmodel.cpp @@ -18,6 +18,9 @@ #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" @@ -53,8 +56,8 @@ void FormatViewModelAttachment( Vector &vOrigin, bool bInverse ) // 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) - float factorX = worldx / viewx; - + // 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. @@ -331,6 +334,16 @@ int C_BaseViewModel::DrawModel( int flags ) } } +#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; } diff --git a/mp/src/game/client/c_rope.cpp b/mp/src/game/client/c_rope.cpp index 9f11fc5d..0c84778c 100644 --- a/mp/src/game/client/c_rope.cpp +++ b/mp/src/game/client/c_rope.cpp @@ -12,6 +12,7 @@ #include "input.h" #ifdef TF_CLIENT_DLL #include "cdll_util.h" +#include "tf_gamerules.h" #endif #include "rope_helpers.h" #include "engine/ivmodelinfo.h" @@ -640,6 +641,15 @@ bool CRopeManager::IsHolidayLightMode( void ) return false; } +#ifdef TF_CLIENT_DLL + if ( TFGameRules() && TFGameRules()->IsPowerupMode() ) + { + // We don't want to draw the lights for the grapple. + // They get left behind for a while and look bad. + return false; + } +#endif + bool bDrawHolidayLights = false; #ifdef USES_ECON_ITEMS @@ -1638,12 +1648,12 @@ struct catmull_t }; // bake out the terms of the catmull rom spline -void Catmull_Rom_Spline_Matrix( const Vector &p1, const Vector &p2, const Vector &p3, const Vector &p4, catmull_t &output ) +void Catmull_Rom_Spline_Matrix( const Vector &vecP1, const Vector &vecP2, const Vector &vecP3, const Vector &vecP4, catmull_t &output ) { - output.t3 = 0.5f * ((-1*p1) + (3*p2) + (-3*p3) + p4); // 0.5 t^3 * [ (-1*p1) + ( 3*p2) + (-3*p3) + p4 ] - output.t2 = 0.5f * ((2*p1) + (-5*p2) + (4*p3) - p4); // 0.5 t^2 * [ ( 2*p1) + (-5*p2) + ( 4*p3) - p4 ] - output.t = 0.5f * ((-1*p1) + p3); // 0.5 t * [ (-1*p1) + p3 ] - output.c = p2; // p2 + output.t3 = 0.5f * ( ( -1 * vecP1 ) + ( 3 * vecP2 ) + ( -3 * vecP3 ) + vecP4 ); // 0.5 t^3 * [ (-1*p1) + ( 3*p2) + (-3*p3) + p4 ] + output.t2 = 0.5f * ( ( 2 * vecP1 ) + ( -5 * vecP2 ) + ( 4 * vecP3 ) - vecP4 ); // 0.5 t^2 * [ ( 2*p1) + (-5*p2) + ( 4*p3) - p4 ] + output.t = 0.5f * ( ( -1 * vecP1 ) + vecP3 ); // 0.5 t * [ (-1*p1) + p3 ] + output.c = vecP2; // p2 } // evaluate one point on the spline, t is a vector of (t, t^2, t^3) diff --git a/mp/src/game/client/c_sceneentity.cpp b/mp/src/game/client/c_sceneentity.cpp index baf2770e..abd211c0 100644 --- a/mp/src/game/client/c_sceneentity.cpp +++ b/mp/src/game/client/c_sceneentity.cpp @@ -219,7 +219,7 @@ void C_SceneEntity::SetupClientOnlyScene( const char *pszFilename, C_BaseFlex *p { LoadSceneFromFile( szFilename ); - if (!CommandLine()->FindParm("-hushasserts")) + if ( !HushAsserts() ) { Assert( m_pScene ); } @@ -257,7 +257,7 @@ void C_SceneEntity::SetupClientOnlyScene( const char *pszFilename, C_BaseFlex *p if ( m_hOwner.Get() ) { - if (!CommandLine()->FindParm("-hushasserts")) + if ( !HushAsserts() ) { Assert( m_pScene ); } @@ -1108,7 +1108,7 @@ void C_SceneEntity::SetCurrentTime( float t, bool forceClientSync ) //----------------------------------------------------------------------------- void C_SceneEntity::PrefetchAnimBlocks( CChoreoScene *pScene ) { - if (!CommandLine()->FindParm("-hushasserts")) + if ( !HushAsserts() ) { Assert( pScene && m_bMultiplayer ); } diff --git a/mp/src/game/client/c_slideshow_display.cpp b/mp/src/game/client/c_slideshow_display.cpp index 90ee0a74..b721f4c3 100644 --- a/mp/src/game/client/c_slideshow_display.cpp +++ b/mp/src/game/client/c_slideshow_display.cpp @@ -272,8 +272,8 @@ void C_SlideshowDisplay::BuildSlideShowImagesList( void ) if ( bLoaded ) { - char szKeywords[ 256 ]; - Q_strcpy( szKeywords, pMaterialKeys->GetString( "%keywords", "" ) ); + char szKeywords[ 256 ] = {0}; + V_strcpy_safe( szKeywords, pMaterialKeys->GetString( "%keywords", "" ) ); char *pchKeyword = szKeywords; @@ -306,7 +306,7 @@ void C_SlideshowDisplay::BuildSlideShowImagesList( void ) { // Couldn't find the list, so create it iList = m_SlideMaterialLists.AddToTail( new SlideMaterialList_t ); - Q_strcpy( m_SlideMaterialLists[ iList ]->szSlideKeyword, pchKeyword ); + V_strcpy_safe( m_SlideMaterialLists[iList]->szSlideKeyword, pchKeyword ); } // Add material index to this list @@ -329,7 +329,7 @@ void C_SlideshowDisplay::BuildSlideShowImagesList( void ) { // Couldn't find the generic list, so create it iList = m_SlideMaterialLists.AddToHead( new SlideMaterialList_t ); - Q_strcpy( m_SlideMaterialLists[ iList ]->szSlideKeyword, "" ); + V_strcpy_safe( m_SlideMaterialLists[iList]->szSlideKeyword, "" ); } // Add material index to this list diff --git a/mp/src/game/client/c_soundscape.cpp b/mp/src/game/client/c_soundscape.cpp index 3196eb94..a9baa479 100644 --- a/mp/src/game/client/c_soundscape.cpp +++ b/mp/src/game/client/c_soundscape.cpp @@ -150,7 +150,7 @@ public: { Msg( "- %d: %s\n", i, m_soundscapes[i]->GetName() ); } - if ( m_forcedSoundscapeIndex ) + if ( m_forcedSoundscapeIndex >= 0 ) { Msg( "- PLAYING DEBUG SOUNDSCAPE: %d [%s]\n", m_forcedSoundscapeIndex, SoundscapeNameByIndex(m_forcedSoundscapeIndex) ); } diff --git a/mp/src/game/client/c_team_objectiveresource.h b/mp/src/game/client/c_team_objectiveresource.h index b7139802..9cc431e2 100644 --- a/mp/src/game/client/c_team_objectiveresource.h +++ b/mp/src/game/client/c_team_objectiveresource.h @@ -104,7 +104,7 @@ public: Assert( iCapper != TEAM_UNASSIGNED ); - return GetIconForTeam( index, iCapper );; + return GetIconForTeam( index, iCapper ); } // Icon for the specified team diff --git a/mp/src/game/client/c_vote_controller.cpp b/mp/src/game/client/c_vote_controller.cpp index c900c27e..e99372da 100644 --- a/mp/src/game/client/c_vote_controller.cpp +++ b/mp/src/game/client/c_vote_controller.cpp @@ -81,7 +81,7 @@ C_VoteController::~C_VoteController() void C_VoteController::ResetData() { m_iActiveIssueIndex = INVALID_ISSUE; - m_iOnlyTeamToVote = TEAM_INVALID; + m_iOnlyTeamToVote = TEAM_UNASSIGNED; for( int index = 0; index < MAX_VOTE_OPTIONS; index++ ) { m_nVoteOptionCount[index] = 0; @@ -118,9 +118,11 @@ void C_VoteController::ClientThink() { if ( m_nPotentialVotes > 0 ) { +#ifdef STAGING_ONLY // Currently hard-coded to MAX_VOTE_COUNT options per issue DevMsg( "Votes: Option1 - %d, Option2 - %d, Option3 - %d, Option4 - %d, Option5 - %d\n", m_nVoteOptionCount[0], m_nVoteOptionCount[1], m_nVoteOptionCount[2], m_nVoteOptionCount[3], m_nVoteOptionCount[4] ); +#endif // STAGING_ONLY IGameEvent *event = gameeventmanager->CreateEvent( "vote_changed" ); if ( event ) diff --git a/mp/src/game/client/cdll_bounded_cvars.cpp b/mp/src/game/client/cdll_bounded_cvars.cpp index 0928b774..fa00db63 100644 --- a/mp/src/game/client/cdll_bounded_cvars.cpp +++ b/mp/src/game/client/cdll_bounded_cvars.cpp @@ -133,7 +133,7 @@ float GetClientInterpAmount() } else { - if (!CommandLine()->FindParm("-hushasserts")) + if ( !HushAsserts() ) { AssertMsgOnce( false, "GetInterpolationAmount: can't get cl_updaterate cvar." ); } diff --git a/mp/src/game/client/cdll_client_int.cpp b/mp/src/game/client/cdll_client_int.cpp index 10cce078..5b8f10d9 100644 --- a/mp/src/game/client/cdll_client_int.cpp +++ b/mp/src/game/client/cdll_client_int.cpp @@ -141,6 +141,7 @@ #if defined( TF_CLIENT_DLL ) #include "econ/tool_items/custom_texture_cache.h" + #endif #ifdef WORKSHOP_IMPORT_ENABLED @@ -568,7 +569,8 @@ void DisplayBoneSetupEnts() if ( pEnt->m_Count >= 3 ) { printInfo.color[0] = 1; - printInfo.color[1] = printInfo.color[2] = 0; + printInfo.color[1] = 0; + printInfo.color[2] = 0; } else if ( pEnt->m_Count == 2 ) { @@ -578,7 +580,9 @@ void DisplayBoneSetupEnts() } else { - printInfo.color[0] = printInfo.color[0] = printInfo.color[0] = 1; + printInfo.color[0] = 1; + printInfo.color[1] = 1; + printInfo.color[2] = 1; } engine->Con_NXPrintf( &printInfo, "%25s / %3d / %3d", pEnt->m_ModelName, pEnt->m_Count, pEnt->m_Index ); printInfo.index++; @@ -2561,8 +2565,8 @@ void CHLClient::ClientAdjustStartSoundParams( StartSoundParams_t& params ) // Halloween voice futzery? else { - float flHeadScale = 1.f; - CALL_ATTRIB_HOOK_FLOAT_ON_OTHER( pEntity, flHeadScale, head_scale ); + float flVoicePitchScale = 1.f; + CALL_ATTRIB_HOOK_FLOAT_ON_OTHER( pEntity, flVoicePitchScale, voice_pitch_scale ); int iHalloweenVoiceSpell = 0; CALL_ATTRIB_HOOK_INT_ON_OTHER( pEntity, iHalloweenVoiceSpell, halloween_voice_modulation ); @@ -2570,17 +2574,9 @@ void CHLClient::ClientAdjustStartSoundParams( StartSoundParams_t& params ) { params.pitch *= 0.8f; } - else if( flHeadScale != 1.f ) + else if( flVoicePitchScale != 1.f ) { - // Big head, deep voice - if( flHeadScale > 1.f ) - { - params.pitch *= 0.8f; - } - else // Small head, high voice - { - params.pitch *= 1.3f; - } + params.pitch *= flVoicePitchScale; } } } diff --git a/mp/src/game/client/client_base.vpc b/mp/src/game/client/client_base.vpc index 309ffb8c..b1e5ae53 100644 --- a/mp/src/game/client/client_base.vpc +++ b/mp/src/game/client/client_base.vpc @@ -1252,7 +1252,8 @@ $Project $Lib vtf $ImpLib steam_api - $Lib $LIBCOMMON/libcrypto [$POSIX] + $Libexternal $LIBCOMMON/libcrypto [$OSXALL] + $Libexternal "$SRCDIR\lib\common\$(CRYPTOPPDIR)\libcrypto" [$LINUXALL] $ImpLib "$LIBCOMMON\curl" [$OSXALL] @@ -1262,7 +1263,7 @@ $Project $Libexternal libz [$LINUXALL] $Libexternal "$LIBCOMMON/libcurl" [$LINUXALL] $Libexternal "$LIBCOMMON/libcurlssl" [$LINUXALL] - $Libexternal "$LIBCOMMON/libssl" [$LINUXALL] + $Libexternal "$SRCDIR\lib\common\$(CRYPTOPPDIR)\libssl" [$LINUXALL] } } diff --git a/mp/src/game/client/clientleafsystem.cpp b/mp/src/game/client/clientleafsystem.cpp index 0a4018f1..fa3a0097 100644 --- a/mp/src/game/client/clientleafsystem.cpp +++ b/mp/src/game/client/clientleafsystem.cpp @@ -189,12 +189,12 @@ private: void RemoveShadowFromLeaves( ClientLeafShadowHandle_t handle ); // Methods associated with the various bi-directional sets - static unsigned short& FirstRenderableInLeaf( int leaf ) + static unsigned int& FirstRenderableInLeaf( int leaf ) { return s_ClientLeafSystem.m_Leaf[leaf].m_FirstElement; } - static unsigned short& FirstLeafInRenderable( unsigned short renderable ) + static unsigned int& FirstLeafInRenderable( unsigned short renderable ) { return s_ClientLeafSystem.m_Renderables[renderable].m_LeafList; } @@ -248,8 +248,8 @@ private: int m_RenderFrame2; int m_EnumCount; // Have I been added to a particular shadow yet? int m_TranslucencyCalculated; - unsigned short m_LeafList; // What leafs is it in? - unsigned short m_RenderLeaf; // What leaf do I render in? + unsigned int m_LeafList; // What leafs is it in? + unsigned int m_RenderLeaf; // What leaf do I render in? unsigned char m_Flags; // rendering flags unsigned char m_RenderGroup; // RenderGroup_t type unsigned short m_FirstShadow; // The first shadow caster that cast on it @@ -260,7 +260,7 @@ private: // The leaf contains an index into a list of renderables struct ClientLeaf_t { - unsigned short m_FirstElement; + unsigned int m_FirstElement; unsigned short m_FirstShadow; unsigned short m_FirstDetailProp; @@ -302,7 +302,7 @@ private: CUtlLinkedList< ShadowInfo_t, ClientLeafShadowHandle_t, false, unsigned int > m_Shadows; // Maintains the list of all renderables in a particular leaf - CBidirectionalSet< int, ClientRenderHandle_t, unsigned short, unsigned int > m_RenderablesInLeaf; + CBidirectionalSet< int, ClientRenderHandle_t, unsigned int, unsigned int > m_RenderablesInLeaf; // Maintains a list of all shadows in a particular leaf CBidirectionalSet< int, ClientLeafShadowHandle_t, unsigned short, unsigned int > m_ShadowsInLeaf; @@ -343,7 +343,8 @@ void DefaultRenderBoundsWorldspace( IClientRenderable *pRenderable, Vector &absM { // Tracker 37433: This fixes a bug where if the stunstick is being wielded by a combine soldier, the fact that the stick was // attached to the soldier's hand would move it such that it would get frustum culled near the edge of the screen. - C_BaseEntity *pEnt = pRenderable->GetIClientUnknown()->GetBaseEntity(); + IClientUnknown *pUnk = pRenderable->GetIClientUnknown(); + C_BaseEntity *pEnt = pUnk->GetBaseEntity(); if ( pEnt && pEnt->IsFollowingEntity() ) { C_BaseEntity *pParent = pEnt->GetFollowedEntity(); @@ -629,7 +630,7 @@ void CClientLeafSystem::NewRenderable( IClientRenderable* pRenderable, RenderGro info.m_Flags = flags; info.m_RenderGroup = (unsigned char)type; info.m_EnumCount = 0; - info.m_RenderLeaf = 0xFFFF; + info.m_RenderLeaf = m_RenderablesInLeaf.InvalidIndex(); if ( IsViewModelRenderGroup( (RenderGroup_t)info.m_RenderGroup ) ) { AddToViewModelList( handle ); @@ -986,7 +987,7 @@ void CClientLeafSystem::AddShadowToLeaf( int leaf, ClientLeafShadowHandle_t shad m_ShadowsInLeaf.AddElementToBucket( leaf, shadow ); // Add the shadow exactly once to all renderables in the leaf - unsigned short i = m_RenderablesInLeaf.FirstElement( leaf ); + unsigned int i = m_RenderablesInLeaf.FirstElement( leaf ); while ( i != m_RenderablesInLeaf.InvalidIndex() ) { ClientRenderHandle_t renderable = m_RenderablesInLeaf.Element(i); @@ -1092,7 +1093,54 @@ void CClientLeafSystem::AddRenderableToLeaf( int leaf, ClientRenderHandle_t rend #ifdef VALIDATE_CLIENT_LEAF_SYSTEM m_RenderablesInLeaf.ValidateAddElementToBucket( leaf, renderable ); #endif - m_RenderablesInLeaf.AddElementToBucket( leaf, renderable ); + +#ifdef DUMP_RENDERABLE_LEAFS + static uint32 count = 0; + if (count < m_RenderablesInLeaf.NumAllocated()) + { + count = m_RenderablesInLeaf.NumAllocated(); + Msg("********** frame: %d count:%u ***************\n", gpGlobals->framecount, count ); + + if (count >= 20000) + { + for (int j = 0; j < m_RenderablesInLeaf.NumAllocated(); j++) + { + const ClientRenderHandle_t& renderable = m_RenderablesInLeaf.Element(j); + RenderableInfo_t& info = m_Renderables[renderable]; + + char pTemp[256]; + const char *pClassName = "<unknown renderable>"; + C_BaseEntity *pEnt = info.m_pRenderable->GetIClientUnknown()->GetBaseEntity(); + if ( pEnt ) + { + pClassName = pEnt->GetClassname(); + } + else + { + CNewParticleEffect *pEffect = dynamic_cast< CNewParticleEffect*>( info.m_pRenderable ); + if ( pEffect ) + { + Vector mins, maxs; + pEffect->GetRenderBounds(mins, maxs); + Q_snprintf( pTemp, sizeof(pTemp), "ps: %s %.2f,%.2f", pEffect->GetEffectName(), maxs.x - mins.x, maxs.y - mins.y ); + pClassName = pTemp; + } + else if ( dynamic_cast< CParticleEffectBinding* >( info.m_pRenderable ) ) + { + pClassName = "<old particle system>"; + } + } + + Msg(" %d: %p group:%d %s %d %d TransCalc:%d renderframe:%d\n", j, info.m_pRenderable, info.m_RenderGroup, pClassName, + info.m_LeafList, info.m_RenderLeaf, info.m_TranslucencyCalculated, info.m_RenderFrame); + } + + DebuggerBreak(); + } + } +#endif // DUMP_RENDERABLE_LEAFS + + m_RenderablesInLeaf.AddElementToBucket(leaf, renderable); if ( !ShouldRenderableReceiveShadow( renderable, SHADOW_FLAGS_PROJECTED_TEXTURE_TYPE_MASK ) ) return; @@ -1344,7 +1392,7 @@ void CClientLeafSystem::ComputeTranslucentRenderLeaf( int count, const LeafIndex orderedList.AddToTail( LeafToMarker( leaf ) ); // iterate over all elements in this leaf - unsigned short idx = m_RenderablesInLeaf.FirstElement(leaf); + unsigned int idx = m_RenderablesInLeaf.FirstElement(leaf); while (idx != m_RenderablesInLeaf.InvalidIndex()) { RenderableInfo_t& info = m_Renderables[m_RenderablesInLeaf.Element(idx)]; @@ -1512,7 +1560,7 @@ void CClientLeafSystem::CollateRenderablesInLeaf( int leaf, int worldListLeafInd AddRenderableToRenderList( *info.m_pRenderList, NULL, worldListLeafIndex, RENDER_GROUP_OPAQUE_ENTITY, NULL ); // Collate everything. - unsigned short idx = m_RenderablesInLeaf.FirstElement(leaf); + unsigned int idx = m_RenderablesInLeaf.FirstElement(leaf); for ( ;idx != m_RenderablesInLeaf.InvalidIndex(); idx = m_RenderablesInLeaf.NextElement(idx) ) { ClientRenderHandle_t handle = m_RenderablesInLeaf.Element(idx); diff --git a/mp/src/game/client/clientmode_shared.cpp b/mp/src/game/client/clientmode_shared.cpp index 68bc89cb..622208a4 100644 --- a/mp/src/game/client/clientmode_shared.cpp +++ b/mp/src/game/client/clientmode_shared.cpp @@ -85,6 +85,12 @@ extern ConVar v_viewmodel_fov; extern ConVar voice_modenable; extern bool IsInCommentaryMode( void ); +extern const char* GetWearLocalizationString( float flWear ); + +CON_COMMAND( cl_reload_localization_files, "Reloads all localization files" ) +{ + g_pVGuiLocalize->ReloadLocalizationFiles(); +} #ifdef VOICE_VOX_ENABLE void VoxCallback( IConVar *var, const char *oldString, float oldFloat ) @@ -141,7 +147,7 @@ CON_COMMAND( hud_reloadscheme, "Reloads hud layout and animation scripts." ) if ( !mode ) return; - mode->ReloadScheme(); + mode->ReloadScheme(true); } #ifdef _DEBUG @@ -292,8 +298,14 @@ ClientModeShared::~ClientModeShared() delete m_pViewport; } -void ClientModeShared::ReloadScheme( void ) +void ClientModeShared::ReloadScheme( bool flushLowLevel ) { + // Invalidate the global cache first. + if (flushLowLevel) + { + KeyValuesSystem()->InvalidateCache(); + } + m_pViewport->ReloadScheme( "resource/ClientScheme.res" ); ClearKeyValuesCache(); } @@ -335,7 +347,7 @@ void ClientModeShared::Init() Assert( m_pReplayReminderPanel ); #endif - ListenForGameEvent( "player_connect" ); + ListenForGameEvent( "player_connect_client" ); ListenForGameEvent( "player_disconnect" ); ListenForGameEvent( "player_team" ); ListenForGameEvent( "server_cvar" ); @@ -421,7 +433,7 @@ void ClientModeShared::OverrideView( CViewSetup *pSetup ) if( ::input->CAM_IsThirdPerson() ) { - Vector cam_ofs = g_ThirdPersonManager.GetCameraOffsetAngles(); + const Vector& cam_ofs = g_ThirdPersonManager.GetCameraOffsetAngles(); Vector cam_ofs_distance = g_ThirdPersonManager.GetFinalCameraOffset(); cam_ofs_distance *= g_ThirdPersonManager.GetDistanceFraction(); @@ -867,7 +879,7 @@ void ClientModeShared::LevelShutdown( void ) void ClientModeShared::Enable() { - vgui::VPANEL pRoot = VGui_GetClientDLLRootPanel();; + vgui::VPANEL pRoot = VGui_GetClientDLLRootPanel(); // Add our viewport to the root panel. if( pRoot != 0 ) @@ -894,7 +906,7 @@ void ClientModeShared::Enable() void ClientModeShared::Disable() { - vgui::VPANEL pRoot = VGui_GetClientDLLRootPanel();; + vgui::VPANEL pRoot = VGui_GetClientDLLRootPanel(); // Remove our viewport from the root panel. if( pRoot != 0 ) @@ -923,7 +935,7 @@ void ClientModeShared::Layout() m_pViewport->SetBounds(0, 0, wide, tall); if ( changed ) { - ReloadScheme(); + ReloadScheme(false); } } } @@ -955,7 +967,7 @@ void ClientModeShared::FireGameEvent( IGameEvent *event ) const char *eventname = event->GetName(); - if ( Q_strcmp( "player_connect", eventname ) == 0 ) + if ( Q_strcmp( "player_connect_client", eventname ) == 0 ) { if ( !hudChat ) return; @@ -1115,7 +1127,7 @@ void ClientModeShared::FireGameEvent( IGameEvent *event ) { CBasePlayer *pSpectatorTarget = UTIL_PlayerByIndex( GetSpectatorTarget() ); - if ( pSpectatorTarget && (GetSpectatorMode() == OBS_MODE_IN_EYE || GetSpectatorMode() == OBS_MODE_CHASE) ) + if ( pSpectatorTarget && (GetSpectatorMode() == OBS_MODE_IN_EYE || GetSpectatorMode() == OBS_MODE_CHASE || GetSpectatorMode() == OBS_MODE_POI) ) { if ( pSpectatorTarget->GetTeamNumber() == team ) { @@ -1222,10 +1234,14 @@ void ClientModeShared::FireGameEvent( IGameEvent *event ) entityquality_t iItemQuality = event->GetInt( "quality" ); int iMethod = event->GetInt( "method" ); int iItemDef = event->GetInt( "itemdef" ); + bool bIsStrange = event->GetInt( "isstrange" ); + bool bIsUnusual = event->GetInt( "isunusual" ); + float flWear = event->GetFloat( "wear" ); + C_BasePlayer *pPlayer = UTIL_PlayerByIndex( iPlayerIndex ); const GameItemDefinition_t *pItemDefinition = dynamic_cast<GameItemDefinition_t *>( GetItemSchema()->GetItemDefinition( iItemDef ) ); - if ( !pPlayer || !pItemDefinition ) + if ( !pPlayer || !pItemDefinition || pItemDefinition->IsHidden() ) return; if ( g_PR ) @@ -1245,19 +1261,101 @@ void ClientModeShared::FireGameEvent( IGameEvent *event ) _snwprintf( wszItemFound, ARRAYSIZE( wszItemFound ), L"%ls", g_pVGuiLocalize->Find( pszLocString ) ); wchar_t *colorMarker = wcsstr( wszItemFound, L"::" ); + const CEconItemRarityDefinition* pItemRarity = GetItemSchema()->GetRarityDefinition( pItemDefinition->GetRarity() ); + if ( colorMarker ) - { - const char *pszQualityColorString = EconQuality_GetColorString( (EEconItemQuality)iItemQuality ); - if ( pszQualityColorString ) + { + if ( pItemRarity ) { - hudChat->SetCustomColor( pszQualityColorString ); - *(colorMarker+1) = COLOR_CUSTOM; + attrib_colors_t colorRarity = pItemRarity->GetAttribColor(); + vgui::HScheme scheme = vgui::scheme()->GetScheme( "ClientScheme" ); + vgui::IScheme *pScheme = vgui::scheme()->GetIScheme( scheme ); + Color color = pScheme->GetColor( GetColorNameForAttribColor( colorRarity ), Color( 255, 255, 255, 255 ) ); + hudChat->SetCustomColor( color ); } + else + { + const char *pszQualityColorString = EconQuality_GetColorString( (EEconItemQuality)iItemQuality ); + if ( pszQualityColorString ) + { + hudChat->SetCustomColor( pszQualityColorString ); + } + } + + *(colorMarker+1) = COLOR_CUSTOM; } // TODO: Update the localization strings to only have two format parameters since that's all we need. wchar_t wszLocalizedString[256]; - g_pVGuiLocalize->ConstructString( wszLocalizedString, sizeof( wszLocalizedString ), wszItemFound, 3, wszPlayerName, CEconItemLocalizedFullNameGenerator( GLocalizationProvider(), pItemDefinition, iItemQuality ).GetFullName(), L"" ); + g_pVGuiLocalize->ConstructString( + wszLocalizedString, + sizeof( wszLocalizedString ), + LOCCHAR( "%s1" ), + 1, + CEconItemLocalizedFullNameGenerator( GLocalizationProvider(), pItemDefinition, iItemQuality ).GetFullName() + ); + + locchar_t tempName[MAX_ITEM_NAME_LENGTH]; + if ( pItemRarity ) + { + // grade and Wear + loc_scpy_safe( tempName, wszLocalizedString ); + + const locchar_t *loc_WearText = LOCCHAR(""); + const char *pszTooltipText = "TFUI_InvTooltip_Rarity"; + + if ( !IsWearableSlot( pItemDefinition->GetDefaultLoadoutSlot() ) ) + { + loc_WearText = g_pVGuiLocalize->Find( GetWearLocalizationString( flWear ) ); + } + else + { + pszTooltipText = "TFUI_InvTooltip_RarityNoWear"; + } + + g_pVGuiLocalize->ConstructString( wszLocalizedString, + ARRAYSIZE( wszLocalizedString ) * sizeof( locchar_t ), + g_pVGuiLocalize->Find( pszTooltipText ), + 3, + g_pVGuiLocalize->Find( pItemRarity->GetLocKey() ), + tempName, + loc_WearText + ); + + if ( bIsUnusual ) + { + loc_scpy_safe( tempName, wszLocalizedString ); + + g_pVGuiLocalize->ConstructString( wszLocalizedString, + ARRAYSIZE( wszLocalizedString ) * sizeof( locchar_t ), + LOCCHAR( "%s1 %s2" ), + 2, + g_pVGuiLocalize->Find( "rarity4" ), + tempName + ); + } + + if ( bIsStrange ) + { + loc_scpy_safe( tempName, wszLocalizedString ); + + g_pVGuiLocalize->ConstructString( wszLocalizedString, + ARRAYSIZE( wszLocalizedString ) * sizeof( locchar_t ), + LOCCHAR( "%s1 %s2" ), + 2, + g_pVGuiLocalize->Find( "strange" ), + tempName + ); + } + } + + loc_scpy_safe( tempName, wszLocalizedString ); + g_pVGuiLocalize->ConstructString( + wszLocalizedString, + sizeof( wszLocalizedString ), + wszItemFound, + 3, + wszPlayerName, tempName, L"" ); char szLocalized[256]; g_pVGuiLocalize->ConvertUnicodeToANSI( wszLocalizedString, szLocalized, sizeof( szLocalized ) ); diff --git a/mp/src/game/client/clientmode_shared.h b/mp/src/game/client/clientmode_shared.h index 27336964..beef0ad9 100644 --- a/mp/src/game/client/clientmode_shared.h +++ b/mp/src/game/client/clientmode_shared.h @@ -66,7 +66,7 @@ public: virtual void Disable(); virtual void Layout(); - virtual void ReloadScheme( void ); + virtual void ReloadScheme( bool flushLowLevel ); virtual void OverrideView( CViewSetup *pSetup ); virtual bool ShouldDrawDetailObjects( ); virtual bool ShouldDrawEntity(C_BaseEntity *pEnt); diff --git a/mp/src/game/client/clientshadowmgr.cpp b/mp/src/game/client/clientshadowmgr.cpp index c37e7650..bd3e2c2a 100644 --- a/mp/src/game/client/clientshadowmgr.cpp +++ b/mp/src/game/client/clientshadowmgr.cpp @@ -1802,6 +1802,9 @@ ClientShadowHandle_t CClientShadowMgr::CreateProjectedTexture( ClientEntityHandl if( !( flags & SHADOW_FLAGS_FLASHLIGHT ) ) { IClientRenderable *pRenderable = ClientEntityList().GetClientRenderableFromHandle( entity ); + if ( !pRenderable ) + return m_Shadows.InvalidIndex(); + int modelType = modelinfo->GetModelType( pRenderable->GetModel() ); if (modelType == mod_brush) { diff --git a/mp/src/game/client/clientsideeffects.cpp b/mp/src/game/client/clientsideeffects.cpp index b9cb5f56..c7912e3b 100644 --- a/mp/src/game/client/clientsideeffects.cpp +++ b/mp/src/game/client/clientsideeffects.cpp @@ -69,6 +69,15 @@ const char *CClientSideEffect::GetName( void ) } //----------------------------------------------------------------------------- +// Purpose: Set the name of effect +// Input : const char +//----------------------------------------------------------------------------- +void CClientSideEffect::SetEffectName( const char *pszName ) +{ + m_pszName = pszName; +} + +//----------------------------------------------------------------------------- // Purpose: Is effect still active? // Output : Returns true on success, false on failure. //----------------------------------------------------------------------------- @@ -99,6 +108,7 @@ public: // Add an effect to the effects list void AddEffect( CClientSideEffect *effect ); // Remove the specified effect + void RemoveEffect( CClientSideEffect *effect ); // Draw/update all effects in the current list void DrawEffects( double frametime ); // Flush out all effects from the list @@ -161,6 +171,23 @@ void CEffectsList::AddEffect( CClientSideEffect *effect ) } //----------------------------------------------------------------------------- +void CEffectsList::RemoveEffect( CClientSideEffect *effect ) +{ + Assert( effect ); + CClientSideEffect **end = &m_rgEffects[m_nEffects]; + for( CClientSideEffect **p = &m_rgEffects[0]; p < end; ++p) + { + if ( *p == effect ) + { + RemoveEffect( p - &m_rgEffects[0] ); // todo remove this crutch + return; + } + } + + Assert( false ); // don't know this effect +} + +//----------------------------------------------------------------------------- // Purpose: Remove specified effect by index // Input : effectIndex - //----------------------------------------------------------------------------- diff --git a/mp/src/game/client/clientsideeffects.h b/mp/src/game/client/clientsideeffects.h index c5aa4fd6..fd749565 100644 --- a/mp/src/game/client/clientsideeffects.h +++ b/mp/src/game/client/clientsideeffects.h @@ -32,7 +32,10 @@ public: virtual bool IsActive( void ); // Sets the effect to inactive so it can be destroed virtual void Destroy( void ); - + + // Sets the effect name (useful for debugging). + virtual void SetEffectName( const char *pszName ); + private: // Name of effect ( static data ) const char *m_pszName; @@ -50,6 +53,8 @@ public: // Add an effect to the list of effects virtual void AddEffect( CClientSideEffect *effect ) = 0; + // Remove the specified effect + virtual void RemoveEffect( CClientSideEffect *effect ) = 0; // Simulate/Update/Draw effects on list virtual void DrawEffects( double frametime ) = 0; // Flush out all effects fbrom the list diff --git a/mp/src/game/client/fx_quad.cpp b/mp/src/game/client/fx_quad.cpp index 6a254b97..12d95b7d 100644 --- a/mp/src/game/client/fx_quad.cpp +++ b/mp/src/game/client/fx_quad.cpp @@ -13,11 +13,21 @@ // memdbgon must be the last include file in a .cpp file!!! #include "tier0/memdbgon.h" -CFXQuad::CFXQuad( const FXQuadData_t &data ) +static const char g_EffectName[] = "Quad"; -: CClientSideEffect( "Quad" ) +CFXQuad::CFXQuad( const FXQuadData_t &data ) + : CClientSideEffect( g_EffectName ) { m_FXData = data; + + if ( data.m_pMaterial != NULL ) + { + // If we've got a material, use that as our effectname instead of just "Quad". + // This should hopefully help narrow down messages like "No room for effect Quad". + const char *szMaterialName = data.m_pMaterial->GetName(); + if ( szMaterialName ) + SetEffectName( szMaterialName ); + } } CFXQuad::~CFXQuad( void ) @@ -62,6 +72,12 @@ void CFXQuad::Draw( double frametime ) float alpha = m_FXData.m_flStartAlpha + ( ( m_FXData.m_flEndAlpha - m_FXData.m_flStartAlpha ) * alphaTimePerc ); alpha = clamp( alpha, 0.0f, 1.0f ); + + // PASSTIME don't bother if alpha is 0 + if ( alpha == 0 ) + { + return; + } CMatRenderContextPtr pRenderContext( materials ); @@ -152,6 +168,8 @@ bool CFXQuad::IsActive( void ) //----------------------------------------------------------------------------- void CFXQuad::Destroy( void ) { + SetEffectName( g_EffectName ); + //Release the material if ( m_FXData.m_pMaterial != NULL ) { diff --git a/mp/src/game/client/fx_quad.h b/mp/src/game/client/fx_quad.h index 77563e8b..638547e8 100644 --- a/mp/src/game/client/fx_quad.h +++ b/mp/src/game/client/fx_quad.h @@ -82,8 +82,6 @@ public: virtual void Destroy( void ); virtual void Update( double frametime ); -protected: - FXQuadData_t m_FXData; }; diff --git a/mp/src/game/client/fx_tracer.cpp b/mp/src/game/client/fx_tracer.cpp index f0ca0e13..cec013a6 100644 --- a/mp/src/game/client/fx_tracer.cpp +++ b/mp/src/game/client/fx_tracer.cpp @@ -13,6 +13,9 @@ // memdbgon must be the last include file in a .cpp file!!! #include "tier0/memdbgon.h" +ConVar r_drawtracers( "r_drawtracers", "1", FCVAR_CHEAT ); +ConVar r_drawtracers_firstperson( "r_drawtracers_firstperson", "1", FCVAR_ARCHIVE, "Toggle visibility of first person weapon tracers" ); + #define TRACER_SPEED 5000 //----------------------------------------------------------------------------- @@ -23,7 +26,7 @@ Vector GetTracerOrigin( const CEffectData &data ) Vector vecStart = data.m_vStart; QAngle vecAngles; - int iAttachment = data.m_nAttachmentIndex;; + int iAttachment = data.m_nAttachmentIndex; // Attachment? if ( data.m_fFlags & TRACER_FLAG_USEATTACHMENT ) @@ -77,6 +80,17 @@ void TracerCallback( const CEffectData &data ) if ( !player ) return; + if ( !r_drawtracers.GetBool() ) + return; + + if ( !r_drawtracers_firstperson.GetBool() ) + { + C_BasePlayer *pPlayer = dynamic_cast<C_BasePlayer*>( data.GetEntity() ); + + if ( pPlayer && !pPlayer->ShouldDrawThisPlayer() ) + return; + } + // Grab the data Vector vecStart = GetTracerOrigin( data ); float flVelocity = data.m_flScale; @@ -120,6 +134,17 @@ void ParticleTracerCallback( const CEffectData &data ) if ( !player ) return; + if ( !r_drawtracers.GetBool() ) + return; + + if ( !r_drawtracers_firstperson.GetBool() ) + { + C_BasePlayer *pPlayer = dynamic_cast<C_BasePlayer*>( data.GetEntity() ); + + if ( pPlayer && !pPlayer->ShouldDrawThisPlayer() ) + return; + } + // Grab the data Vector vecStart = GetTracerOrigin( data ); Vector vecEnd = data.m_vOrigin; diff --git a/mp/src/game/client/game_controls/MapOverview.cpp b/mp/src/game/client/game_controls/MapOverview.cpp index b4262fbb..73d259ff 100644 --- a/mp/src/game/client/game_controls/MapOverview.cpp +++ b/mp/src/game/client/game_controls/MapOverview.cpp @@ -181,7 +181,7 @@ void CMapOverview::Init( void ) // register for events as client listener ListenForGameEvent( "game_newmap" ); ListenForGameEvent( "round_start" ); - ListenForGameEvent( "player_connect" ); + ListenForGameEvent( "player_connect_client" ); ListenForGameEvent( "player_info" ); ListenForGameEvent( "player_team" ); ListenForGameEvent( "player_spawn" ); @@ -933,7 +933,7 @@ void CMapOverview::FireGameEvent( IGameEvent *event ) ResetRound(); } - else if ( Q_strcmp(type,"player_connect") == 0 ) + else if ( Q_strcmp(type,"player_connect_client") == 0 ) { int index = event->GetInt("index"); // = entity index - 1 diff --git a/mp/src/game/client/game_controls/SpectatorGUI.cpp b/mp/src/game/client/game_controls/SpectatorGUI.cpp index 1c95068a..3ce30008 100644 --- a/mp/src/game/client/game_controls/SpectatorGUI.cpp +++ b/mp/src/game/client/game_controls/SpectatorGUI.cpp @@ -67,6 +67,7 @@ static const char *s_SpectatorModes[] = "#Spec_Mode2", // OBS_MODE_FIXED, "#Spec_Mode3", // OBS_MODE_IN_EYE, "#Spec_Mode4", // OBS_MODE_CHASE, + "#Spec_Mode_POI", // OBS_MODE_POI, PASSTIME "#Spec_Mode5", // OBS_MODE_ROAMING, }; @@ -806,6 +807,8 @@ CON_COMMAND_F( spec_mode, "Set spectator mode", FCVAR_CLIENTCMD_CAN_EXECUTE ) if ( mode > LAST_PLAYER_OBSERVERMODE ) mode = OBS_MODE_IN_EYE; + else if ( mode == OBS_MODE_POI ) // PASSTIME skip POI mode since hltv doesn't have the entity data required to make it work + mode = OBS_MODE_ROAMING; } // handle the command clientside diff --git a/mp/src/game/client/game_controls/basemodel_panel.cpp b/mp/src/game/client/game_controls/basemodel_panel.cpp index e4115ea4..5f834412 100644 --- a/mp/src/game/client/game_controls/basemodel_panel.cpp +++ b/mp/src/game/client/game_controls/basemodel_panel.cpp @@ -22,6 +22,7 @@ CBaseModelPanel::CBaseModelPanel( vgui::Panel *pParent, const char *pName ): Bas m_bForcePos = false; m_bMousePressed = false; m_bAllowRotation = false; + m_bAllowPitch = false; m_bAllowFullManipulation = false; m_bApplyManipulators = false; m_bForcedCameraPosition = false; @@ -43,6 +44,7 @@ void CBaseModelPanel::ApplySettings( KeyValues *inResourceData ) // Set whether we render to texture m_bRenderToTexture = inResourceData->GetBool( "render_texture", true ); + m_bUseParticle = inResourceData->GetBool( "use_particle", false ); // Grab and set the camera FOV. float flFOV = GetCameraFOV(); @@ -51,6 +53,7 @@ void CBaseModelPanel::ApplySettings( KeyValues *inResourceData ) // Do we allow rotation on these panels. m_bAllowRotation = inResourceData->GetBool( "allow_rot", false ); + m_bAllowPitch = inResourceData->GetBool( "allow_pitch", false ); // Do we allow full manipulation on these panels. m_bAllowFullManipulation = inResourceData->GetBool( "allow_manip", false ); @@ -64,7 +67,7 @@ void CBaseModelPanel::ApplySettings( KeyValues *inResourceData ) } } - SetMouseInputEnabled( m_bAllowFullManipulation || m_bAllowRotation ); + SetMouseInputEnabled( m_bAllowFullManipulation || m_bAllowRotation || m_bAllowPitch ); } //----------------------------------------------------------------------------- @@ -412,13 +415,16 @@ void CBaseModelPanel::OnMousePressed ( vgui::MouseCode code ) return; } - if ( !m_bAllowRotation ) + if ( !m_bAllowRotation && !m_bAllowPitch ) return; RequestFocus(); EnableMouseCapture( true, code ); + // Save where they clicked + input()->GetCursorPosition( m_nClickStartX, m_nClickStartY ); + // Warp the mouse to the center of the screen int width, height; GetSize( width, height ); @@ -446,11 +452,14 @@ void CBaseModelPanel::OnMouseReleased( vgui::MouseCode code ) return; } - if ( !m_bAllowRotation ) + if ( !m_bAllowRotation && !m_bAllowPitch ) return; EnableMouseCapture( false ); m_bMousePressed = false; + + // Restore the cursor to where the clicked + input()->SetCursorPos( m_nClickStartX, m_nClickStartY ); } //----------------------------------------------------------------------------- @@ -467,7 +476,7 @@ void CBaseModelPanel::OnCursorMoved( int x, int y ) return; } - if ( !m_bAllowRotation ) + if ( !m_bAllowRotation && !m_bAllowPitch ) return; if ( m_bMousePressed ) @@ -476,11 +485,25 @@ void CBaseModelPanel::OnCursorMoved( int x, int y ) int xpos, ypos; input()->GetCursorPos( xpos, ypos ); - // Only want the x delta. - float flDelta = xpos - m_nManipStartX; + if ( m_bAllowRotation ) + { + // Only want the x delta. + float flDelta = xpos - m_nManipStartX; + - // Apply the delta and rotate the player. - RotateYaw( flDelta ); + // Apply the delta and rotate the player. + RotateYaw( flDelta ); + } + + if ( m_bAllowPitch ) + { + // Only want the y delta. + float flDelta = ypos - m_nManipStartY; + + + // Apply the delta and rotate the player. + RotatePitch( flDelta ); + } } } @@ -503,6 +526,23 @@ void CBaseModelPanel::RotateYaw( float flDelta ) //----------------------------------------------------------------------------- //----------------------------------------------------------------------------- +void CBaseModelPanel::RotatePitch( float flDelta ) +{ + m_angPlayer.x += flDelta; + if ( m_angPlayer.x > m_flMaxPitch ) + { + m_angPlayer.x = m_flMaxPitch; + } + else if ( m_angPlayer.x < -m_flMaxPitch ) + { + m_angPlayer.x = -m_flMaxPitch; + } + + SetModelAnglesAndPosition( m_angPlayer, m_vecPlayerPos ); +} + +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- Vector CBaseModelPanel::GetPlayerPos() const { return m_vecPlayerPos; @@ -643,7 +683,7 @@ void CBaseModelPanel::LookAtBounds( const Vector &vecBoundsMin, const Vector &ve // Clear the camera pivot and set position matrix. ResetCameraPivot(); - if (m_bAllowRotation ) + if (m_bAllowRotation || m_bAllowPitch ) { vecCameraOffset.x = 0.0f; } @@ -651,3 +691,150 @@ void CBaseModelPanel::LookAtBounds( const Vector &vecBoundsMin, const Vector &ve UpdateCameraTransform(); } + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +CBaseModelPanel::particle_data_t::~particle_data_t() +{ + if ( m_pParticleSystem ) + { + delete m_pParticleSystem; + m_pParticleSystem = NULL; + } +} + + +//----------------------------------------------------------------------------- +// Purpose: Allocate particle data +//----------------------------------------------------------------------------- +void CBaseModelPanel::particle_data_t::UpdateControlPoints( CStudioHdr *pStudioHdr, matrix3x4_t *pWorldMatrix, const CUtlVector< int >& vecAttachments, int iDefaultBone /*= 0*/, const Vector& vecParticleOffset /*= vec3_origin*/ ) +{ + if ( m_pParticleSystem ) + { + // Update control points which is updating the position of the particles + matrix3x4_t matAttachToWorld; + Vector vecPosition, vecForward, vecRight, vecUp; + if ( vecAttachments.Count() ) + { + for ( int i = 0; i < vecAttachments.Count(); ++i ) + { + const mstudioattachment_t& attach = pStudioHdr->pAttachment( vecAttachments[i] ); + MatrixMultiply( pWorldMatrix[ attach.localbone ], attach.local, matAttachToWorld ); + + MatrixVectors( matAttachToWorld, &vecForward, &vecRight, &vecUp ); + MatrixPosition( matAttachToWorld, vecPosition ); + + m_pParticleSystem->SetControlPointOrientation( i, vecForward, vecRight, vecUp ); + m_pParticleSystem->SetControlPoint( i, vecPosition + vecParticleOffset ); + } + } + else + { + matAttachToWorld = pWorldMatrix[iDefaultBone]; + MatrixVectors( matAttachToWorld, &vecForward, &vecRight, &vecUp ); + MatrixPosition( matAttachToWorld, vecPosition ); + + m_pParticleSystem->SetControlPointOrientation( 0, vecForward, vecRight, vecUp ); + m_pParticleSystem->SetControlPoint( 0, vecPosition + vecParticleOffset ); + } + } + + m_bIsUpdateToDate = true; +} + + +//----------------------------------------------------------------------------- +// Purpose: Allocate particle data +//----------------------------------------------------------------------------- +CBaseModelPanel::particle_data_t *CBaseModelPanel::CreateParticleData( const char *pszParticleName ) +{ + Assert( m_bUseParticle ); + if ( !m_bUseParticle ) + return NULL; + + CParticleCollection *pParticle = g_pParticleSystemMgr->CreateParticleCollection( pszParticleName ); + if ( !pParticle ) + return NULL; + + particle_data_t *pData = new particle_data_t; + pData->m_bIsUpdateToDate = false; + pData->m_pParticleSystem = pParticle; + + m_particleList.AddToTail( pData ); + + return pData; +} + + +//----------------------------------------------------------------------------- +// Purpose: remove and delete particle data +//----------------------------------------------------------------------------- +bool CBaseModelPanel::SafeDeleteParticleData( particle_data_t **pData ) +{ + if ( !m_bUseParticle ) + return false; + + if ( *pData ) + { + FOR_EACH_VEC( m_particleList, i ) + { + if ( *pData == m_particleList[i] ) + { + delete *pData; + *pData = NULL; + m_particleList.FastRemove( i ); + return true; + } + } + } + return false; +} + + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CBaseModelPanel::PrePaint3D( IMatRenderContext *pRenderContext ) +{ + if ( !m_bUseParticle ) + return; + + // mark all effects need to be updated + FOR_EACH_VEC( m_particleList, i ) + { + m_particleList[i]->m_bIsUpdateToDate = false; + } +} + + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CBaseModelPanel::PostPaint3D( IMatRenderContext *pRenderContext ) +{ + if ( !m_bUseParticle ) + return; + + // This needs calling to reset various counters. + g_pParticleSystemMgr->SetLastSimulationTime( gpGlobals->curtime ); + + // Render Particles + pRenderContext->MatrixMode( MATERIAL_MODEL ); + pRenderContext->PushMatrix(); + pRenderContext->LoadIdentity( ); + + FOR_EACH_VEC( m_particleList, i ) + { + if ( m_particleList[i]->m_bIsUpdateToDate ) + { + m_particleList[i]->m_pParticleSystem->Simulate( gpGlobals->frametime, false ); + m_particleList[i]->m_pParticleSystem->Render( pRenderContext ); + m_particleList[i]->m_bIsUpdateToDate = false; + } + } + + pRenderContext->MatrixMode( MATERIAL_MODEL ); + pRenderContext->PopMatrix(); +} + diff --git a/mp/src/game/client/game_controls/basemodel_panel.h b/mp/src/game/client/game_controls/basemodel_panel.h index b9fa0d68..a71bb7a4 100644 --- a/mp/src/game/client/game_controls/basemodel_panel.h +++ b/mp/src/game/client/game_controls/basemodel_panel.h @@ -182,7 +182,8 @@ public: studiohdr_t* GetStudioHdr( void ) { return m_RootMDL.m_MDL.GetStudioHdr(); } void SetBody( unsigned int nBody ) { m_RootMDL.m_MDL.m_nBody = nBody; } - void RotateYaw( float flDelta ); + void RotateYaw( float flDelta ); + void RotatePitch( float flDelta ); Vector GetPlayerPos() const; QAngle GetPlayerAngles() const; @@ -213,6 +214,7 @@ protected: bool m_bForcePos; bool m_bMousePressed; bool m_bAllowRotation; + bool m_bAllowPitch; bool m_bAllowFullManipulation; bool m_bApplyManipulators; bool m_bForcedCameraPosition; @@ -220,6 +222,25 @@ protected: // VGUI script accessible variables. CPanelAnimationVar( bool, m_bStartFramed, "start_framed", "0" ); CPanelAnimationVar( bool, m_bDisableManipulation, "disable_manipulation", "0" ); + CPanelAnimationVar( bool, m_bUseParticle, "use_particle", "0" ); + CPanelAnimationVar( float, m_flMaxPitch, "max_pitch", "90" ); + + struct particle_data_t + { + ~particle_data_t(); + + void UpdateControlPoints( CStudioHdr *pStudioHdr, matrix3x4_t *pWorldMatrix, const CUtlVector< int >& vecAttachments, int iDefaultBone = 0, const Vector& vecParticleOffset = vec3_origin ); + + bool m_bIsUpdateToDate; + CParticleCollection *m_pParticleSystem; + }; + CUtlVector< particle_data_t* > m_particleList; + + particle_data_t *CreateParticleData( const char *pszParticleName ); + bool SafeDeleteParticleData( particle_data_t **pData ); + + virtual void PrePaint3D( IMatRenderContext *pRenderContext ) OVERRIDE; + virtual void PostPaint3D( IMatRenderContext *pRenderContext ) OVERRIDE; }; #endif // BASEMODEL_PANEL_H
\ No newline at end of file diff --git a/mp/src/game/client/game_controls/baseviewport.cpp b/mp/src/game/client/game_controls/baseviewport.cpp index f239cde8..31d8dca2 100644 --- a/mp/src/game/client/game_controls/baseviewport.cpp +++ b/mp/src/game/client/game_controls/baseviewport.cpp @@ -65,7 +65,17 @@ vgui::Panel *g_lastPanel = NULL; // used for mouseover buttons, keeps track of t vgui::Button *g_lastButton = NULL; // used for mouseover buttons, keeps track of the last active button using namespace vgui; -ConVar hud_autoreloadscript("hud_autoreloadscript", "0", FCVAR_NONE, "Automatically reloads the animation script each time one is ran"); +void hud_autoreloadscript_callback( IConVar *var, const char *pOldValue, float flOldValue ); + +ConVar hud_autoreloadscript("hud_autoreloadscript", "0", FCVAR_NONE, "Automatically reloads the animation script each time one is ran", hud_autoreloadscript_callback); + +void hud_autoreloadscript_callback( IConVar *var, const char *pOldValue, float flOldValue ) +{ + if ( g_pClientMode && g_pClientMode->GetViewportAnimationController() ) + { + g_pClientMode->GetViewportAnimationController()->SetAutoReloadScript( hud_autoreloadscript.GetBool() ); + } +} static ConVar cl_leveloverviewmarker( "cl_leveloverviewmarker", "0", FCVAR_CHEAT ); @@ -573,11 +583,12 @@ void CBaseViewport::OnThink() else m_pActivePanel = NULL; } - - m_pAnimController->UpdateAnimations( gpGlobals->curtime ); - // check the auto-reload cvar - m_pAnimController->SetAutoReloadScript(hud_autoreloadscript.GetBool()); + // TF does this in OnTick in TFViewport. This remains to preserve old + // behavior in other games +#if !defined( TF_CLIENT_DLL ) + m_pAnimController->UpdateAnimations( gpGlobals->curtime ); +#endif int count = m_Panels.Count(); diff --git a/mp/src/game/client/game_controls/vguitextwindow.cpp b/mp/src/game/client/game_controls/vguitextwindow.cpp index 3c641859..3c25eb80 100644 --- a/mp/src/game/client/game_controls/vguitextwindow.cpp +++ b/mp/src/game/client/game_controls/vguitextwindow.cpp @@ -138,9 +138,9 @@ void CTextWindow::Reset( void ) // HPE_BEGIN: // [Forrest] Replace strange hard-coded default message with hard-coded error message. //============================================================================= - Q_strcpy( m_szTitle, "Error loading info message." ); - Q_strcpy( m_szMessage, "" ); - Q_strcpy( m_szMessageFallback, "" ); + V_strcpy_safe( m_szTitle, "Error loading info message." ); + V_strcpy_safe( m_szMessage, "" ); + V_strcpy_safe( m_szMessageFallback, "" ); //============================================================================= // HPE_END //============================================================================= diff --git a/mp/src/game/client/hl2/c_waterbullet.cpp b/mp/src/game/client/hl2/c_waterbullet.cpp index b4491ca1..c758069d 100644 --- a/mp/src/game/client/hl2/c_waterbullet.cpp +++ b/mp/src/game/client/hl2/c_waterbullet.cpp @@ -85,7 +85,7 @@ public: sParticle->m_flDieTime = 0.2f; sParticle->m_flRoll = random->RandomInt( 0, 360 ); - sParticle->m_flRollDelta = random->RandomInt( -4, 4 );; + sParticle->m_flRollDelta = random->RandomInt( -4, 4 ); unsigned char color = random->RandomInt( 200, 255 ); diff --git a/mp/src/game/client/hl2/hud_credits.cpp b/mp/src/game/client/hl2/hud_credits.cpp index 8021c49a..6ad1488b 100644 --- a/mp/src/game/client/hl2/hud_credits.cpp +++ b/mp/src/game/client/hl2/hud_credits.cpp @@ -215,8 +215,8 @@ void CHudCredits::ReadNames( KeyValues *pKeyValue ) while ( pKVNames ) { creditname_t Credits; - Q_strcpy( Credits.szCreditName, pKVNames->GetName()); - Q_strcpy( Credits.szFontName, pKeyValue->GetString( Credits.szCreditName, "Default" ) ); + V_strcpy_safe( Credits.szCreditName, pKVNames->GetName() ); + V_strcpy_safe( Credits.szFontName, pKeyValue->GetString( Credits.szCreditName, "Default" ) ); m_CreditsList.AddToTail( Credits ); pKVNames = pKVNames->GetNextKey(); diff --git a/mp/src/game/client/hltvcamera.cpp b/mp/src/game/client/hltvcamera.cpp index 9754b99f..1da4acfd 100644 --- a/mp/src/game/client/hltvcamera.cpp +++ b/mp/src/game/client/hltvcamera.cpp @@ -736,7 +736,7 @@ void C_HLTVCamera::FireGameEvent( IGameEvent * event) } // after this only auto-director commands follow - // don't execute them is autodirector is off and PVS is unlocked + // don't execute them if autodirector is off and PVS is unlocked if ( !spec_autodirector.GetBool() && !IsPVSLocked() ) return; diff --git a/mp/src/game/client/hud_basechat.cpp b/mp/src/game/client/hud_basechat.cpp index 69d67862..f6b20413 100644 --- a/mp/src/game/client/hud_basechat.cpp +++ b/mp/src/game/client/hud_basechat.cpp @@ -24,6 +24,7 @@ #include "vgui/IInput.h" #include "vgui/ILocalize.h" #include "multiplay_gamerules.h" +#include "voice_status.h" // memdbgon must be the last include file in a .cpp file!!! @@ -36,6 +37,7 @@ ConVar hud_saytext_time( "hud_saytext_time", "12", 0 ); ConVar cl_showtextmsg( "cl_showtextmsg", "1", 0, "Enable/disable text messages printing on the screen." ); ConVar cl_chatfilters( "cl_chatfilters", "63", FCVAR_CLIENTDLL | FCVAR_ARCHIVE, "Stores the chat filter settings " ); ConVar cl_chatfilter_version( "cl_chatfilter_version", "0", FCVAR_CLIENTDLL | FCVAR_ARCHIVE | FCVAR_HIDDEN, "Stores the chat filter version" ); +ConVar cl_mute_all_comms("cl_mute_all_comms", "1", FCVAR_ARCHIVE, "If 1, then all communications from a player will be blocked when that player is muted, including chat messages."); const int kChatFilterVersion = 1; @@ -1750,6 +1752,13 @@ void CBaseHudChat::ChatPrintf( int iPlayerIndex, int iFilter, const char *fmt, . return; } + // If a player is muted for voice, also mute them for text because jerks gonna jerk. + if ( cl_mute_all_comms.GetBool() && iPlayerIndex != 0 ) + { + if ( GetClientVoiceMgr() && GetClientVoiceMgr()->IsPlayerBlocked( iPlayerIndex ) ) + return; + } + if ( *pmsg < 32 ) { hudlcd->AddChatLine( pmsg + 1 ); diff --git a/mp/src/game/client/hud_basedeathnotice.cpp b/mp/src/game/client/hud_basedeathnotice.cpp index c7499ac6..36a9cc3c 100644 --- a/mp/src/game/client/hud_basedeathnotice.cpp +++ b/mp/src/game/client/hud_basedeathnotice.cpp @@ -115,7 +115,9 @@ void CHudBaseDeathNotice::Paint() DeathNoticeItem &msg = m_DeathNotices[i]; CHudTexture *icon = msg.iconDeath; - CHudTexture *iconPrekiller = msg.iconPreKiller; + CHudTexture *iconPostKillerName = msg.iconPostKillerName; + CHudTexture *iconPreKillerName = msg.iconPreKillerName; + CHudTexture *iconPostVictimName = msg.iconPostVictimName; wchar_t victim[256]=L""; wchar_t killer[256]=L""; @@ -135,7 +137,11 @@ void CHudBaseDeathNotice::Paint() int iconWide = 0, iconTall = 0, iDeathInfoOffset = 0, iVictimTextOffset = 0, iconActualWide = 0; int iPreKillerTextWide = msg.wzPreKillerText[0] ? UTIL_ComputeStringWidth( m_hTextFont, msg.wzPreKillerText ) - xSpacing : 0; - int iconPrekillerWide = 0, iconPrekillerActualWide = 0, iconPreKillerTall = 0; + + int iconPrekillerWide = 0, iconPrekillerActualWide = 0, iconPrekillerTall = 0; + int iconPostkillerWide = 0, iconPostkillerActualWide = 0, iconPostkillerTall = 0; + + int iconPostVictimWide = 0, iconPostVictimActualWide = 0, iconPostVictimTall = 0; // Get the local position for this notice if ( icon ) @@ -153,23 +159,53 @@ void CHudBaseDeathNotice::Paint() iconWide *= flScale; } - if ( iconPrekiller ) + if ( iconPreKillerName ) { - iconPrekillerActualWide = iconPrekiller->EffectiveWidth( 1.0f ); + iconPrekillerActualWide = iconPreKillerName->EffectiveWidth( 1.0f ); iconPrekillerWide = iconPrekillerActualWide; - iconPreKillerTall = iconPrekiller->EffectiveHeight( 1.0f ); + iconPrekillerTall = iconPreKillerName->EffectiveHeight( 1.0f ); - int iconTallDesired = iLineTall-YRES(2); + int iconTallDesired = iLineTall - YRES( 2 ); Assert( 0 != iconTallDesired ); - float flScale = (float) iconTallDesired / (float) iconPreKillerTall; + float flScale = (float)iconTallDesired / (float)iconPrekillerTall; iconPrekillerActualWide *= flScale; - iconPreKillerTall *= flScale; + iconPrekillerTall *= flScale; iconPrekillerWide *= flScale; } + if ( iconPostKillerName ) + { + iconPostkillerActualWide = iconPostKillerName->EffectiveWidth( 1.0f ); + iconPostkillerWide = iconPostkillerActualWide; + iconPostkillerTall = iconPostKillerName->EffectiveHeight( 1.0f ); + + int iconTallDesired = iLineTall-YRES(2); + Assert( 0 != iconTallDesired ); + float flScale = (float) iconTallDesired / (float) iconPostkillerTall; + + iconPostkillerActualWide *= flScale; + iconPostkillerTall *= flScale; + iconPostkillerWide *= flScale; + } + + if ( iconPostVictimName ) + { + iconPostVictimActualWide = iconPostVictimName->EffectiveWidth( 1.0f ); + iconPostVictimWide = iconPostVictimActualWide; + iconPostVictimTall = iconPostVictimName->EffectiveHeight( 1.0f ); + + int iconTallDesired = iLineTall - YRES( 2 ); + Assert( 0 != iconTallDesired ); + float flScale = (float)iconTallDesired / (float)iconPostVictimTall; + + iconPostVictimActualWide *= flScale; + iconPostVictimTall *= flScale; + iconPostVictimWide *= flScale; + } + int iTotalWide = iKillerTextWide + iconWide + iVictimTextWide + iDeathInfoTextWide + iDeathInfoEndTextWide + ( xMargin * 2 ); - iTotalWide += iconPrekillerWide + iPreKillerTextWide; + iTotalWide += iconPrekillerWide + iconPostkillerWide + iPreKillerTextWide + iconPostVictimWide; int y = yStart + ( ( iLineTall + m_flLineSpacing ) * i ); int yText = y + ( ( iLineTall - iTextTall ) / 2 ); @@ -190,6 +226,14 @@ void CHudBaseDeathNotice::Paint() x += xMargin; + // prekiller icon + if ( iconPreKillerName ) + { + int yPreIconTall = y + ( ( iLineTall - iconPrekillerTall ) / 2 ); + iconPreKillerName->DrawSelf( x, yPreIconTall, iconPrekillerActualWide, iconPrekillerTall, m_clrIcon); + x += iconPrekillerWide + xSpacing; + } + if ( killer[0] ) { // Draw killer's name @@ -205,12 +249,12 @@ void CHudBaseDeathNotice::Paint() x += iPreKillerTextWide; } - // Prekiller icon - if ( iconPrekiller ) + // postkiller icon + if ( iconPostKillerName ) { - int yPreIconTall = y + ( ( iLineTall - iconPreKillerTall ) / 2 ); - iconPrekiller->DrawSelf( x, yPreIconTall, iconPrekillerActualWide, iconPreKillerTall, m_clrIcon ); - x += iconPrekillerWide + xSpacing; + int yPreIconTall = y + ( ( iLineTall - iconPostkillerTall ) / 2 ); + iconPostKillerName->DrawSelf( x, yPreIconTall, iconPostkillerActualWide, iconPostkillerTall, m_clrIcon ); + x += iconPostkillerWide + xSpacing; } // Draw glow behind weapon icon to show it was a crit death @@ -243,6 +287,14 @@ void CHudBaseDeathNotice::Paint() DrawText( x + iVictimTextOffset, yText, m_hTextFont, GetTeamColor( msg.Victim.iTeam, msg.bLocalPlayerInvolved ), victim ); x += iVictimTextWide; + // postkiller icon + if ( iconPostVictimName ) + { + int yPreIconTall = y + ( ( iLineTall - iconPostVictimTall ) / 2 ); + iconPostVictimName->DrawSelf( x, yPreIconTall, iconPostVictimActualWide, iconPostVictimTall, m_clrIcon ); + x += iconPostkillerWide + xSpacing; + } + // Draw Additional Text on the end of the victims name if ( msg.wzInfoTextEnd[0] ) { @@ -569,16 +621,27 @@ void CHudBaseDeathNotice::FireGameEvent( IGameEvent *event ) } } + bool bIsHalloween2014 = TFGameRules() && TFGameRules()->IsHalloweenScenario( CTFGameRules::HALLOWEEN_SCENARIO_DOOMSDAY ); + switch ( iEventType ) { case TF_FLAGEVENT_PICKUP: - pszMsgKey = "#Msg_PickedUpFlag"; + pszMsgKey = bIsHalloween2014 ? "#Msg_PickedUpFlagHalloween2014" : "#Msg_PickedUpFlag"; break; case TF_FLAGEVENT_CAPTURE: - pszMsgKey = "#Msg_CapturedFlag"; + pszMsgKey = bIsHalloween2014 ? "#Msg_CapturedFlagHalloween2014" : "#Msg_CapturedFlag"; break; case TF_FLAGEVENT_DEFEND: - pszMsgKey = bIsMvM ? "#Msg_DefendedBomb" : "#Msg_DefendedFlag"; + if ( bIsMvM ) + { + pszMsgKey = "#Msg_DefendedBomb"; + } + else + { + pszMsgKey = bIsHalloween2014 ? "#Msg_DefendedFlagHalloween2014" : "#Msg_DefendedFlag"; + } + + break; // Add this when we can get localization for it diff --git a/mp/src/game/client/hud_basedeathnotice.h b/mp/src/game/client/hud_basedeathnotice.h index 2a9da0c5..b4f34eb8 100644 --- a/mp/src/game/client/hud_basedeathnotice.h +++ b/mp/src/game/client/hud_basedeathnotice.h @@ -42,8 +42,10 @@ struct DeathNoticeItem iKillerID = -1; iVictimID = -1; - iconPreKiller = NULL; + iconPreKillerName = NULL; + iconPostKillerName = NULL; wzPreKillerText[0] = 0; + iconPostVictimName = NULL; } float GetExpiryTime(); @@ -56,9 +58,13 @@ struct DeathNoticeItem CHudTexture *iconDeath; CHudTexture *iconCritDeath; // crit background icon - CHudTexture *iconPreKiller; + CHudTexture *iconPreKillerName; + + CHudTexture *iconPostKillerName; wchar_t wzPreKillerText[32]; + CHudTexture *iconPostVictimName; + bool bSelfInflicted; bool bLocalPlayerInvolved; bool bCrit; diff --git a/mp/src/game/client/hud_controlpointicons.cpp b/mp/src/game/client/hud_controlpointicons.cpp index cc446c83..2c0628e3 100644 --- a/mp/src/game/client/hud_controlpointicons.cpp +++ b/mp/src/game/client/hud_controlpointicons.cpp @@ -1402,7 +1402,7 @@ void CControlPointProgressBar::PerformLayout( void ) { BaseClass::PerformLayout(); - if ( m_pAttachedToIcon && m_pTeardrop && m_pTeardropSide ) + if ( m_pAttachedToIcon && m_pTeardrop && m_pTeardropSide && m_pAttachedToIcon->GetVPanel() ) { int iIconX, iIconY; ipanel()->GetAbsPos(m_pAttachedToIcon->GetVPanel(), iIconX, iIconY ); diff --git a/mp/src/game/client/hud_vote.cpp b/mp/src/game/client/hud_vote.cpp index 64d3e76e..319255dd 100644 --- a/mp/src/game/client/hud_vote.cpp +++ b/mp/src/game/client/hud_vote.cpp @@ -59,7 +59,7 @@ public: { g_pVGuiLocalize->ConvertANSIToUnicode( pPlayerName, m_wszPlayerName, sizeof(m_wszPlayerName) ); SetLifetime( 7 ); - SetText( "#Vote_notification_text" ); + SetText( "#GameUI_Vote_Notification_Text" ); AddStringToken( "initiator", m_wszPlayerName ); } virtual bool CanBeTriggered() @@ -68,7 +68,10 @@ public: } virtual void Trigger() { - CTFGenericConfirmDialog *pDialog = ShowConfirmDialog( "#Vote_notification_title", "#Vote_notification_text", "#Vote_notification_view", "#cancel", &ConfirmShowVoteSetup ); + CTFGenericConfirmDialog *pDialog = ShowConfirmDialog( "#GameUI_Vote_Notification_Title", + "#GameUI_Vote_Notification_Text", + "#GameUI_Vote_Notification_View", + "#cancel", &ConfirmShowVoteSetup ); pDialog->SetContext( this ); pDialog->AddStringToken( "initiator", m_wszPlayerName ); // so we aren't deleted @@ -95,7 +98,7 @@ public: CHudVote *pHudVote = GET_HUDELEMENT( CHudVote ); if ( pHudVote ) { - pHudVote->ShowVoteUI(); + pHudVote->ShowVoteUI( true ); } } pNotification->SetIsInUse( false ); @@ -291,6 +294,76 @@ void CVoteSetupDialog::ApplySettings(KeyValues *inResourceData) } //----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CVoteSetupDialog::InitializeIssueList( void ) +{ + m_pComboBox->RemoveAll(); + m_pComboBox->SetVisible( false ); + SetDialogVariable( "combo_label", "" ); + + for ( int index = 0; index < m_VoteIssues.Count(); index++ ) + { + if ( !m_VoteIssues[index].szName || !m_VoteIssues[index].szName[0] ) + continue; + + bool bActive = m_VoteIssues[index].bIsActive; + + char szIssueLocalized[k_MAX_VOTE_NAME_LENGTH] = { 0 }; + g_pVGuiLocalize->ConvertUnicodeToANSI( g_pVGuiLocalize->Find( m_VoteIssues[index].szNameString ), szIssueLocalized, sizeof( szIssueLocalized ) ); + + if ( !bActive ) + { + char szDisabled[k_MAX_VOTE_NAME_LENGTH] = { 0 }; + g_pVGuiLocalize->ConvertUnicodeToANSI( g_pVGuiLocalize->Find( "#GameUI_Vote_Disabled" ), szDisabled, sizeof( szDisabled ) ); + V_strcat_safe( szIssueLocalized, szDisabled ); + } + + KeyValues *pKeyValues = new KeyValues( "Issue" ); + pKeyValues->SetString( "Issue", szIssueLocalized ); + pKeyValues->SetString( "IssueRaw", m_VoteIssues[index].szName ); + pKeyValues->SetBool( "Active", m_VoteIssues[index].bIsActive ); + int iId = m_pVoteSetupList->AddItem( 0, pKeyValues ); + pKeyValues->deleteThis(); + + // Setup the list entry style + if ( m_hIssueFont != INVALID_FONT ) + { + m_pVoteSetupList->SetItemFont( iId, m_hIssueFont ); + Color colFG = bActive ? m_IssueFGColor : m_IssueFGColorDisabled; + m_pVoteSetupList->SetItemFgColor( iId, colFG ); + } + } + + // Select the first item by default + if ( m_pVoteSetupList->GetItemCount() > 0 ) + { + m_pVoteSetupList->SetSelectedItem( 0 ); + } + else + { + // No active issues + char szIssueLocalized[k_MAX_VOTE_NAME_LENGTH] = { 0 }; + g_pVGuiLocalize->ConvertUnicodeToANSI( g_pVGuiLocalize->Find( "#GameUI_Vote_System_Disabled" ), szIssueLocalized, sizeof( szIssueLocalized ) ); + + KeyValues *pKeyValues = new KeyValues( "Issue" ); + pKeyValues->SetString( "Issue", szIssueLocalized ); + pKeyValues->SetString( "IssueRaw", "Disabled" ); + pKeyValues->SetBool( "Active", false ); + int iId = m_pVoteSetupList->AddItem( 0, pKeyValues ); + pKeyValues->deleteThis(); + + if ( m_hIssueFont != INVALID_FONT ) + { + m_pVoteSetupList->SetItemFont( iId, m_hIssueFont ); + m_pVoteSetupList->SetItemFgColor( iId, m_IssueFGColor ); + } + } + + UpdateCurrentMap(); +} + +//----------------------------------------------------------------------------- // Purpose: Keep track of the current map //----------------------------------------------------------------------------- void CVoteSetupDialog::UpdateCurrentMap( void ) @@ -302,7 +375,7 @@ void CVoteSetupDialog::UpdateCurrentMap( void ) //----------------------------------------------------------------------------- // Purpose: Feeds Issues from the server to this Dialog //----------------------------------------------------------------------------- -void CVoteSetupDialog::AddVoteIssues( CUtlStringList &m_VoteSetupIssues ) +void CVoteSetupDialog::AddVoteIssues( CUtlVector< VoteIssue_t > &m_VoteSetupIssues ) { m_VoteIssues.RemoveAll(); for ( int index = 0; index < m_VoteSetupIssues.Count(); index++ ) @@ -385,36 +458,7 @@ void CVoteSetupDialog::Activate() m_pVoteParameterList->SetSectionFgColor( 1, m_HeaderFGColor ); } - // Populate the Issue list - for ( int index = 0; index < m_VoteIssues.Count(); index++ ) - { - const char *pszIssue = m_VoteIssues[index]; - if ( !pszIssue || !pszIssue[0] ) - continue; - - KeyValues *pKeyValues = new KeyValues( "Issue" ); - pKeyValues->SetString( "Issue", pszIssue ); - int iId = m_pVoteSetupList->AddItem( 0, pKeyValues ); - pKeyValues->deleteThis(); - - // Setup the list entry style - if ( m_hIssueFont != INVALID_FONT ) - { - m_pVoteSetupList->SetItemFont( iId, m_hIssueFont ); - - bool bDisabled = V_stristr( pszIssue, "(Disabled on Server)" ); // driller: need to localize - Color colFG = bDisabled ? m_IssueFGColorDisabled : m_IssueFGColor; - m_pVoteSetupList->SetItemFgColor( iId, colFG ); - } - } - - // Select the first item by default - if ( m_pVoteSetupList->GetItemCount() > 0 ) - { - m_pVoteSetupList->SetSelectedItem( 0 ); - } - - UpdateCurrentMap(); + InitializeIssueList(); } //----------------------------------------------------------------------------- @@ -432,15 +476,15 @@ void CVoteSetupDialog::OnClose() void CVoteSetupDialog::OnCommand(const char *command) { // We should have enough data to issue a CallVote command - if ( V_stricmp( command, "CallVote" ) == 0 ) + if ( !V_stricmp( command, "CallVote" ) ) { int iSelectedItem = m_pVoteSetupList->GetSelectedItem(); if ( iSelectedItem >= 0 ) { - char szVoteCommand[128]; + char szVoteCommand[k_MAX_VOTE_NAME_LENGTH]; KeyValues *pIssueKeyValues = m_pVoteSetupList->GetItemData( iSelectedItem ); - const char *szIssue = pIssueKeyValues->GetString( "Issue" ); - if ( V_stricmp( "changelevel", szIssue ) == 0 || V_stricmp( "nextlevel", szIssue ) == 0 ) + const char *szIssueRaw = pIssueKeyValues->GetString( "IssueRaw" ); + if ( !V_stricmp( "ChangeLevel", szIssueRaw ) || !V_stricmp( "NextLevel", szIssueRaw ) ) { int nSelectedParam = m_pVoteParameterList->GetSelectedItem(); if ( nSelectedParam >= 0 ) @@ -454,13 +498,13 @@ void CVoteSetupDialog::OnCommand(const char *command) { // Which Map? const char *szMapName = pParameterKeyValues->GetString( "Name" ); - Q_snprintf( szVoteCommand, sizeof( szVoteCommand ), "callvote %s %s\n;", szIssue, szMapName ); + Q_snprintf( szVoteCommand, sizeof( szVoteCommand ), "callvote %s %s\n;", szIssueRaw, szMapName ); engine->ClientCmd( szVoteCommand ); } } } } - else if ( V_stricmp( "kick", szIssue ) == 0 ) + else if ( !V_stricmp( "Kick", szIssueRaw ) ) { // Get selected Player int iSelectedParam = m_pVoteParameterList->GetSelectedItem(); @@ -476,7 +520,7 @@ void CVoteSetupDialog::OnCommand(const char *command) if ( engine->GetPlayerInfo( playerIndex, &playerInfo ) ) { CBasePlayer *pPlayer = UTIL_PlayerByIndex( playerIndex ); - Q_snprintf( szVoteCommand, sizeof( szVoteCommand ), "callvote %s \"%d %s\"\n;", szIssue, pPlayer->GetUserID(), pReasonString ); + Q_snprintf( szVoteCommand, sizeof( szVoteCommand ), "callvote %s \"%d %s\"\n;", szIssueRaw, pPlayer->GetUserID(), pReasonString ); engine->ClientCmd( szVoteCommand ); #ifdef TF_CLIENT_DLL CSteamID steamID; @@ -495,7 +539,7 @@ void CVoteSetupDialog::OnCommand(const char *command) } } #ifdef TF_CLIENT_DLL - else if ( V_stricmp( "ChangeMission", szIssue ) == 0 ) + else if ( !V_stricmp( "ChangeMission", szIssueRaw ) ) { int nSelectedParam = m_pVoteParameterList->GetSelectedItem(); if ( nSelectedParam >= 0 ) @@ -509,7 +553,7 @@ void CVoteSetupDialog::OnCommand(const char *command) { // Which Pop File? const char *szPopFile = pParameterKeyValues->GetString( "Name" ); - Q_snprintf( szVoteCommand, sizeof( szVoteCommand ), "callvote %s %s\n;", szIssue, szPopFile ); + Q_snprintf( szVoteCommand, sizeof( szVoteCommand ), "callvote %s %s\n;", szIssueRaw, szPopFile ); engine->ClientCmd( szVoteCommand ); } } @@ -519,7 +563,7 @@ void CVoteSetupDialog::OnCommand(const char *command) else { // Non-parameter vote. i.e. callvote scrambleteams - Q_snprintf( szVoteCommand, sizeof(szVoteCommand), "callvote %s\n;", szIssue ); + Q_snprintf( szVoteCommand, sizeof(szVoteCommand), "callvote %s\n;", szIssueRaw ); engine->ClientCmd( szVoteCommand ); } @@ -551,22 +595,23 @@ void CVoteSetupDialog::OnItemSelected( vgui::Panel *panel ) if ( !pIssueKeyValues ) return; + CHudVote *pHudVote = GET_HUDELEMENT( CHudVote ); + if ( !pHudVote ) + return; + // We're rebuilding, so clear state m_bVoteButtonEnabled = false; m_pVoteParameterList->ClearSelection(); m_pVoteParameterList->RemoveAll(); - const char *szName = pIssueKeyValues->GetString( "Issue" ); - if ( V_stricmp( "Voting disabled on this Server", szName ) == 0 ) - { - m_bVoteButtonEnabled = false; - } - else if ( V_stristr( szName, "(Disabled on Server)" ) ) // driller: need to localize + const char *pszIssueRaw = pIssueKeyValues->GetString( "IssueRaw" ); + bool bActive = pIssueKeyValues->GetBool( "Active" ); + if ( !pHudVote->IsVoteSystemActive() || !bActive ) { m_bVoteButtonEnabled = false; } // CHANGELEVEL / NEXTLEVEL - else if ( V_stricmp( "changelevel", szName ) == 0 || V_stricmp( "nextlevel", szName ) == 0 ) + else if ( !V_stricmp( "ChangeLevel", pszIssueRaw ) || !V_stricmp( "NextLevel", pszIssueRaw ) ) { // Feed the mapcycle to the parameters list for ( int index = 0; index < m_VoteIssuesMapCycle.Count(); index++ ) @@ -598,7 +643,7 @@ void CVoteSetupDialog::OnItemSelected( vgui::Panel *panel ) } } // KICK - else if ( V_stricmp( "kick", szName ) == 0 ) + else if ( !V_stricmp( "Kick", pszIssueRaw ) ) { // Feed the player list to the parameters list int nMaxClients = engine->GetMaxClients(); @@ -656,7 +701,7 @@ void CVoteSetupDialog::OnItemSelected( vgui::Panel *panel ) } #ifdef TF_CLIENT_DLL // CHANGE POP FILE - else if ( V_stricmp( "ChangeMission", szName ) == 0 ) + else if ( !V_stricmp( "ChangeMission", pszIssueRaw ) ) { // Feed the popfiles to the parameters list for ( int index = 0; index < m_VoteIssuesPopFiles.Count(); index++ ) @@ -742,8 +787,8 @@ void CVoteSetupDialog::RefreshIssueParameters() if ( iSelectedItem >= 0 ) { KeyValues *pIssueKeyValues = m_pVoteSetupList->GetItemData( iSelectedItem ); - const char *szName = pIssueKeyValues->GetString( "Issue" ); - if ( V_stricmp( "kick", szName ) == 0 ) + const char *pszIssueRaw = pIssueKeyValues->GetString( "IssueRaw" ); + if ( !V_stricmp( "Kick", pszIssueRaw ) ) { if ( m_pVoteParameterList->GetItemCount() > 0 ) { @@ -786,10 +831,10 @@ void CVoteSetupDialog::RefreshIssueParameters() m_pVoteParameterList->InvalidateItem( index ); } - - m_pVoteParameterList->SetImageList( m_pImageList, false ); } } + + m_pVoteParameterList->SetImageList( m_pImageList, false ); } } @@ -799,9 +844,9 @@ void CVoteSetupDialog::RefreshIssueParameters() void CVoteSetupDialog::ResetData() { m_bVoteButtonEnabled = false; - m_pVoteSetupList->DeleteAllItems(); - m_pVoteParameterList->DeleteAllItems(); - m_pComboBox->DeleteAllItems(); + m_pVoteSetupList->RemoveAll(); + m_pVoteParameterList->RemoveAll(); + m_pComboBox->RemoveAll(); } //----------------------------------------------------------------------------- @@ -863,7 +908,7 @@ void CHudVote::Init( void ) ListenForGameEvent( "vote_options" ); ListenForGameEvent( "vote_cast" ); - SetVoteActive( false ); + m_bVotingActive = false; m_flVoteResultCycleTime = -1; m_flHideTime = -1; m_bIsYesNoVote = true; @@ -871,6 +916,8 @@ void CHudVote::Init( void ) m_nVoteChoicesCount = 2; // Yes/No is the default m_bShowVoteActivePanel = false; m_iVoteCallerIdx = -1; + m_bVoteSystemActive = false; + m_nVoteTeamIndex = 0; HOOK_HUD_MESSAGE( CHudVote, CallVoteFailed ); HOOK_HUD_MESSAGE( CHudVote, VoteStart ); @@ -884,7 +931,7 @@ void CHudVote::Init( void ) //----------------------------------------------------------------------------- void CHudVote::LevelInit( void ) { - SetVoteActive( false ); + m_bVotingActive = false; m_flVoteResultCycleTime = -1; m_flHideTime = -1; m_flPostVotedHideTime = -1; @@ -901,7 +948,7 @@ int CHudVote::KeyInput( int down, ButtonCode_t keynum, const char *pszCurrentBin if ( !down ) return 1; - if ( !m_bVoteActive ) + if ( !m_bVotingActive ) return 1; if ( m_bPlayerVoted ) @@ -979,21 +1026,19 @@ void CHudVote::MsgFunc_CallVoteFailed( bf_read &msg ) m_pCallVoteFailed->SetVisible( true ); m_pVoteSetupDialog->SetVisible( false ); - m_flHideTime = gpGlobals->curtime + 4.0; + m_flHideTime = gpGlobals->curtime + 4.f; - char szTime[256]; - wchar_t wszTime[256]; + char szTime[k_MAX_VOTE_NAME_LENGTH]; + wchar_t wszTime[k_MAX_VOTE_NAME_LENGTH]; bool bMinutes = ( nTime > 65 ); if ( bMinutes ) { nTime /= 60; } - const char *pszTimeString = ( bMinutes ) ? ( ( nTime < 2 ) ? "#GameUI_vote_failed_recently_min" : "#GameUI_vote_failed_recently_mins" ) : "#GameUI_vote_failed_recently"; Q_snprintf( szTime, sizeof ( szTime), "%i", nTime ); g_pVGuiLocalize->ConvertANSIToUnicode( szTime, wszTime, sizeof( wszTime ) ); - wchar_t wszHeaderString[512]; - wchar_t *pwszHeaderString; + wchar_t wszHeaderString[k_MAX_VOTE_NAME_LENGTH]; switch( nReason ) { @@ -1006,10 +1051,12 @@ void CHudVote::MsgFunc_CallVoteFailed( bf_read &msg ) break; case VOTE_FAILED_RATE_EXCEEDED: - g_pVGuiLocalize->ConstructString( wszHeaderString, sizeof(wszHeaderString), g_pVGuiLocalize->Find( "#GameUI_vote_failed_vote_spam" ), 1, wszTime ); - pwszHeaderString = wszHeaderString; - m_pCallVoteFailed->SetDialogVariable( "FailedReason", pwszHeaderString ); + { + const char *pszTimeString = ( bMinutes ) ? ( ( nTime < 2 ) ? "#GameUI_vote_failed_vote_spam_min" : "#GameUI_vote_failed_vote_spam_mins" ) : "#GameUI_vote_failed_vote_spam"; + g_pVGuiLocalize->ConstructString( wszHeaderString, sizeof( wszHeaderString ), g_pVGuiLocalize->Find( pszTimeString ), 1, wszTime ); + m_pCallVoteFailed->SetDialogVariable( "FailedReason", wszHeaderString ); break; + } case VOTE_FAILED_ISSUE_DISABLED: m_pCallVoteFailed->SetControlString( "FailedReason", "#GameUI_vote_failed_disabled_issue" ); @@ -1028,10 +1075,12 @@ void CHudVote::MsgFunc_CallVoteFailed( bf_read &msg ) break; case VOTE_FAILED_ON_COOLDOWN: + { + const char *pszTimeString = ( bMinutes ) ? ( ( nTime < 2 ) ? "#GameUI_vote_failed_recently_min" : "#GameUI_vote_failed_recently_mins" ) : "#GameUI_vote_failed_recently"; g_pVGuiLocalize->ConstructString( wszHeaderString, sizeof( wszHeaderString ), g_pVGuiLocalize->Find( pszTimeString ), 1, wszTime ); - pwszHeaderString = wszHeaderString; - m_pCallVoteFailed->SetDialogVariable( "FailedReason", pwszHeaderString ); + m_pCallVoteFailed->SetDialogVariable( "FailedReason", wszHeaderString ); break; + } case VOTE_FAILED_TEAM_CANT_CALL: m_pCallVoteFailed->SetControlString( "FailedReason", "#GameUI_vote_failed_team_cant_call" ); @@ -1058,10 +1107,12 @@ void CHudVote::MsgFunc_CallVoteFailed( bf_read &msg ) break; case VOTE_FAILED_CANNOT_KICK_FOR_TIME: - g_pVGuiLocalize->ConstructString( wszHeaderString, sizeof(wszHeaderString), g_pVGuiLocalize->Find( "#GameUI_vote_failed_cannot_kick_for_time" ), 1, wszTime ); - pwszHeaderString = wszHeaderString; - m_pCallVoteFailed->SetDialogVariable( "FailedReason", pwszHeaderString ); + { + const char *pszTimeString = ( bMinutes ) ? ( ( nTime < 2 ) ? "#GameUI_vote_failed_cannot_kick_min" : "#GameUI_vote_failed_cannot_kick_mins" ) : "#GameUI_vote_failed_cannot_kick"; + g_pVGuiLocalize->ConstructString( wszHeaderString, sizeof( wszHeaderString ), g_pVGuiLocalize->Find( pszTimeString ), 1, wszTime ); + m_pCallVoteFailed->SetDialogVariable( "FailedReason", wszHeaderString ); break; + } case VOTE_FAILED_CANNOT_KICK_DURING_ROUND: m_pCallVoteFailed->SetControlString( "FailedReason", "#GameUI_vote_failed_round_active" ); @@ -1070,6 +1121,14 @@ void CHudVote::MsgFunc_CallVoteFailed( bf_read &msg ) case VOTE_FAILED_MODIFICATION_ALREADY_ACTIVE: m_pCallVoteFailed->SetControlString( "FailedReason", "#GameUI_vote_failed_event_already_active" ); break; + + case VOTE_FAILED_VOTE_IN_PROGRESS: + m_pCallVoteFailed->SetControlString( "FailedReason", "#GameUI_vote_failed_vote_in_progress" ); + break; + + case VOTE_FAILED_KICK_LIMIT_REACHED: + m_pCallVoteFailed->SetControlString( "FailedReason", "#GameUI_vote_failed_kick_limit" ); + break; } } @@ -1081,14 +1140,14 @@ void CHudVote::MsgFunc_VoteFailed( bf_read &msg ) if ( IsPlayingDemo() ) return; - int iTeam = msg.ReadByte(); + m_nVoteTeamIndex = msg.ReadByte(); vote_create_failed_t nReason = (vote_create_failed_t)msg.ReadByte(); // Visibility of this error is handled by OnThink() - SetVoteActive( false ); + m_bVotingActive = false; m_bVotePassed = false; - m_flVoteResultCycleTime = gpGlobals->curtime + 2; - m_flHideTime = gpGlobals->curtime + 5; + m_flVoteResultCycleTime = gpGlobals->curtime + 2.f; + m_flHideTime = gpGlobals->curtime + 5.f; switch ( nReason ) { @@ -1105,11 +1164,10 @@ void CHudVote::MsgFunc_VoteFailed( bf_read &msg ) break; } - // driller: this event has no listeners - will eventually hook into stats IGameEvent *event = gameeventmanager->CreateEvent( "vote_failed" ); if ( event ) { - event->SetInt( "team", iTeam ); + event->SetInt( "team", m_nVoteTeamIndex ); gameeventmanager->FireEventClientSide( event ); } @@ -1117,7 +1175,11 @@ void CHudVote::MsgFunc_VoteFailed( bf_read &msg ) if ( !pLocalPlayer ) return; - pLocalPlayer->EmitSound("Vote.Failed"); + bool bShowToPlayer = ( !m_nVoteTeamIndex || pLocalPlayer->GetTeamNumber() == m_nVoteTeamIndex ); + if ( bShowToPlayer ) + { + pLocalPlayer->EmitSound("Vote.Failed"); + } } //----------------------------------------------------------------------------- @@ -1133,9 +1195,8 @@ void CHudVote::MsgFunc_VoteStart( bf_read &msg ) return; // Is this a team-only vote? - int iTeam = msg.ReadByte(); - uint8 invalidTeam = (uint8)TEAM_INVALID; - if ( iTeam != invalidTeam && iTeam != pLocalPlayer->GetTeamNumber() ) + m_nVoteTeamIndex = msg.ReadByte(); + if ( m_nVoteTeamIndex >= FIRST_GAME_TEAM && m_nVoteTeamIndex != pLocalPlayer->GetTeamNumber() ) return; // Entity calling the vote @@ -1163,18 +1224,18 @@ void CHudVote::MsgFunc_VoteStart( bf_read &msg ) } // DisplayString - char szIssue[256]; + char szIssue[k_MAX_VOTE_NAME_LENGTH]; szIssue[0] = 0; msg.ReadString( szIssue, sizeof(szIssue) ); // DetailString - char szParam1[256]; + char szParam1[k_MAX_VOTE_NAME_LENGTH]; szParam1[0] = 0; msg.ReadString( szParam1, sizeof(szParam1) ); m_bIsYesNoVote = msg.ReadByte(); - SetVoteActive( true ); + m_bVotingActive = true; m_pVoteFailed->SetVisible( false ); m_pVotePassed->SetVisible( false ); m_pCallVoteFailed->SetVisible( false ); @@ -1204,25 +1265,23 @@ void CHudVote::MsgFunc_VoteStart( bf_read &msg ) // Display vote caller's name wchar_t wszCallerName[MAX_PLAYER_NAME_LENGTH]; - wchar_t wszHeaderString[512]; - wchar_t *pwszHeaderString; + wchar_t wszHeaderString[k_MAX_VOTE_NAME_LENGTH]; // Player g_pVGuiLocalize->ConvertANSIToUnicode( pszCallerName, wszCallerName, sizeof( wszCallerName ) ); // String - g_pVGuiLocalize->ConstructString( wszHeaderString, sizeof(wszHeaderString), g_pVGuiLocalize->Find( "#GameUI_vote_header" ), 1, wszCallerName ); - pwszHeaderString = wszHeaderString; + g_pVGuiLocalize->ConstructString( wszHeaderString, sizeof( wszHeaderString ), g_pVGuiLocalize->Find( "#GameUI_vote_header" ), 1, wszCallerName ); // Final - m_pVoteActive->SetDialogVariable( "header", pwszHeaderString ); + m_pVoteActive->SetDialogVariable( "header", wszHeaderString ); // Display the Issue wchar_t *pwcParam; - wchar_t wcParam[128]; + wchar_t wcParam[k_MAX_VOTE_NAME_LENGTH]; wchar_t *pwcIssue; - wchar_t wcIssue[512]; + wchar_t wcIssue[k_MAX_VOTE_NAME_LENGTH]; if ( Q_strlen( szParam1 ) > 0 ) { @@ -1252,7 +1311,7 @@ void CHudVote::MsgFunc_VoteStart( bf_read &msg ) if ( m_bIsYesNoVote ) { // YES / NO UI - wchar_t wzFinal[512] = L""; + wchar_t wzFinal[k_MAX_VOTE_NAME_LENGTH] = L""; wchar_t *pszText = g_pVGuiLocalize->Find( "#GameUI_vote_yes_pc_instruction" ); if ( pszText ) { @@ -1294,7 +1353,7 @@ void CHudVote::MsgFunc_VoteStart( bf_read &msg ) // Construct Option name const char *pszChoiceName = m_VoteSetupChoices[iIndex]; - char szOptionName[256]; + char szOptionName[k_MAX_VOTE_NAME_LENGTH]; Q_snprintf( szOptionName, sizeof( szOptionName ), "F%i. ", iIndex + 1 ); Q_strncat( szOptionName, pszChoiceName, sizeof( szOptionName ), COPY_ALL_CHARACTERS ); @@ -1320,7 +1379,7 @@ void CHudVote::MsgFunc_VoteStart( bf_read &msg ) { event->SetString( "issue", szIssue ); event->SetString( "param1", szParam1 ); - event->SetInt( "team", iTeam ); + event->SetInt( "team", m_nVoteTeamIndex ); event->SetInt( "initiator", m_iVoteCallerIdx ); gameeventmanager->FireEventClientSide( event ); } @@ -1332,10 +1391,10 @@ void CHudVote::MsgFunc_VoteStart( bf_read &msg ) } else { - ShowVoteUI(); + m_bShowVoteActivePanel = true; } #else - ShowVoteUI(); + m_bShowVoteActivePanel = true; #endif // TF_CLIENT_DLL } @@ -1347,24 +1406,24 @@ void CHudVote::MsgFunc_VotePass( bf_read &msg ) if ( IsPlayingDemo() ) return; - int iTeam = msg.ReadByte(); + m_nVoteTeamIndex = msg.ReadByte(); // Passed string - char szResult[256]; + char szResult[k_MAX_VOTE_NAME_LENGTH]; szResult[0] = 0; msg.ReadString( szResult, sizeof(szResult) ); // Detail string - char szParam1[256]; + char szParam1[k_MAX_VOTE_NAME_LENGTH]; szParam1[0] = 0; msg.ReadString( szParam1, sizeof(szParam1) ); // Localize wchar_t *pwcParam; - wchar_t wcParam[128]; + wchar_t wcParam[k_MAX_VOTE_NAME_LENGTH]; wchar_t *pwcIssue; - wchar_t wcIssue[512]; + wchar_t wcIssue[k_MAX_VOTE_NAME_LENGTH]; if ( Q_strlen( szParam1 ) > 0 ) { @@ -1390,10 +1449,10 @@ void CHudVote::MsgFunc_VotePass( bf_read &msg ) m_pVotePassed->SetDialogVariable( "passedresult", pwcIssue ); - SetVoteActive( false ); + m_bVotingActive = false; m_bVotePassed = true; - m_flVoteResultCycleTime = gpGlobals->curtime + 2; - m_flHideTime = gpGlobals->curtime + 5; + m_flVoteResultCycleTime = gpGlobals->curtime + 2.f; + m_flHideTime = gpGlobals->curtime + 5.f; // driller: this event has no listeners - will eventually hook into stats IGameEvent *event = gameeventmanager->CreateEvent( "vote_passed" ); @@ -1401,7 +1460,7 @@ void CHudVote::MsgFunc_VotePass( bf_read &msg ) { event->SetString( "details", szResult ); event->SetString( "param1", szParam1 ); - event->SetInt( "team", iTeam ); + event->SetInt( "team", m_nVoteTeamIndex ); gameeventmanager->FireEventClientSide( event ); } @@ -1434,21 +1493,45 @@ void CHudVote::MsgFunc_VoteSetup( bf_read &msg ) int nIssueCount = msg.ReadByte(); if ( nIssueCount ) { - for ( int index = 0; index < nIssueCount; index++ ) + for ( int i = 0; i < nIssueCount; i++ ) { - char szIssue[256]; - msg.ReadString( szIssue, sizeof(szIssue) ); - if ( !m_VoteSetupIssues.HasElement( szIssue ) ) + char szIssue[k_MAX_VOTE_NAME_LENGTH]; + char szIssueString[k_MAX_VOTE_NAME_LENGTH]; + msg.ReadString( szIssue, sizeof( szIssue ) ); + msg.ReadString( szIssueString, sizeof( szIssueString ) ); + bool bIsActive = (bool)msg.ReadByte(); + + m_bVoteSystemActive |= bIsActive; + + bool bAdd = true; + FOR_EACH_VEC( m_VoteSetupIssues, j ) + { + if ( !V_strcmp( szIssue, m_VoteSetupIssues[j].szName ) ) + { + bAdd = false; + break; + } + } + + if ( bAdd ) { + // When empty, assume that we just pre-pend #Vote_ to szIssue (reduces msg size) + if ( !szIssueString[0] ) + { + V_sprintf_safe( szIssueString, "#Vote_%s", szIssue ); + } + + VoteIssue_t issue; + V_strcpy_safe( issue.szName, szIssue ); + V_strcpy_safe( issue.szNameString, szIssueString ); + issue.bIsActive = bIsActive; + // Send it over to the listpanel - m_VoteSetupIssues.CopyAndAddToTail( szIssue ); + m_VoteSetupIssues.AddToTail( issue ); } } } - else - { - m_VoteSetupIssues.CopyAndAddToTail( "Voting disabled on this Server" ); - } + m_pVoteSetupDialog->AddVoteIssues( m_VoteSetupIssues ); // Load up the list of Vote Issue Parameters @@ -1638,50 +1721,51 @@ void CHudVote::FireGameEvent( IGameEvent *event ) //----------------------------------------------------------------------------- void CHudVote::OnThink() { - // We delay hiding the menu after we cast a vote - if ( m_bPlayerVoted && m_flPostVotedHideTime > 0 && m_flPostVotedHideTime < gpGlobals->curtime ) - { - m_pVoteActive->SetVisible( false ); - m_bShowVoteActivePanel = false; - m_flPostVotedHideTime = -1; - } - - if ( m_flVoteResultCycleTime > 0 && m_flVoteResultCycleTime < gpGlobals->curtime ) + C_BasePlayer *pLocalPlayer = C_BasePlayer::GetLocalPlayer(); + if ( pLocalPlayer ) { - m_pVoteActive->SetVisible( false ); - m_pVoteFailed->SetVisible( !m_bVotePassed ); - m_pVotePassed->SetVisible( m_bVotePassed ); - g_pClientMode->GetViewportAnimationController()->StartAnimationSequence( m_pVoteActive, "HideVoteBackgrounds" ); - - m_flVoteResultCycleTime = -1; - m_bPlayerVoted = false; - m_bVoteActive = false; - m_bShowVoteActivePanel = false; - m_iVoteCallerIdx = -1; - } + bool bShowToPlayer = ( !m_nVoteTeamIndex || pLocalPlayer->GetTeamNumber() == m_nVoteTeamIndex ); - if ( m_bVoteActive ) - { - // driller: Need to rewrite this to handle all vote types (Yes/No and General) - if ( m_bIsYesNoVote && m_pVoteActive ) + // We delay hiding the menu after we cast a vote + if ( m_bPlayerVoted && m_flPostVotedHideTime > 0 && gpGlobals->curtime > m_flPostVotedHideTime ) { - char szYesCount[512] = ""; - Q_snprintf( szYesCount, 512, "%d", m_nVoteOptionCount[0] ); - - char szNoCount[512] = ""; - Q_snprintf( szNoCount, 512, "%d", m_nVoteOptionCount[1] ); + m_pVoteActive->SetVisible( false ); + m_bShowVoteActivePanel = false; + m_flPostVotedHideTime = -1; + } - m_pVoteActive->SetControlString( "Option1CountLabel", szYesCount ); - m_pVoteActive->SetControlString( "Option2CountLabel", szNoCount ); + if ( m_flVoteResultCycleTime > 0 && gpGlobals->curtime > m_flVoteResultCycleTime ) + { + m_pVoteActive->SetVisible( false ); + m_pVoteFailed->SetVisible( !m_bVotePassed && bShowToPlayer ); + m_pVotePassed->SetVisible( m_bVotePassed && bShowToPlayer ); + g_pClientMode->GetViewportAnimationController()->StartAnimationSequence( m_pVoteActive, "HideVoteBackgrounds" ); + + m_flVoteResultCycleTime = -1; + m_bPlayerVoted = false; + m_bVotingActive = false; + m_bShowVoteActivePanel = false; + m_iVoteCallerIdx = -1; } - if ( !m_pVoteActive->IsVisible() && m_bShowVoteActivePanel ) + if ( m_bVotingActive && m_bShowVoteActivePanel ) { - m_pVoteActive->SetVisible( true ); + // driller: Need to rewrite this to handle all vote types (Yes/No and General) + if ( m_bIsYesNoVote && m_pVoteActive ) + { + char szYesCount[k_MAX_VOTE_NAME_LENGTH] = ""; + Q_snprintf( szYesCount, sizeof( szYesCount ), "%d", m_nVoteOptionCount[0] ); - C_BasePlayer *pLocalPlayer = C_BasePlayer::GetLocalPlayer(); - if ( pLocalPlayer ) + char szNoCount[k_MAX_VOTE_NAME_LENGTH] = ""; + Q_snprintf( szNoCount, sizeof( szNoCount ), "%d", m_nVoteOptionCount[1] ); + + m_pVoteActive->SetControlString( "Option1CountLabel", szYesCount ); + m_pVoteActive->SetControlString( "Option2CountLabel", szNoCount ); + } + + if ( !m_pVoteActive->IsVisible() && bShowToPlayer ) { + m_pVoteActive->SetVisible( true ); pLocalPlayer->EmitSound("Vote.Created"); } } @@ -1695,7 +1779,7 @@ void CHudVote::OnThink() //----------------------------------------------------------------------------- bool CHudVote::ShouldDraw( void ) { - return ( m_bVoteActive || m_flHideTime > gpGlobals->curtime ); + return ( m_bVotingActive || gpGlobals->curtime < m_flHideTime ); } //----------------------------------------------------------------------------- @@ -1709,22 +1793,6 @@ bool CHudVote::IsPlayingDemo() const //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- -void CHudVote::SetVoteActive( bool bActive ) -{ - m_bVoteActive = bActive; -} - -//----------------------------------------------------------------------------- -// Purpose: -//----------------------------------------------------------------------------- -void CHudVote::ShowVoteUI( void ) -{ - m_bShowVoteActivePanel = true; -} - -//----------------------------------------------------------------------------- -// Purpose: -//----------------------------------------------------------------------------- bool CHudVote::IsVoteUIActive( void ) { return m_bShowVoteActivePanel; diff --git a/mp/src/game/client/hud_vote.h b/mp/src/game/client/hud_vote.h index 91ba1e9b..38956366 100644 --- a/mp/src/game/client/hud_vote.h +++ b/mp/src/game/client/hud_vote.h @@ -25,6 +25,8 @@ extern INetworkStringTable *g_pStringTableServerPopFiles; extern INetworkStringTable *g_pStringTableServerMapCycleMvM; #endif +static const int k_MAX_VOTE_NAME_LENGTH = 256; + namespace vgui { class SectionedListPanel; @@ -32,6 +34,13 @@ namespace vgui class ImageList; }; +struct VoteIssue_t +{ + char szName[k_MAX_VOTE_NAME_LENGTH]; + char szNameString[k_MAX_VOTE_NAME_LENGTH]; + bool bIsActive; +}; + class VoteBarPanel : public vgui::Panel, public CGameEventListener { DECLARE_CLASS_SIMPLE( VoteBarPanel, vgui::Panel ); @@ -69,8 +78,9 @@ public: virtual void PostApplySchemeSettings( vgui::IScheme *pScheme ); virtual void ApplySettings(KeyValues *inResourceData); + void InitializeIssueList( void ); void UpdateCurrentMap( void ); - void AddVoteIssues( CUtlStringList &m_VoteSetupIssues ); + void AddVoteIssues( CUtlVector< VoteIssue_t > &m_VoteSetupIssues ); void AddVoteIssueParams_MapCycle( CUtlStringList &m_VoteSetupMapCycle ); #ifdef TF_CLIENT_DLL @@ -94,7 +104,7 @@ private: vgui::Button *m_pCallVoteButton; vgui::ImageList *m_pImageList; - CUtlVector<const char*> m_VoteIssues; + CUtlVector< VoteIssue_t > m_VoteIssues; CUtlVector<const char*> m_VoteIssuesMapCycle; #ifdef TF_CLIENT_DLL @@ -137,12 +147,12 @@ class CHudVote : public vgui::EditablePanel, public CHudElement void MsgFunc_VoteSetup( bf_read &msg ); void PropagateOptionParameters( void ); - void ShowVoteUI( void ); + void ShowVoteUI( bool bShow ) { m_bShowVoteActivePanel = bShow; } bool IsVoteUIActive( void ); + bool IsVoteSystemActive( void ) { return m_bVoteSystemActive; } private: bool IsPlayingDemo() const; - void SetVoteActive( bool bActive ); EditablePanel *m_pVoteActive; VoteBarPanel *m_voteBar; @@ -151,7 +161,7 @@ private: EditablePanel *m_pCallVoteFailed; CVoteSetupDialog *m_pVoteSetupDialog; - CUtlStringList m_VoteSetupIssues; + CUtlVector< VoteIssue_t > m_VoteSetupIssues; CUtlStringList m_VoteSetupMapCycle; #ifdef TF_CLIENT_DLL @@ -160,7 +170,8 @@ private: CUtlStringList m_VoteSetupChoices; - bool m_bVoteActive; + bool m_bVotingActive; + bool m_bVoteSystemActive; float m_flVoteResultCycleTime; // what time will we cycle to the result float m_flHideTime; // what time will we hide bool m_bVotePassed; // what mode are we going to cycle to @@ -172,6 +183,7 @@ private: float m_flPostVotedHideTime; bool m_bShowVoteActivePanel; int m_iVoteCallerIdx; + int m_nVoteTeamIndex; // If defined, only players on this team will see/vote on the issue }; #endif // HUD_VOTE_H diff --git a/mp/src/game/client/in_camera.cpp b/mp/src/game/client/in_camera.cpp index aa010732..ec40ac18 100644 --- a/mp/src/game/client/in_camera.cpp +++ b/mp/src/game/client/in_camera.cpp @@ -60,6 +60,7 @@ void CAM_ToThirdPerson(void) { if ( cl_thirdperson.GetBool() == false ) { + g_ThirdPersonManager.SetDesiredCameraOffset( Vector( cam_idealdist.GetFloat(), cam_idealdistright.GetFloat(), cam_idealdistup.GetFloat() ) ); g_ThirdPersonManager.SetOverridingThirdPerson( true ); } diff --git a/mp/src/game/client/in_joystick.cpp b/mp/src/game/client/in_joystick.cpp index 71d03a08..a3b63620 100644 --- a/mp/src/game/client/in_joystick.cpp +++ b/mp/src/game/client/in_joystick.cpp @@ -800,7 +800,7 @@ void CInput::JoyStickMove( float frametime, CUserCmd *cmd ) if ( m_flPreviousJoystickForward || m_flPreviousJoystickSide || m_flPreviousJoystickPitch || m_flPreviousJoystickYaw ) { - Vector vTempOffset = g_ThirdPersonManager.GetCameraOffsetAngles(); + const Vector& vTempOffset = g_ThirdPersonManager.GetCameraOffsetAngles(); // update the ideal pitch and yaw cam_idealpitch.SetValue( vTempOffset[ PITCH ] - viewangles[ PITCH ] ); diff --git a/mp/src/game/client/in_mouse.cpp b/mp/src/game/client/in_mouse.cpp index bcf715a1..332b0ea1 100644 --- a/mp/src/game/client/in_mouse.cpp +++ b/mp/src/game/client/in_mouse.cpp @@ -522,7 +522,7 @@ void CInput::ApplyMouse( QAngle& viewangles, CUserCmd *cmd, float mouse_x, float } else { - viewangles[PITCH] += m_pitch->GetFloat() * mouse_y; + viewangles[PITCH] += CAM_CapPitch( m_pitch->GetFloat() * mouse_y ); } // Check pitch bounds diff --git a/mp/src/game/client/input.h b/mp/src/game/client/input.h index e34b82db..2fa2cec3 100644 --- a/mp/src/game/client/input.h +++ b/mp/src/game/client/input.h @@ -99,7 +99,8 @@ public: virtual bool CAM_IsOrthographic() const; virtual void CAM_OrthographicSize( float& w, float& h ) const; - virtual float CAM_CapYaw( float fVal ) { return fVal; } + virtual float CAM_CapYaw( float fVal ) const { return fVal; } + virtual float CAM_CapPitch( float fVal ) const { return fVal; } #if defined( HL2_CLIENT_DLL ) // IK back channel info @@ -113,7 +114,7 @@ public: virtual bool EnableJoystickMode(); // Private Implementation -private: +protected: // Implementation specific initialization void Init_Camera( void ); void Init_Keyboard( void ); @@ -134,8 +135,8 @@ private: void GetAccumulatedMouseDeltasAndResetAccumulators( float *mx, float *my ); void GetMouseDelta( float inmousex, float inmousey, float *pOutMouseX, float *pOutMouseY ); void ScaleMouse( float *x, float *y ); - void ApplyMouse( QAngle& viewangles, CUserCmd *cmd, float mouse_x, float mouse_y ); - void MouseMove ( CUserCmd *cmd ); + virtual void ApplyMouse( QAngle& viewangles, CUserCmd *cmd, float mouse_x, float mouse_y ); + virtual void MouseMove ( CUserCmd *cmd ); // Joystick movement input helpers void ControllerMove ( float frametime, CUserCmd *cmd ); diff --git a/mp/src/game/client/particlemgr.cpp b/mp/src/game/client/particlemgr.cpp index f79d17a6..0eb09a43 100644 --- a/mp/src/game/client/particlemgr.cpp +++ b/mp/src/game/client/particlemgr.cpp @@ -1540,12 +1540,15 @@ static ConVar r_threaded_particles( "r_threaded_particles", "1" ); static float s_flThreadedPSystemTimeStep; -static void ProcessPSystem( CNewParticleEffect *&pNewEffect ) +static void ProcessPSystem( ParticleSimListEntry_t& pSimListEntry ) { // Enable FP exceptions here when FP_EXCEPTIONS_ENABLED is defined, // to help track down bad math. FPExceptionEnabler enableExceptions; + CNewParticleEffect* pNewEffect = pSimListEntry.m_pNewParticleEffect; + bool updateBboxOnly = pSimListEntry.m_bBoundingBoxOnly; + // If this is a new effect, then update its bbox so it goes in the // right leaves (if it has particles). int bFirstUpdate = pNewEffect->GetNeedsBBoxUpdate(); @@ -1564,12 +1567,12 @@ static void ProcessPSystem( CNewParticleEffect *&pNewEffect ) if ( pNewEffect->GetFirstFrameFlag() ) { - pNewEffect->Simulate( 0.0f ); + pNewEffect->Simulate( 0.0f, updateBboxOnly ); pNewEffect->SetFirstFrameFlag( false ); } else if ( pNewEffect->ShouldSimulate() ) { - pNewEffect->Simulate( s_flThreadedPSystemTimeStep ); + pNewEffect->Simulate( s_flThreadedPSystemTimeStep, updateBboxOnly ); } if ( pNewEffect->IsFinished() ) @@ -1684,7 +1687,7 @@ bool CParticleMgr::RetireParticleCollections( CParticleSystemDefinition* pDef, // Next, see if there are new particle systems that need early retirement static ConVar cl_particle_retire_cost( "cl_particle_retire_cost", "0", FCVAR_CHEAT ); -bool CParticleMgr::EarlyRetireParticleSystems( int nCount, CNewParticleEffect **ppEffects ) +bool CParticleMgr::EarlyRetireParticleSystems( int nCount, ParticleSimListEntry_t *ppEffects ) { // NOTE: Doing a cheap and hacky estimate of worst-case fillrate const CViewSetup *pViewSetup = view->GetPlayerViewSetup(); @@ -1699,14 +1702,14 @@ bool CParticleMgr::EarlyRetireParticleSystems( int nCount, CNewParticleEffect ** CParticleSystemDefinition **ppDefs = (CParticleSystemDefinition**)stackalloc( nCount * sizeof(CParticleSystemDefinition*) ); for ( int i = 0; i < nCount; ++i ) { - CParticleSystemDefinition *pDef = ppEffects[i]->m_pDef; + CParticleSystemDefinition *pDef = ppEffects[i].m_pNewParticleEffect->m_pDef; // Skip stuff that doesn't have a cull radius set if ( pDef->GetCullRadius() == 0.0f ) continue; // Only perform the cull check on creation - if ( !ppEffects[i]->GetFirstFrameFlag() ) + if ( !ppEffects[i].m_pNewParticleEffect->GetFirstFrameFlag() ) continue; if ( pDef->HasRetirementBeenChecked( gpGlobals->framecount ) ) @@ -1714,7 +1717,7 @@ bool CParticleMgr::EarlyRetireParticleSystems( int nCount, CNewParticleEffect ** pDef->MarkRetirementCheck( gpGlobals->framecount ); - ppDefs[nDefCount++] = ppEffects[i]->m_pDef; + ppDefs[nDefCount++] = ppEffects[i].m_pNewParticleEffect->m_pDef; } if ( nDefCount == 0 ) @@ -1722,7 +1725,7 @@ bool CParticleMgr::EarlyRetireParticleSystems( int nCount, CNewParticleEffect ** for ( int i = 0; i < nCount; ++i ) { - ppEffects[i]->MarkShouldPerformCullCheck( true ); + ppEffects[i].m_pNewParticleEffect->MarkShouldPerformCullCheck( true ); } Vector vecCameraForward; @@ -1749,28 +1752,45 @@ bool CParticleMgr::EarlyRetireParticleSystems( int nCount, CNewParticleEffect ** for ( int i = 0; i < nCount; ++i ) { - ppEffects[i]->MarkShouldPerformCullCheck( false ); + ppEffects[i].m_pNewParticleEffect->MarkShouldPerformCullCheck( false ); } return bRetiredCollections; } static ConVar particle_sim_alt_cores( "particle_sim_alt_cores", "2" ); -void CParticleMgr::BuildParticleSimList( CUtlVector< CNewParticleEffect* > &list ) +void CParticleMgr::BuildParticleSimList( CUtlVector< ParticleSimListEntry_t > &list ) { float flNow = g_pParticleSystemMgr->GetLastSimulationTime(); for( CNewParticleEffect *pNewEffect=m_NewEffects.m_pHead; pNewEffect; pNewEffect=pNewEffect->m_pNext ) { + bool bSkip = false; + bool bNeedsBboxUpdate = false; + if ( flNow >= pNewEffect->m_flNextSleepTime && pNewEffect->m_nActiveParticles > 0 ) - continue; + bSkip = true; if ( pNewEffect->GetRemoveFlag() ) - continue; - if ( g_bMeasureParticlePerformance ) + bSkip = true; + + if ( !bSkip && g_bMeasureParticlePerformance ) { g_nNumParticlesSimulated += pNewEffect->m_nActiveParticles; } - list.AddToTail( pNewEffect ); + + // Particles that are attached to moving things will need to update their bboxes even if they + // otherwise would like to skip the updates. Check that here. + if (bSkip) + { + bNeedsBboxUpdate = pNewEffect->HasMoved(); + bSkip = !bNeedsBboxUpdate; + } + + if (!bSkip) + { + ParticleSimListEntry_t entry = { pNewEffect, bNeedsBboxUpdate }; + list.AddToTail( entry ); + } } } @@ -1812,23 +1832,27 @@ void CParticleMgr::UpdateNewEffects( float flTimeDelta ) int nParticleStatsTriggerCount = cl_particle_stats_trigger_count.GetInt(); BeginSimulateParticles(); - CUtlVector<CNewParticleEffect *> particlesToSimulate; - BuildParticleSimList( particlesToSimulate ); s_flThreadedPSystemTimeStep = flTimeDelta; - int nCount = particlesToSimulate.Count(); - // first, run non-reentrant part to get CP updates from entities - for( int i=0; i<nCount; i++ ) + // This is done on all particles, because it updates control point locations which we need to determine whether or not we should + // do full simulation later. + for (CNewParticleEffect *pNewEffect = m_NewEffects.m_pHead; pNewEffect; + pNewEffect = pNewEffect->m_pNext) { // this one can call into random entity code which may not be thread-safe - particlesToSimulate[i]->Update( s_flThreadedPSystemTimeStep ); + pNewEffect->Update( s_flThreadedPSystemTimeStep ); if ( nParticleStatsTriggerCount > 0 ) { - nParticleActiveParticlesCount += CountParticleSystemActiveParticles( particlesToSimulate[i] ); + nParticleActiveParticlesCount += CountParticleSystemActiveParticles( pNewEffect ); } } + CUtlVector<ParticleSimListEntry_t> particlesToSimulate; + BuildParticleSimList(particlesToSimulate); + int nCount = particlesToSimulate.Count(); + + // See if there are new particle systems that need early retirement // This has to happen after the first update if ( EarlyRetireParticleSystems( nCount, particlesToSimulate.Base() ) ) @@ -1861,7 +1885,7 @@ void CParticleMgr::UpdateNewEffects( float flTimeDelta ) { nAltCore = 2; } - CParallelProcessor<CNewParticleEffect*, CFuncJobItemProcessor<CNewParticleEffect*> > processor( "CParticleMgr::UpdateNewEffects" ); + CParallelProcessor<ParticleSimListEntry_t, CFuncJobItemProcessor<ParticleSimListEntry_t> > processor( "CParticleMgr::UpdateNewEffects" ); processor.m_ItemProcessor.Init( ProcessPSystem, NULL, NULL ); processor.Run( particlesToSimulate.Base(), nCount, INT_MAX, m_pThreadPool[nAltCore-1] ); } @@ -1872,7 +1896,7 @@ void CParticleMgr::UpdateNewEffects( float flTimeDelta ) for( int i=0; i<nCount; i++) { // this one can call into random entity code which may not be thread-safe - particlesToSimulate[i]->DetectChanges(); + particlesToSimulate[i].m_pNewParticleEffect->DetectChanges(); } EndSimulateParticles(); diff --git a/mp/src/game/client/particlemgr.h b/mp/src/game/client/particlemgr.h index 3214a55f..d4537f35 100644 --- a/mp/src/game/client/particlemgr.h +++ b/mp/src/game/client/particlemgr.h @@ -236,6 +236,13 @@ public: IMaterial *m_pMaterial; }; +// Particle simulation list, used to determine what particles to simulate and how. +struct ParticleSimListEntry_t +{ + CNewParticleEffect* m_pNewParticleEffect; + bool m_bBoundingBoxOnly; +}; + //----------------------------------------------------------------------------- // interface IParticleEffect: @@ -715,8 +722,9 @@ private: const CViewSetup& view, const VMatrix &worldToPixels, float flFocalDist ); bool RetireParticleCollections( CParticleSystemDefinition* pDef, int nCount, RetireInfo_t *pInfo, float flScreenArea, float flMaxTotalArea ); - void BuildParticleSimList( CUtlVector< CNewParticleEffect* > &list ); - bool EarlyRetireParticleSystems( int nCount, CNewParticleEffect **ppEffects ); + + void BuildParticleSimList( CUtlVector< ParticleSimListEntry_t > &list ); + bool EarlyRetireParticleSystems( int nCount, ParticleSimListEntry_t *ppEffects ); static int RetireSort( const void *p1, const void *p2 ); private: diff --git a/mp/src/game/client/particles_new.cpp b/mp/src/game/client/particles_new.cpp index d3dc6599..647d304f 100644 --- a/mp/src/game/client/particles_new.cpp +++ b/mp/src/game/client/particles_new.cpp @@ -65,6 +65,8 @@ void CNewParticleEffect::Construct() m_MaxBounds = Vector( -1.0e6, -1.0e6, -1.0e6 ); m_pDebugName = NULL; + m_bViewModelEffect = m_pDef ? m_pDef->IsViewModelEffect() : false; + if ( IsValid() && clienttools->IsInRecordingMode() ) { int nId = AllocateToolParticleEffectId(); diff --git a/mp/src/game/client/particles_new.h b/mp/src/game/client/particles_new.h index eb80f93a..06d98c9c 100644 --- a/mp/src/game/client/particles_new.h +++ b/mp/src/game/client/particles_new.h @@ -91,6 +91,9 @@ public: void SetControlPointUpVector( int nWhichPoint, const Vector &v ); void SetControlPointRightVector( int nWhichPoint, const Vector &v ); + void SetIsViewModelEffect ( bool bIsViewModelEffect ) { m_bViewModelEffect = bIsViewModelEffect; } + bool GetIsViewModelEffect () { return m_bViewModelEffect; } + FORCEINLINE EHANDLE const &GetControlPointEntity( int nWhichPoint ) { return m_hControlPointOwners[ nWhichPoint ]; @@ -153,6 +156,8 @@ protected: Vector m_LastMin; Vector m_LastMax; + bool m_bViewModelEffect; + private: // Update the reference count. void AddRef(); @@ -309,7 +314,7 @@ inline void CNewParticleEffect::MarkShouldPerformCullCheck( bool bEnable ) inline CSmartPtr<CNewParticleEffect> CNewParticleEffect::Create( CBaseEntity *pOwner, const char *pParticleSystemName, const char *pDebugName ) { CNewParticleEffect *pRet = new CNewParticleEffect( pOwner, pParticleSystemName ); - pRet->m_pDebugName = pDebugName; + pRet->m_pDebugName = pDebugName ? pDebugName : pParticleSystemName; pRet->SetDynamicallyAllocated( true ); return pRet; } @@ -317,7 +322,7 @@ inline CSmartPtr<CNewParticleEffect> CNewParticleEffect::Create( CBaseEntity *pO inline CSmartPtr<CNewParticleEffect> CNewParticleEffect::Create( CBaseEntity *pOwner, CParticleSystemDefinition *pDef, const char *pDebugName ) { CNewParticleEffect *pRet = new CNewParticleEffect( pOwner, pDef ); - pRet->m_pDebugName = pDebugName; + pRet->m_pDebugName = pDebugName ? pDebugName : pDef->GetName(); pRet->SetDynamicallyAllocated( true ); return pRet; } diff --git a/mp/src/game/client/prediction.cpp b/mp/src/game/client/prediction.cpp index 6646f8f9..2a67007b 100644 --- a/mp/src/game/client/prediction.cpp +++ b/mp/src/game/client/prediction.cpp @@ -45,6 +45,12 @@ static ConVar cl_predictionentitydump( "cl_pdump", "-1", FCVAR_CHEAT, "Dump info static ConVar cl_predictionentitydumpbyclass( "cl_pclass", "", FCVAR_CHEAT, "Dump entity by prediction classname." ); static ConVar cl_pred_optimize( "cl_pred_optimize", "2", 0, "Optimize for not copying data if didn't receive a network update (1), and also for not repredicting if there were no errors (2)." ); +#ifdef STAGING_ONLY +// Do not ship this - testing a fix +static ConVar cl_pred_optimize_prefer_server_data( "cl_pred_optimize_prefer_server_data", "0", 0, "In the case where we have both server data and predicted data up to the same tick, choose server data over predicted data." ); +// +#endif // STAGING_ONLY + #endif extern IGameMovement *g_pGameMovement; @@ -1401,6 +1407,11 @@ int CPrediction::ComputeFirstCommandToExecute( bool received_new_world_update, i } else { +#ifdef STAGING_ONLY + int nPredictedLimit = cl_pred_optimize_prefer_server_data.GetBool() ? m_nCommandsPredicted - 1 : m_nCommandsPredicted; +#else + int nPredictedLimit = m_nCommandsPredicted; +#endif // STAGING_ONLY // Otherwise, there is a second optimization, wherein if we did receive an update, but no // values differed (or were outside their epsilon) and the server actually acknowledged running // one or more commands, then we can revert the entity to the predicted state from last frame, @@ -1409,7 +1420,7 @@ int CPrediction::ComputeFirstCommandToExecute( bool received_new_world_update, i if ( cl_pred_optimize.GetInt() >= 2 && !m_bPreviousAckHadErrors && m_nCommandsPredicted > 0 && - m_nServerCommandsAcknowledged <= m_nCommandsPredicted ) + m_nServerCommandsAcknowledged <= nPredictedLimit ) { // Copy all of the previously predicted data back into entity so we can skip repredicting it // This is the final slot that we previously predicted diff --git a/mp/src/game/client/rendertexture.cpp b/mp/src/game/client/rendertexture.cpp index 78780e93..fa2edb28 100644 --- a/mp/src/game/client/rendertexture.cpp +++ b/mp/src/game/client/rendertexture.cpp @@ -107,11 +107,11 @@ ITexture *GetFullFrameFrameBufferTexture( int textureIndex ) char name[256]; if( textureIndex != 0 ) { - sprintf( name, "_rt_FullFrameFB%d", textureIndex ); + V_sprintf_safe( name, "_rt_FullFrameFB%d", textureIndex ); } else { - Q_strcpy( name, "_rt_FullFrameFB" ); + V_strcpy_safe( name, "_rt_FullFrameFB" ); } s_pFullFrameFrameBufferTexture[textureIndex].Init( materials->FindTexture( name, TEXTURE_GROUP_RENDER_TARGET ) ); Assert( !IsErrorTexture( s_pFullFrameFrameBufferTexture[textureIndex] ) ); diff --git a/mp/src/game/client/replay/genericclassbased_replay.cpp b/mp/src/game/client/replay/genericclassbased_replay.cpp index 00e2feba..13dfacfd 100644 --- a/mp/src/game/client/replay/genericclassbased_replay.cpp +++ b/mp/src/game/client/replay/genericclassbased_replay.cpp @@ -141,7 +141,7 @@ bool CGenericClassBasedReplay::Read( KeyValues *pIn ) // Read killer info m_nKillerClass = pIn->GetInt( "killer_class" ); - V_strcpy( m_szKillerName, pIn->GetString( "killer_name" ) ); + V_strcpy_safe( m_szKillerName, pIn->GetString( "killer_name" ) ); // Make sure vector is clear Assert( GetKillCount() == 0 ); diff --git a/mp/src/game/client/sixense/in_sixense.cpp b/mp/src/game/client/sixense/in_sixense.cpp index e0f4ba39..c8f79ec7 100644 --- a/mp/src/game/client/sixense/in_sixense.cpp +++ b/mp/src/game/client/sixense/in_sixense.cpp @@ -2151,7 +2151,7 @@ void SixenseInput::SetPlayerHandPositions( CUserCmd *pCmd, float flFrametime ) // This 'slides' the hold origin if you pull the object back into the player float min_z_dist = sixense_hold_slide_z_min_dist.GetFloat(); - float xy_radius = sixense_hold_slide_xy_radius.GetFloat();; + float xy_radius = sixense_hold_slide_xy_radius.GetFloat(); if ( !m_bScalingLockedOneToOne && (Vector3( ss_right_pos[0], ss_right_pos[1], 0.0f ).length() < xy_radius) && (ss_right_pos[2] > min_z_dist) ) { diff --git a/mp/src/game/client/spritemodel.cpp b/mp/src/game/client/spritemodel.cpp index 018e918f..09284865 100644 --- a/mp/src/game/client/spritemodel.cpp +++ b/mp/src/game/client/spritemodel.cpp @@ -201,7 +201,7 @@ static void AdjustSubRect(CEngineSprite *pSprite, int frame, float *pfLeft, floa *pw = rc.right - rc.left; *ph = rc.bottom - rc.top; - f = 1.0 / (float)pSprite->GetWidth();; + f = 1.0 / (float)pSprite->GetWidth(); *pfLeft = ((float)rc.left + 0.5) * f; *pfRight = ((float)rc.right - 0.5) * f; @@ -415,12 +415,14 @@ IMaterial *CEngineSprite::GetMaterial( RenderMode_t nRenderMode, int nFrame ) m_VideoMaterial->SetFrame( nFrame ); } - IMaterial *pMaterial = m_material[nRenderMode]; - IMaterialVar* pFrameVar = pMaterial->FindVarFast( "$frame", &frameCache ); - if ( pFrameVar ) + if ( pMaterial ) { - pFrameVar->SetIntValue( nFrame ); + IMaterialVar* pFrameVar = pMaterial->FindVarFast( "$frame", &frameCache ); + if ( pFrameVar ) + { + pFrameVar->SetIntValue( nFrame ); + } } return pMaterial; diff --git a/mp/src/game/client/vgui_debugoverlaypanel.cpp b/mp/src/game/client/vgui_debugoverlaypanel.cpp index c3734147..32a7ee83 100644 --- a/mp/src/game/client/vgui_debugoverlaypanel.cpp +++ b/mp/src/game/client/vgui_debugoverlaypanel.cpp @@ -166,7 +166,8 @@ public: if ( debugOverlayPanel ) { debugOverlayPanel->SetParent( (vgui::Panel *)NULL ); - delete debugOverlayPanel; + debugOverlayPanel->MarkForDeletion(); + debugOverlayPanel = NULL; } } }; diff --git a/mp/src/game/client/vgui_fpspanel.cpp b/mp/src/game/client/vgui_fpspanel.cpp index a1e88875..7458b702 100644 --- a/mp/src/game/client/vgui_fpspanel.cpp +++ b/mp/src/game/client/vgui_fpspanel.cpp @@ -395,7 +395,7 @@ public: if ( fpsPanel ) { fpsPanel->SetParent( (vgui::Panel *)NULL ); - delete fpsPanel; + fpsPanel->MarkForDeletion(); fpsPanel = NULL; } } @@ -814,7 +814,7 @@ public: if ( ioPanel ) { ioPanel->SetParent( (vgui::Panel *)NULL ); - delete ioPanel; + ioPanel->MarkForDeletion(); ioPanel = NULL; } } diff --git a/mp/src/game/client/vgui_loadingdiscpanel.cpp b/mp/src/game/client/vgui_loadingdiscpanel.cpp index 94b2a9fb..2dc7dd8f 100644 --- a/mp/src/game/client/vgui_loadingdiscpanel.cpp +++ b/mp/src/game/client/vgui_loadingdiscpanel.cpp @@ -128,14 +128,14 @@ public: if ( loadingDiscPanel ) { loadingDiscPanel->SetParent( (vgui::Panel *)NULL ); - delete loadingDiscPanel; + loadingDiscPanel->MarkForDeletion(); loadingDiscPanel = NULL; } if ( m_pPauseDiscPanel ) { m_pPauseDiscPanel->SetParent( (vgui::Panel *)NULL ); - delete m_pPauseDiscPanel; + m_pPauseDiscPanel->MarkForDeletion(); m_pPauseDiscPanel = NULL; } diff --git a/mp/src/game/client/vgui_messagechars.cpp b/mp/src/game/client/vgui_messagechars.cpp index 1d1410f1..6bde7566 100644 --- a/mp/src/game/client/vgui_messagechars.cpp +++ b/mp/src/game/client/vgui_messagechars.cpp @@ -378,7 +378,7 @@ public: if ( messageCharsPanel ) { messageCharsPanel->SetParent( (vgui::Panel *)NULL ); - delete messageCharsPanel; + messageCharsPanel->MarkForDeletion(); messageCharsPanel = NULL; } } diff --git a/mp/src/game/client/vgui_netgraphpanel.cpp b/mp/src/game/client/vgui_netgraphpanel.cpp index 0f601438..adf3e4b9 100644 --- a/mp/src/game/client/vgui_netgraphpanel.cpp +++ b/mp/src/game/client/vgui_netgraphpanel.cpp @@ -492,6 +492,10 @@ void CNetGraphPanel::DrawTimes( vrect_t vrect, cmdinfo_t *cmdinfo, int x, int w, { i = ( m_OutgoingSequence - a ) & ( TIMINGS - 1 ); h = MIN( ( cmdinfo[i].cmd_lerp / 3.0 ) * LERP_HEIGHT, LERP_HEIGHT ); + if ( h < 0 ) + { + h = LERP_HEIGHT; + } rcFill.x = x + w -a - 1; rcFill.width = 1; @@ -514,7 +518,9 @@ void CNetGraphPanel::DrawTimes( vrect_t vrect, cmdinfo_t *cmdinfo, int x, int w, for ( j = start; j < h; j++ ) { - DrawLine(&rcFill, colors[j + extrap_point], 255 ); + int index = j + extrap_point; + Assert( (size_t)index < Q_ARRAYSIZE( colors ) ); + DrawLine(&rcFill, colors[ index ], 255 ); rcFill.y--; } } @@ -532,7 +538,9 @@ void CNetGraphPanel::DrawTimes( vrect_t vrect, cmdinfo_t *cmdinfo, int x, int w, for ( j = 0; j < h; j++ ) { - DrawLine(&rcFill, colors[j + oldh], 255 ); + int index = j + oldh; + Assert( (size_t)index < Q_ARRAYSIZE( colors ) ); + DrawLine(&rcFill, colors[ index ], 255 ); rcFill.y--; } } @@ -1533,7 +1541,7 @@ public: if ( netGraphPanel ) { netGraphPanel->SetParent( (Panel *)NULL ); - delete netGraphPanel; + netGraphPanel->MarkForDeletion(); netGraphPanel = NULL; } } diff --git a/mp/src/game/client/vgui_schemevisualizer.cpp b/mp/src/game/client/vgui_schemevisualizer.cpp index b2a6f774..afde874d 100644 --- a/mp/src/game/client/vgui_schemevisualizer.cpp +++ b/mp/src/game/client/vgui_schemevisualizer.cpp @@ -178,11 +178,13 @@ void CSchemeVisualizer::AddFontsToList() { #ifdef POSIX const char strOAccent[] = { (char)0xc3, (char)0x93, 0x00 }; // UTF-8 for U+00D3 (LATIN CAPITAL LETTER O WITH ACUTE) + const char strSkull[] = { (char)0xe2, (char)0x98, (char)0xa0, 0x00 }; #else const uint8 strOAccent[] = { 0xd3, 0x00 }; + const char strSkull[] = ""; #endif // Stick an intl character in here to test accents (O') - CFmtStr fmtText( "ABCDEFGHIJKLMN%sPQRSTUVWXYZabcdefhijklmnopqrstuvwxyz0123456789!@#$%%^&*()-_=+", strOAccent ); + CFmtStr fmtText( "ABCDEFGHIJKLMN%sPQRSTUVWXYZ%sabcdefhijklmnopqrstuvwxyz0123456789!@#$%%^&*()-_=+", strOAccent, strSkull ); const int nFontCount = m_pViewScheme->GetFontCount(); @@ -288,4 +290,4 @@ void CSchemeVisualizer::OnTick() // Update the list now UpdateList( nType ); -}
\ No newline at end of file +} diff --git a/mp/src/game/client/vgui_video.cpp b/mp/src/game/client/vgui_video.cpp index 3badea3f..57323f40 100644 --- a/mp/src/game/client/vgui_video.cpp +++ b/mp/src/game/client/vgui_video.cpp @@ -348,7 +348,8 @@ bool VideoPanel_Create( unsigned int nXPos, unsigned int nYPos, // Start it going if ( pVideoPanel->BeginPlayback( pVideoFilename ) == false ) { - delete pVideoPanel; + pVideoPanel->MarkForDeletion(); + pVideoPanel = NULL; return false; } diff --git a/mp/src/game/client/view.cpp b/mp/src/game/client/view.cpp index 333a2756..d74d326e 100644 --- a/mp/src/game/client/view.cpp +++ b/mp/src/game/client/view.cpp @@ -110,9 +110,9 @@ static ConVar v_centerspeed( "v_centerspeed","500" ); #ifdef TF_CLIENT_DLL // 54 degrees approximates a 35mm camera - we determined that this makes the viewmodels // and motions look the most natural. -ConVar v_viewmodel_fov( "viewmodel_fov", "54", FCVAR_ARCHIVE ); +ConVar v_viewmodel_fov( "viewmodel_fov", "54", FCVAR_ARCHIVE, "Sets the field-of-view for the viewmodel.", true, 0.1, true, 179.9 ); #else -ConVar v_viewmodel_fov( "viewmodel_fov", "54", FCVAR_CHEAT ); +ConVar v_viewmodel_fov( "viewmodel_fov", "54", FCVAR_CHEAT, "Sets the field-of-view for the viewmodel.", true, 0.1, true, 179.9 ); #endif ConVar mat_viewportscale( "mat_viewportscale", "1.0", FCVAR_ARCHIVE, "Scale down the main viewport (to reduce GPU impact on CPU profiling)", true, (1.0f / 640.0f), true, 1.0f ); ConVar mat_viewportupscale( "mat_viewportupscale", "1", FCVAR_ARCHIVE, "Scale the viewport back up" ); diff --git a/mp/src/game/client/weapon_selection.cpp b/mp/src/game/client/weapon_selection.cpp index 66666b59..dc2adf4e 100644 --- a/mp/src/game/client/weapon_selection.cpp +++ b/mp/src/game/client/weapon_selection.cpp @@ -101,6 +101,7 @@ void CBaseHudWeaponSelection::Reset(void) // Start hidden m_bSelectionVisible = false; m_flSelectionTime = gpGlobals->curtime; + gHUD.UnlockRenderGroup( gHUD.LookupRenderGroupIndexByName( "weapon_selection" ) ); } //----------------------------------------------------------------------------- @@ -207,6 +208,7 @@ bool CBaseHudWeaponSelection::IsInSelectionMode() void CBaseHudWeaponSelection::OpenSelection( void ) { m_bSelectionVisible = true; + gHUD.LockRenderGroup( gHUD.LookupRenderGroupIndexByName( "weapon_selection" ) ); } //----------------------------------------------------------------------------- @@ -215,6 +217,7 @@ void CBaseHudWeaponSelection::OpenSelection( void ) void CBaseHudWeaponSelection::HideSelection( void ) { m_bSelectionVisible = false; + gHUD.UnlockRenderGroup( gHUD.LookupRenderGroupIndexByName( "weapon_selection" ) ); } //----------------------------------------------------------------------------- |