aboutsummaryrefslogtreecommitdiff
path: root/mp/src/game
diff options
context:
space:
mode:
authorJohn Schoenick <[email protected]>2015-09-09 18:35:41 -0700
committerJohn Schoenick <[email protected]>2015-09-09 18:35:41 -0700
commit0d8dceea4310fde5706b3ce1c70609d72a38efdf (patch)
treec831ef32c2c801a5c5a80401736b52c7b5a528ec /mp/src/game
parentUpdated the SDK with the latest code from the TF and HL2 branches. (diff)
downloadsource-sdk-2013-master.tar.xz
source-sdk-2013-master.zip
Updated the SDK with the latest code from the TF and HL2 branches.HEADmaster
Diffstat (limited to 'mp/src/game')
-rw-r--r--mp/src/game/client/baseanimatedtextureproxy.cpp42
-rw-r--r--mp/src/game/client/bsp_utils.cpp170
-rw-r--r--mp/src/game/client/bsp_utils.h21
-rw-r--r--mp/src/game/client/c_ai_basenpc.cpp16
-rw-r--r--mp/src/game/client/c_ai_basenpc.h4
-rw-r--r--mp/src/game/client/c_baseanimating.cpp168
-rw-r--r--mp/src/game/client/c_baseanimating.h23
-rw-r--r--mp/src/game/client/c_basecombatcharacter.cpp19
-rw-r--r--mp/src/game/client/c_basecombatcharacter.h7
-rw-r--r--mp/src/game/client/c_basecombatweapon.cpp5
-rw-r--r--mp/src/game/client/c_baseentity.cpp64
-rw-r--r--mp/src/game/client/c_baseentity.h5
-rw-r--r--mp/src/game/client/c_baseplayer.cpp50
-rw-r--r--mp/src/game/client/c_baseplayer.h7
-rw-r--r--mp/src/game/client/c_baseviewmodel.cpp17
-rw-r--r--mp/src/game/client/c_rope.cpp20
-rw-r--r--mp/src/game/client/c_sceneentity.cpp6
-rw-r--r--mp/src/game/client/c_slideshow_display.cpp8
-rw-r--r--mp/src/game/client/c_soundscape.cpp2
-rw-r--r--mp/src/game/client/c_team_objectiveresource.h2
-rw-r--r--mp/src/game/client/c_vote_controller.cpp4
-rw-r--r--mp/src/game/client/cdll_bounded_cvars.cpp2
-rw-r--r--mp/src/game/client/cdll_client_int.cpp24
-rw-r--r--mp/src/game/client/client_base.vpc5
-rw-r--r--mp/src/game/client/clientleafsystem.cpp72
-rw-r--r--mp/src/game/client/clientmode_shared.cpp130
-rw-r--r--mp/src/game/client/clientmode_shared.h2
-rw-r--r--mp/src/game/client/clientshadowmgr.cpp3
-rw-r--r--mp/src/game/client/clientsideeffects.cpp27
-rw-r--r--mp/src/game/client/clientsideeffects.h7
-rw-r--r--mp/src/game/client/fx_quad.cpp22
-rw-r--r--mp/src/game/client/fx_quad.h2
-rw-r--r--mp/src/game/client/fx_tracer.cpp27
-rw-r--r--mp/src/game/client/game_controls/MapOverview.cpp4
-rw-r--r--mp/src/game/client/game_controls/SpectatorGUI.cpp3
-rw-r--r--mp/src/game/client/game_controls/basemodel_panel.cpp205
-rw-r--r--mp/src/game/client/game_controls/basemodel_panel.h23
-rw-r--r--mp/src/game/client/game_controls/baseviewport.cpp21
-rw-r--r--mp/src/game/client/game_controls/vguitextwindow.cpp6
-rw-r--r--mp/src/game/client/hl2/c_waterbullet.cpp2
-rw-r--r--mp/src/game/client/hl2/hud_credits.cpp4
-rw-r--r--mp/src/game/client/hltvcamera.cpp2
-rw-r--r--mp/src/game/client/hud_basechat.cpp9
-rw-r--r--mp/src/game/client/hud_basedeathnotice.cpp97
-rw-r--r--mp/src/game/client/hud_basedeathnotice.h10
-rw-r--r--mp/src/game/client/hud_controlpointicons.cpp2
-rw-r--r--mp/src/game/client/hud_vote.cpp412
-rw-r--r--mp/src/game/client/hud_vote.h24
-rw-r--r--mp/src/game/client/in_camera.cpp1
-rw-r--r--mp/src/game/client/in_joystick.cpp2
-rw-r--r--mp/src/game/client/in_mouse.cpp2
-rw-r--r--mp/src/game/client/input.h9
-rw-r--r--mp/src/game/client/particlemgr.cpp70
-rw-r--r--mp/src/game/client/particlemgr.h12
-rw-r--r--mp/src/game/client/particles_new.cpp2
-rw-r--r--mp/src/game/client/particles_new.h9
-rw-r--r--mp/src/game/client/prediction.cpp13
-rw-r--r--mp/src/game/client/rendertexture.cpp4
-rw-r--r--mp/src/game/client/replay/genericclassbased_replay.cpp2
-rw-r--r--mp/src/game/client/sixense/in_sixense.cpp2
-rw-r--r--mp/src/game/client/spritemodel.cpp12
-rw-r--r--mp/src/game/client/vgui_debugoverlaypanel.cpp3
-rw-r--r--mp/src/game/client/vgui_fpspanel.cpp4
-rw-r--r--mp/src/game/client/vgui_loadingdiscpanel.cpp4
-rw-r--r--mp/src/game/client/vgui_messagechars.cpp2
-rw-r--r--mp/src/game/client/vgui_netgraphpanel.cpp14
-rw-r--r--mp/src/game/client/vgui_schemevisualizer.cpp6
-rw-r--r--mp/src/game/client/vgui_video.cpp3
-rw-r--r--mp/src/game/client/view.cpp4
-rw-r--r--mp/src/game/client/weapon_selection.cpp3
-rw-r--r--mp/src/game/server/AI_ResponseSystem.h1
-rw-r--r--mp/src/game/server/BaseAnimatingOverlay.cpp19
-rw-r--r--mp/src/game/server/BaseAnimatingOverlay.h1
-rw-r--r--mp/src/game/server/CommentarySystem.cpp2
-rw-r--r--mp/src/game/server/GameStats_BasicStatsFunctions.cpp2
-rw-r--r--mp/src/game/server/ai_activity.cpp47
-rw-r--r--mp/src/game/server/baseanimating.cpp52
-rw-r--r--mp/src/game/server/baseanimating.h11
-rw-r--r--mp/src/game/server/basecombatcharacter.cpp4
-rw-r--r--mp/src/game/server/baseentity.cpp14
-rw-r--r--mp/src/game/server/baseentity.h7
-rw-r--r--mp/src/game/server/baseflex.cpp4
-rw-r--r--mp/src/game/server/client.cpp73
-rw-r--r--mp/src/game/server/doors.h2
-rw-r--r--mp/src/game/server/episodic/ep2_gamestats.h8
-rw-r--r--mp/src/game/server/func_break.cpp4
-rw-r--r--mp/src/game/server/gameinterface.cpp71
-rw-r--r--mp/src/game/server/gameinterface.h14
-rw-r--r--mp/src/game/server/items.h3
-rw-r--r--mp/src/game/server/nav_area.cpp5
-rw-r--r--mp/src/game/server/nav_area.h11
-rw-r--r--mp/src/game/server/nav_entities.cpp3
-rw-r--r--mp/src/game/server/nav_file.cpp14
-rw-r--r--mp/src/game/server/nav_generate.cpp11
-rw-r--r--mp/src/game/server/nav_mesh.cpp12
-rw-r--r--mp/src/game/server/networkstringtable_gamedll.h2
-rw-r--r--mp/src/game/server/player.cpp35
-rw-r--r--mp/src/game/server/player.h9
-rw-r--r--mp/src/game/server/player_command.cpp7
-rw-r--r--mp/src/game/server/point_spotlight.cpp32
-rw-r--r--mp/src/game/server/props.cpp2
-rw-r--r--mp/src/game/server/props.h3
-rw-r--r--mp/src/game/server/recipientfilter.cpp2
-rw-r--r--mp/src/game/server/sceneentity.cpp3
-rw-r--r--mp/src/game/server/slideshow_display.cpp8
-rw-r--r--mp/src/game/server/team_control_point.cpp18
-rw-r--r--mp/src/game/server/team_control_point.h2
-rw-r--r--mp/src/game/server/team_control_point_master.cpp65
-rw-r--r--mp/src/game/server/team_control_point_master.h1
-rw-r--r--mp/src/game/server/trigger_area_capture.cpp16
-rw-r--r--mp/src/game/server/triggers.cpp162
-rw-r--r--mp/src/game/server/triggers.h22
-rw-r--r--mp/src/game/server/util.cpp25
-rw-r--r--mp/src/game/server/util.h1
-rw-r--r--mp/src/game/server/vote_controller.cpp375
-rw-r--r--mp/src/game/server/vote_controller.h29
-rw-r--r--mp/src/game/shared/GameStats.cpp47
-rw-r--r--mp/src/game/shared/ModelSoundsCache.cpp2
-rw-r--r--mp/src/game/shared/Multiplayer/multiplayer_animstate.cpp12
-rw-r--r--mp/src/game/shared/Multiplayer/multiplayer_animstate.h8
-rw-r--r--mp/src/game/shared/SceneCache.cpp2
-rw-r--r--mp/src/game/shared/SoundEmitterSystem.cpp14
-rw-r--r--mp/src/game/shared/SpriteTrail.h9
-rw-r--r--mp/src/game/shared/activitylist.cpp47
-rw-r--r--mp/src/game/shared/ai_activity.h50
-rw-r--r--mp/src/game/shared/animation.cpp83
-rw-r--r--mp/src/game/shared/base_playeranimstate.cpp9
-rw-r--r--mp/src/game/shared/base_playeranimstate.h1
-rw-r--r--mp/src/game/shared/basecombatcharacter_shared.cpp17
-rw-r--r--mp/src/game/shared/basecombatweapon_shared.cpp67
-rw-r--r--mp/src/game/shared/basecombatweapon_shared.h48
-rw-r--r--mp/src/game/shared/baseentity_shared.cpp9
-rw-r--r--mp/src/game/shared/baseentity_shared.h6
-rw-r--r--mp/src/game/shared/baseplayer_shared.cpp5
-rw-r--r--mp/src/game/shared/baseprojectile.cpp5
-rw-r--r--mp/src/game/shared/baseprojectile.h9
-rw-r--r--mp/src/game/shared/cam_thirdperson.cpp16
-rw-r--r--mp/src/game/shared/cam_thirdperson.h16
-rw-r--r--mp/src/game/shared/effect_dispatch_data.cpp2
-rw-r--r--mp/src/game/shared/eventlist.cpp3
-rw-r--r--mp/src/game/shared/eventlist.h3
-rw-r--r--mp/src/game/shared/expressionsample.h1
-rw-r--r--mp/src/game/shared/gamemovement.cpp2
-rw-r--r--mp/src/game/shared/gamerules.h2
-rw-r--r--mp/src/game/shared/mp_shareddefs.cpp4
-rw-r--r--mp/src/game/shared/mp_shareddefs.h3
-rw-r--r--mp/src/game/shared/multiplay_gamerules.cpp98
-rw-r--r--mp/src/game/shared/multiplay_gamerules.h10
-rw-r--r--mp/src/game/shared/particle_parse.cpp35
-rw-r--r--mp/src/game/shared/particle_property.cpp6
-rw-r--r--mp/src/game/shared/ragdoll_shared.cpp8
-rw-r--r--mp/src/game/shared/shareddefs.h6
-rw-r--r--mp/src/game/shared/takedamageinfo.cpp1
-rw-r--r--mp/src/game/shared/takedamageinfo.h14
-rw-r--r--mp/src/game/shared/teamplay_gamerules.h2
-rw-r--r--mp/src/game/shared/teamplay_round_timer.cpp71
-rw-r--r--mp/src/game/shared/teamplay_round_timer.h2
-rw-r--r--mp/src/game/shared/teamplayroundbased_gamerules.cpp467
-rw-r--r--mp/src/game/shared/teamplayroundbased_gamerules.h38
-rw-r--r--mp/src/game/shared/triggers_shared.h33
-rw-r--r--mp/src/game/shared/usercmd.h9
-rw-r--r--mp/src/game/shared/util_shared.h32
-rw-r--r--mp/src/game/shared/voice_gamemgr.cpp4
-rw-r--r--mp/src/game/shared/weapon_parse.cpp4
164 files changed, 3448 insertions, 1098 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" ) );
}
//-----------------------------------------------------------------------------
diff --git a/mp/src/game/server/AI_ResponseSystem.h b/mp/src/game/server/AI_ResponseSystem.h
index a34255b2..a7b3a797 100644
--- a/mp/src/game/server/AI_ResponseSystem.h
+++ b/mp/src/game/server/AI_ResponseSystem.h
@@ -18,6 +18,7 @@
abstract_class IResponseFilter
{
public:
+ virtual ~IResponseFilter(){}
virtual bool IsValidResponse( ResponseType_t type, const char *pszValue ) = 0;
};
diff --git a/mp/src/game/server/BaseAnimatingOverlay.cpp b/mp/src/game/server/BaseAnimatingOverlay.cpp
index 36534bc0..84be6fba 100644
--- a/mp/src/game/server/BaseAnimatingOverlay.cpp
+++ b/mp/src/game/server/BaseAnimatingOverlay.cpp
@@ -928,6 +928,25 @@ void CBaseAnimatingOverlay::SetLayerCycle( int iLayer, float flCycle, float flPr
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
+void CBaseAnimatingOverlay::SetLayerCycle( int iLayer, float flCycle, float flPrevCycle, float flLastEventCheck )
+{
+ if (!IsValidLayer( iLayer ))
+ return;
+
+ if (!m_AnimOverlay[iLayer].m_bLooping)
+ {
+ flCycle = clamp( flCycle, 0.0f, 1.0f );
+ flPrevCycle = clamp( flPrevCycle, 0.0f, 1.0f );
+ }
+ m_AnimOverlay[iLayer].m_flCycle = flCycle;
+ m_AnimOverlay[iLayer].m_flPrevCycle = flPrevCycle;
+ m_AnimOverlay[iLayer].m_flLastEventCheck = flLastEventCheck;
+ m_AnimOverlay[iLayer].MarkActive( );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
float CBaseAnimatingOverlay::GetLayerCycle( int iLayer )
{
if (!IsValidLayer( iLayer ))
diff --git a/mp/src/game/server/BaseAnimatingOverlay.h b/mp/src/game/server/BaseAnimatingOverlay.h
index ac112cbd..5184eac3 100644
--- a/mp/src/game/server/BaseAnimatingOverlay.h
+++ b/mp/src/game/server/BaseAnimatingOverlay.h
@@ -165,6 +165,7 @@ public:
void SetLayerCycle( int iLayer, float flCycle );
void SetLayerCycle( int iLayer, float flCycle, float flPrevCycle );
+ void SetLayerCycle( int iLayer, float flCycle, float flPrevCycle, float flLastEventCheck );
float GetLayerCycle( int iLayer );
void SetLayerPlaybackRate( int iLayer, float flPlaybackRate );
diff --git a/mp/src/game/server/CommentarySystem.cpp b/mp/src/game/server/CommentarySystem.cpp
index f846a029..677b4d84 100644
--- a/mp/src/game/server/CommentarySystem.cpp
+++ b/mp/src/game/server/CommentarySystem.cpp
@@ -839,7 +839,7 @@ void CC_CommentaryChanged( IConVar *pConVar, const char *pOldString, float flOld
g_CommentarySystem.SetCommentaryMode( var.GetBool() );
}
}
-ConVar commentary("commentary", "0", FCVAR_ARCHIVE | FCVAR_ARCHIVE_XBOX, "Desired commentary mode state.", CC_CommentaryChanged );
+ConVar commentary( "commentary", "0", FCVAR_NONE, "Desired commentary mode state.", CC_CommentaryChanged );
//-----------------------------------------------------------------------------
// Purpose: We need to revert back any convar changes that are made by the
diff --git a/mp/src/game/server/GameStats_BasicStatsFunctions.cpp b/mp/src/game/server/GameStats_BasicStatsFunctions.cpp
index 5656b6b7..47e3de77 100644
--- a/mp/src/game/server/GameStats_BasicStatsFunctions.cpp
+++ b/mp/src/game/server/GameStats_BasicStatsFunctions.cpp
@@ -155,7 +155,7 @@ bool BasicGameStats_t::ParseFromBuffer( CUtlBuffer& buf, int iBufferStatsVersion
for ( int i = 0; i < c; ++i )
{
char mapname[ 256 ];
- buf.GetString( mapname, sizeof( mapname ) );
+ buf.GetString( mapname );
BasicGameStatsRecord_t *rec = FindOrAddRecordForMap( mapname );
bool valid= rec->ParseFromBuffer( buf, iBufferStatsVersion );
diff --git a/mp/src/game/server/ai_activity.cpp b/mp/src/game/server/ai_activity.cpp
index e7ba1761..3f5b5b49 100644
--- a/mp/src/game/server/ai_activity.cpp
+++ b/mp/src/game/server/ai_activity.cpp
@@ -1686,6 +1686,11 @@ void CAI_BaseNPC::InitDefaultActivitySR(void)
ADD_ACTIVITY_TO_SR( ACT_MP_ATTACK_SWIM_GRENADE_ITEM2 );
ADD_ACTIVITY_TO_SR( ACT_MP_ATTACK_AIRWALK_GRENADE_ITEM2 );
+ // Passtime
+ ADD_ACTIVITY_TO_SR( ACT_MP_STAND_PASSTIME );
+ ADD_ACTIVITY_TO_SR( ACT_MP_RUN_PASSTIME );
+ ADD_ACTIVITY_TO_SR( ACT_MP_CROUCHWALK_PASSTIME );
+
// Flinches
ADD_ACTIVITY_TO_SR( ACT_MP_GESTURE_FLINCH );
ADD_ACTIVITY_TO_SR( ACT_MP_GESTURE_FLINCH_PRIMARY );
@@ -1826,6 +1831,7 @@ void CAI_BaseNPC::InitDefaultActivitySR(void)
ADD_ACTIVITY_TO_SR( ACT_MP_DOUBLEJUMP_CROUCH_ITEM1 );
ADD_ACTIVITY_TO_SR( ACT_MP_DOUBLEJUMP_CROUCH_ITEM2 );
ADD_ACTIVITY_TO_SR( ACT_MP_DOUBLEJUMP_CROUCH_LOSERSTATE );
+ ADD_ACTIVITY_TO_SR( ACT_MP_DOUBLEJUMP_CROUCH_PASSTIME );
ADD_ACTIVITY_TO_SR( ACT_MP_GESTURE_VC_HANDMOUTH );
ADD_ACTIVITY_TO_SR( ACT_MP_GESTURE_VC_FINGERPOINT );
@@ -1887,6 +1893,11 @@ void CAI_BaseNPC::InitDefaultActivitySR(void)
ADD_ACTIVITY_TO_SR( ACT_MP_STUN_MIDDLE );
ADD_ACTIVITY_TO_SR( ACT_MP_STUN_END );
+ ADD_ACTIVITY_TO_SR( ACT_MP_PASSTIME_THROW_BEGIN );
+ ADD_ACTIVITY_TO_SR( ACT_MP_PASSTIME_THROW_MIDDLE );
+ ADD_ACTIVITY_TO_SR( ACT_MP_PASSTIME_THROW_END );
+ ADD_ACTIVITY_TO_SR( ACT_MP_PASSTIME_THROW_CANCEL );
+
ADD_ACTIVITY_TO_SR( ACT_VM_UNUSABLE );
ADD_ACTIVITY_TO_SR( ACT_VM_UNUSABLE_TO_USABLE );
ADD_ACTIVITY_TO_SR( ACT_VM_USABLE_TO_UNUSABLE );
@@ -2186,4 +2197,40 @@ void CAI_BaseNPC::InitDefaultActivitySR(void)
ADD_ACTIVITY_TO_SR( ACT_BOT_GESTURE_FLINCH );
ADD_ACTIVITY_TO_SR( ACT_BOT_PANIC_START );
ADD_ACTIVITY_TO_SR( ACT_BOT_PANIC_END );
+
+ ADD_ACTIVITY_TO_SR( ACT_ENGINEER_REVOLVER_DRAW );
+ ADD_ACTIVITY_TO_SR( ACT_ENGINEER_REVOLVER_IDLE );
+ ADD_ACTIVITY_TO_SR( ACT_ENGINEER_REVOLVER_PRIMARYATTACK );
+ ADD_ACTIVITY_TO_SR( ACT_ENGINEER_REVOLVER_RELOAD );
+
+ ADD_ACTIVITY_TO_SR( ACT_KART_IDLE );
+ ADD_ACTIVITY_TO_SR( ACT_KART_ACTION_SHOOT );
+ ADD_ACTIVITY_TO_SR( ACT_KART_ACTION_DASH );
+ ADD_ACTIVITY_TO_SR( ACT_KART_JUMP_START );
+ ADD_ACTIVITY_TO_SR( ACT_KART_JUMP_FLOAT );
+ ADD_ACTIVITY_TO_SR( ACT_KART_JUMP_LAND );
+ ADD_ACTIVITY_TO_SR( ACT_KART_IMPACT );
+ ADD_ACTIVITY_TO_SR( ACT_KART_IMPACT_BIG );
+ ADD_ACTIVITY_TO_SR( ACT_KART_GESTURE_POSITIVE );
+ ADD_ACTIVITY_TO_SR( ACT_KART_GESTURE_NEGATIVE );
+
+ ADD_ACTIVITY_TO_SR( ACT_GRAPPLE_DRAW );
+ ADD_ACTIVITY_TO_SR( ACT_GRAPPLE_IDLE );
+ ADD_ACTIVITY_TO_SR( ACT_GRAPPLE_FIRE_START );
+ ADD_ACTIVITY_TO_SR( ACT_GRAPPLE_FIRE_IDLE );
+ ADD_ACTIVITY_TO_SR( ACT_GRAPPLE_PULL_START );
+ ADD_ACTIVITY_TO_SR( ACT_GRAPPLE_PULL_IDLE );
+ ADD_ACTIVITY_TO_SR( ACT_GRAPPLE_PULL_END );
+
+ ADD_ACTIVITY_TO_SR( ACT_PRIMARY_VM_INSPECT_START );
+ ADD_ACTIVITY_TO_SR( ACT_PRIMARY_VM_INSPECT_IDLE );
+ ADD_ACTIVITY_TO_SR( ACT_PRIMARY_VM_INSPECT_END );
+
+ ADD_ACTIVITY_TO_SR( ACT_SECONDARY_VM_INSPECT_START );
+ ADD_ACTIVITY_TO_SR( ACT_SECONDARY_VM_INSPECT_IDLE );
+ ADD_ACTIVITY_TO_SR( ACT_SECONDARY_VM_INSPECT_END );
+
+ ADD_ACTIVITY_TO_SR( ACT_MELEE_VM_INSPECT_START );
+ ADD_ACTIVITY_TO_SR( ACT_MELEE_VM_INSPECT_IDLE );
+ ADD_ACTIVITY_TO_SR( ACT_MELEE_VM_INSPECT_END );
}
diff --git a/mp/src/game/server/baseanimating.cpp b/mp/src/game/server/baseanimating.cpp
index 34bf6378..9999c496 100644
--- a/mp/src/game/server/baseanimating.cpp
+++ b/mp/src/game/server/baseanimating.cpp
@@ -470,7 +470,6 @@ void CBaseAnimating::StudioFrameAdvanceManual( float flInterval )
if ( !pStudioHdr )
return;
- UpdateModelScale();
m_flAnimTime = gpGlobals->curtime;
m_flPrevAnimTime = m_flAnimTime - flInterval;
float flCycleRate = GetSequenceCycleRate( pStudioHdr, GetSequence() ) * m_flPlaybackRate;
@@ -490,8 +489,6 @@ void CBaseAnimating::StudioFrameAdvance()
return;
}
- UpdateModelScale();
-
if ( !m_flPrevAnimTime )
{
m_flPrevAnimTime = m_flAnimTime;
@@ -631,7 +628,7 @@ void CBaseAnimating::InputSetModelScale( inputdata_t &inputdata )
int CBaseAnimating::SelectWeightedSequence ( Activity activity )
{
Assert( activity != ACT_INVALID );
- Assert( GetModelPtr() );
+ AssertMsg( GetModelPtr(), "GetModelPtr NULL. %s", STRING(GetEntityName()) ? STRING(GetEntityName()) : "" );
return ::SelectWeightedSequence( GetModelPtr(), activity, GetSequence() );
}
@@ -639,16 +636,23 @@ int CBaseAnimating::SelectWeightedSequence ( Activity activity )
int CBaseAnimating::SelectWeightedSequence ( Activity activity, int curSequence )
{
Assert( activity != ACT_INVALID );
- Assert( GetModelPtr() );
+ AssertMsg( GetModelPtr(), "GetModelPtr NULL. %s", STRING(GetEntityName()) ? STRING(GetEntityName()) : "" );
return ::SelectWeightedSequence( GetModelPtr(), activity, curSequence );
}
+int CBaseAnimating::SelectWeightedSequenceFromModifiers( Activity activity, CUtlSymbol *pActivityModifiers, int iModifierCount )
+{
+ Assert( activity != ACT_INVALID );
+ AssertMsg( GetModelPtr(), "GetModelPtr NULL. %s", STRING(GetEntityName()) ? STRING(GetEntityName()) : "" );
+ return GetModelPtr()->SelectWeightedSequenceFromModifiers( activity, pActivityModifiers, iModifierCount );
+}
+
//=========================================================
// ResetActivityIndexes
//=========================================================
void CBaseAnimating::ResetActivityIndexes ( void )
{
- Assert( GetModelPtr() );
+ AssertMsg( GetModelPtr(), "GetModelPtr NULL. %s", STRING(GetEntityName()) ? STRING(GetEntityName()) : "" );
::ResetActivityIndexes( GetModelPtr() );
}
@@ -657,7 +661,7 @@ void CBaseAnimating::ResetActivityIndexes ( void )
//=========================================================
void CBaseAnimating::ResetEventIndexes ( void )
{
- Assert( GetModelPtr() );
+ AssertMsg( GetModelPtr(), "GetModelPtr NULL. %s", STRING(GetEntityName()) ? STRING(GetEntityName()) : "" );
::ResetEventIndexes( GetModelPtr() );
}
@@ -669,7 +673,7 @@ void CBaseAnimating::ResetEventIndexes ( void )
//=========================================================
int CBaseAnimating::SelectHeaviestSequence ( Activity activity )
{
- Assert( GetModelPtr() );
+ AssertMsg( GetModelPtr(), "GetModelPtr NULL. %s", STRING(GetEntityName()) ? STRING(GetEntityName()) : "" );
return ::SelectHeaviestSequence( GetModelPtr(), activity );
}
@@ -681,7 +685,7 @@ int CBaseAnimating::SelectHeaviestSequence ( Activity activity )
//-----------------------------------------------------------------------------
int CBaseAnimating::LookupActivity( const char *label )
{
- Assert( GetModelPtr() );
+ AssertMsg( GetModelPtr(), "GetModelPtr NULL. %s", STRING(GetEntityName()) ? STRING(GetEntityName()) : "" );
return ::LookupActivity( GetModelPtr(), label );
}
@@ -689,7 +693,7 @@ int CBaseAnimating::LookupActivity( const char *label )
//=========================================================
int CBaseAnimating::LookupSequence( const char *label )
{
- Assert( GetModelPtr() );
+ AssertMsg( GetModelPtr(), "GetModelPtr NULL. %s", STRING(GetEntityName()) ? STRING(GetEntityName()) : "" );
return ::LookupSequence( GetModelPtr(), label );
}
@@ -729,7 +733,7 @@ float CBaseAnimating::GetSequenceMoveYaw( int iSequence )
{
Vector vecReturn;
- Assert( GetModelPtr() );
+ AssertMsg( GetModelPtr(), "GetModelPtr NULL. %s", STRING(GetEntityName()) ? STRING(GetEntityName()) : "" );
::GetSequenceLinearMotion( GetModelPtr(), iSequence, GetPoseParameterArray(), &vecReturn );
if (vecReturn.Length() > 0)
@@ -765,7 +769,7 @@ float CBaseAnimating::GetSequenceMoveDist( CStudioHdr *pStudioHdr, int iSequence
//-----------------------------------------------------------------------------
void CBaseAnimating::GetSequenceLinearMotion( int iSequence, Vector *pVec )
{
- Assert( GetModelPtr() );
+ AssertMsg( GetModelPtr(), "GetModelPtr NULL. %s", STRING(GetEntityName()) ? STRING(GetEntityName()) : "" );
::GetSequenceLinearMotion( GetModelPtr(), iSequence, GetPoseParameterArray(), pVec );
}
@@ -912,7 +916,7 @@ void CBaseAnimating::ResetSequenceInfo ( )
//=========================================================
bool CBaseAnimating::IsValidSequence( int iSequence )
{
- Assert( GetModelPtr() );
+ AssertMsg( GetModelPtr(), "GetModelPtr NULL. %s", STRING(GetEntityName()) ? STRING(GetEntityName()) : "" );
CStudioHdr* pstudiohdr = GetModelPtr( );
if (iSequence < 0 || iSequence >= pstudiohdr->GetNumSeq())
{
@@ -1779,7 +1783,7 @@ void CBaseAnimating::SetupBones( matrix3x4_t *pBoneToWorld, int boneMask )
MDLCACHE_CRITICAL_SECTION();
- Assert( GetModelPtr() );
+ AssertMsg( GetModelPtr(), "GetModelPtr NULL. %s", STRING(GetEntityName()) ? STRING(GetEntityName()) : "" );
CStudioHdr *pStudioHdr = GetModelPtr( );
@@ -2087,7 +2091,7 @@ void CBaseAnimating::GetEyeballs( Vector &origin, QAngle &angles )
//=========================================================
int CBaseAnimating::FindTransitionSequence( int iCurrentSequence, int iGoalSequence, int *piDir )
{
- Assert( GetModelPtr() );
+ AssertMsg( GetModelPtr(), "GetModelPtr NULL. %s", STRING(GetEntityName()) ? STRING(GetEntityName()) : "" );
if (piDir == NULL)
{
@@ -2136,7 +2140,7 @@ void CBaseAnimating::SetBodygroup( int iGroup, int iValue )
{
// SetBodygroup is not supported on pending dynamic models. Wait for it to load!
// XXX TODO we could buffer up the group and value if we really needed to. -henryg
- Assert( GetModelPtr() );
+ AssertMsg( GetModelPtr(), "GetModelPtr NULL. %s", STRING(GetEntityName()) ? STRING(GetEntityName()) : "" );
int newBody = m_nBody;
::SetBodygroup( GetModelPtr( ), newBody, iGroup, iValue );
m_nBody = newBody;
@@ -2735,7 +2739,7 @@ void CBaseAnimating::InitBoneControllers ( void ) // FIXME: rename
//=========================================================
float CBaseAnimating::SetBoneController ( int iController, float flValue )
{
- Assert( GetModelPtr() );
+ AssertMsg( GetModelPtr(), "GetModelPtr NULL. %s", STRING(GetEntityName()) ? STRING(GetEntityName()) : "" );
CStudioHdr *pmodel = (CStudioHdr*)GetModelPtr();
@@ -2752,7 +2756,7 @@ float CBaseAnimating::SetBoneController ( int iController, float flValue )
//=========================================================
float CBaseAnimating::GetBoneController ( int iController )
{
- Assert( GetModelPtr() );
+ AssertMsg( GetModelPtr(), "GetModelPtr NULL. %s", STRING(GetEntityName()) ? STRING(GetEntityName()) : "" );
CStudioHdr *pmodel = (CStudioHdr*)GetModelPtr();
@@ -2943,7 +2947,7 @@ void CBaseAnimating::SetHitboxSet( int setnum )
//-----------------------------------------------------------------------------
void CBaseAnimating::SetHitboxSetByName( const char *setname )
{
- Assert( GetModelPtr() );
+ AssertMsg( GetModelPtr(), "GetModelPtr NULL. %s", STRING(GetEntityName()) ? STRING(GetEntityName()) : "" );
m_nHitboxSet = FindHitboxSetByName( GetModelPtr(), setname );
}
@@ -2962,7 +2966,7 @@ int CBaseAnimating::GetHitboxSet( void )
//-----------------------------------------------------------------------------
const char *CBaseAnimating::GetHitboxSetName( void )
{
- Assert( GetModelPtr() );
+ AssertMsg( GetModelPtr(), "GetModelPtr NULL. %s", STRING(GetEntityName()) ? STRING(GetEntityName()) : "" );
return ::GetHitboxSetName( GetModelPtr(), m_nHitboxSet );
}
@@ -2972,7 +2976,7 @@ const char *CBaseAnimating::GetHitboxSetName( void )
//-----------------------------------------------------------------------------
int CBaseAnimating::GetHitboxSetCount( void )
{
- Assert( GetModelPtr() );
+ AssertMsg( GetModelPtr(), "GetModelPtr NULL. %s", STRING(GetEntityName()) ? STRING(GetEntityName()) : "" );
return ::GetHitboxSetCount( GetModelPtr() );
}
@@ -3303,6 +3307,7 @@ void CBaseAnimating::SetModelScale( float scale, float change_duration /*= 0.0f*
mvs->m_flModelScaleGoal = scale;
mvs->m_flModelScaleStartTime = gpGlobals->curtime;
mvs->m_flModelScaleFinishTime = mvs->m_flModelScaleStartTime + change_duration;
+ SetContextThink( &CBaseAnimating::UpdateModelScale, gpGlobals->curtime, "UpdateModelScaleThink" );
}
else
{
@@ -3341,6 +3346,11 @@ void CBaseAnimating::UpdateModelScale()
}
RefreshCollisionBounds();
+
+ if ( frac < 1.f )
+ {
+ SetContextThink( &CBaseAnimating::UpdateModelScale, gpGlobals->curtime, "UpdateModelScaleThink" );
+ }
}
void CBaseAnimating::RefreshCollisionBounds( void )
diff --git a/mp/src/game/server/baseanimating.h b/mp/src/game/server/baseanimating.h
index 75300e8e..0550683e 100644
--- a/mp/src/game/server/baseanimating.h
+++ b/mp/src/game/server/baseanimating.h
@@ -108,6 +108,7 @@ public:
void ResetEventIndexes ( void );
int SelectWeightedSequence ( Activity activity );
int SelectWeightedSequence ( Activity activity, int curSequence );
+ int SelectWeightedSequenceFromModifiers( Activity activity, CUtlSymbol *pActivityModifiers, int iModifierCount );
int SelectHeaviestSequence ( Activity activity );
int LookupActivity( const char *label );
int LookupSequence ( const char *label );
@@ -436,10 +437,14 @@ inline CStudioHdr *CBaseAnimating::GetModelPtr( void )
return NULL;
#ifdef _DEBUG
- // GetModelPtr() is often called before OnNewModel() so go ahead and set it up first chance.
- static IDataCacheSection *pModelCache = datacache->FindSection( "ModelData" );
- AssertOnce( pModelCache->IsFrameLocking() );
+ if ( !HushAsserts() )
+ {
+ // GetModelPtr() is often called before OnNewModel() so go ahead and set it up first chance.
+ static IDataCacheSection *pModelCache = datacache->FindSection( "ModelData" );
+ AssertOnce( pModelCache->IsFrameLocking() );
+ }
#endif
+
if ( !m_pStudioHdr && GetModel() )
{
LockStudioHdr();
diff --git a/mp/src/game/server/basecombatcharacter.cpp b/mp/src/game/server/basecombatcharacter.cpp
index 9f6a8674..71d6c844 100644
--- a/mp/src/game/server/basecombatcharacter.cpp
+++ b/mp/src/game/server/basecombatcharacter.cpp
@@ -2280,8 +2280,8 @@ CBaseCombatWeapon *CBaseCombatCharacter::Weapon_GetWpnForAmmo( int iAmmoIndex )
//-----------------------------------------------------------------------------
bool CBaseCombatCharacter::Weapon_CanUse( CBaseCombatWeapon *pWeapon )
{
- acttable_t *pTable = pWeapon->ActivityList();
- int actCount = pWeapon->ActivityListCount();
+ int actCount = 0;
+ acttable_t *pTable = pWeapon->ActivityList( actCount );
if( actCount < 1 )
{
diff --git a/mp/src/game/server/baseentity.cpp b/mp/src/game/server/baseentity.cpp
index 7a7a7e6c..9bd525a4 100644
--- a/mp/src/game/server/baseentity.cpp
+++ b/mp/src/game/server/baseentity.cpp
@@ -86,6 +86,7 @@ bool CBaseEntity::sm_bDisableTouchFuncs = false; // Disables PhysicsTouch and Ph
bool CBaseEntity::sm_bAccurateTriggerBboxChecks = true; // set to false for legacy behavior in ep1
int CBaseEntity::m_nPredictionRandomSeed = -1;
+int CBaseEntity::m_nPredictionRandomSeedServer = -1;
CBasePlayer *CBaseEntity::m_pPredictionPlayer = NULL;
// Used to make sure nobody calls UpdateTransmitState directly.
@@ -1440,10 +1441,10 @@ int CBaseEntity::OnTakeDamage( const CTakeDamageInfo &info )
//-----------------------------------------------------------------------------
// Purpose: Scale damage done and call OnTakeDamage
//-----------------------------------------------------------------------------
-void CBaseEntity::TakeDamage( const CTakeDamageInfo &inputInfo )
+int CBaseEntity::TakeDamage( const CTakeDamageInfo &inputInfo )
{
if ( !g_pGameRules )
- return;
+ return 0;
bool bHasPhysicsForceDamage = !g_pGameRules->Damage_NoPhysicsForce( inputInfo.GetDamageType() );
if ( bHasPhysicsForceDamage && inputInfo.GetDamageType() != DMG_GENERIC )
@@ -1475,12 +1476,12 @@ void CBaseEntity::TakeDamage( const CTakeDamageInfo &inputInfo )
// Make sure our damage filter allows the damage.
if ( !PassesDamageFilter( inputInfo ))
{
- return;
+ return 0;
}
if( !g_pGameRules->AllowDamage(this, inputInfo) )
{
- return;
+ return 0;
}
if ( PhysIsInCallback() )
@@ -1502,8 +1503,9 @@ void CBaseEntity::TakeDamage( const CTakeDamageInfo &inputInfo )
//Msg("%s took %.2f Damage, at %.2f\n", GetClassname(), info.GetDamage(), gpGlobals->curtime );
- OnTakeDamage( info );
+ return OnTakeDamage( info );
}
+ return 0;
}
//-----------------------------------------------------------------------------
@@ -6089,7 +6091,7 @@ void CBaseEntity::SetLocalAngles( const QAngle& angles )
{
Warning( "Bad SetLocalAngles(%f,%f,%f) on %s\n", angles.x, angles.y, angles.z, GetDebugName() );
}
- Assert( false );
+ AssertMsg( false, "Bad SetLocalAngles(%f,%f,%f) on %s\n", angles.x, angles.y, angles.z, GetDebugName() );
return;
}
diff --git a/mp/src/game/server/baseentity.h b/mp/src/game/server/baseentity.h
index 7261e0a8..42c0cdf2 100644
--- a/mp/src/game/server/baseentity.h
+++ b/mp/src/game/server/baseentity.h
@@ -904,7 +904,7 @@ public:
virtual int OnTakeDamage( const CTakeDamageInfo &info );
// This is what you should call to apply damage to an entity.
- void TakeDamage( const CTakeDamageInfo &info );
+ int TakeDamage( const CTakeDamageInfo &info );
virtual void AdjustDamageDirection( const CTakeDamageInfo &info, Vector &dir, CBaseEntity *pEnt ) {}
virtual int TakeHealth( float flHealth, int bitsDamageType );
@@ -1748,6 +1748,7 @@ private:
// randon number generators to spit out the same random numbers on both sides for a particular
// usercmd input.
static int m_nPredictionRandomSeed;
+ static int m_nPredictionRandomSeedServer;
static CBasePlayer *m_pPredictionPlayer;
// FIXME: Make hierarchy a member of CBaseEntity
@@ -1761,7 +1762,7 @@ private:
public:
// Accessors for above
- static int GetPredictionRandomSeed( void );
+ static int GetPredictionRandomSeed( bool bUseUnSyncedServerPlatTime = false );
static void SetPredictionRandomSeed( const CUserCmd *cmd );
static CBasePlayer *GetPredictionPlayer( void );
static void SetPredictionPlayer( CBasePlayer *player );
@@ -1799,6 +1800,8 @@ public:
{
return s_bAbsQueriesValid;
}
+
+ virtual bool ShouldBlockNav() const { return true; }
};
// Send tables exposed in this module.
diff --git a/mp/src/game/server/baseflex.cpp b/mp/src/game/server/baseflex.cpp
index 5c435d73..b760ed54 100644
--- a/mp/src/game/server/baseflex.cpp
+++ b/mp/src/game/server/baseflex.cpp
@@ -113,7 +113,7 @@ CBaseFlex::CBaseFlex( void ) :
CBaseFlex::~CBaseFlex( void )
{
m_LocalToGlobal.RemoveAll();
- Assert( m_SceneEvents.Count() == 0 );
+ AssertMsg( m_SceneEvents.Count() == 0, "m_ScenesEvent.Count != 0: %d", m_SceneEvents.Count() );
}
void CBaseFlex::SetModel( const char *szModelName )
@@ -508,7 +508,7 @@ bool CBaseFlex::HandleStartSequenceSceneEvent( CSceneEventInfo *info, CChoreoSce
float seq_duration = SequenceDuration( info->m_nSequence );
float flCycle = dt / seq_duration;
flCycle = flCycle - (int)flCycle; // loop
- SetLayerCycle( info->m_iLayer, flCycle, flCycle );
+ SetLayerCycle( info->m_iLayer, flCycle, flCycle, 0.f );
SetLayerPlaybackRate( info->m_iLayer, 0.0 );
}
diff --git a/mp/src/game/server/client.cpp b/mp/src/game/server/client.cpp
index f500ad5e..eced1df1 100644
--- a/mp/src/game/server/client.cpp
+++ b/mp/src/game/server/client.cpp
@@ -57,6 +57,60 @@ extern bool IsInCommentaryMode( void );
ConVar *sv_cheats = NULL;
+enum eAllowPointServerCommand {
+ eAllowNever,
+ eAllowOfficial,
+ eAllowAlways
+};
+
+#ifdef TF_DLL
+// The default value here should match the default of the convar
+eAllowPointServerCommand sAllowPointServerCommand = eAllowOfficial;
+#else
+eAllowPointServerCommand sAllowPointServerCommand = eAllowAlways;
+#endif // TF_DLL
+
+void sv_allow_point_servercommand_changed( IConVar *pConVar, const char *pOldString, float flOldValue )
+{
+ ConVarRef var( pConVar );
+ if ( !var.IsValid() )
+ {
+ return;
+ }
+
+ const char *pNewValue = var.GetString();
+ if ( V_strcasecmp ( pNewValue, "always" ) == 0 )
+ {
+ sAllowPointServerCommand = eAllowAlways;
+ }
+#ifdef TF_DLL
+ else if ( V_strcasecmp ( pNewValue, "official" ) == 0 )
+ {
+ sAllowPointServerCommand = eAllowOfficial;
+ }
+#endif // TF_DLL
+ else
+ {
+ sAllowPointServerCommand = eAllowNever;
+ }
+}
+
+ConVar sv_allow_point_servercommand ( "sv_allow_point_servercommand",
+#ifdef TF_DLL
+ // The default value here should match the default of the convar
+ "official",
+#else
+ // Other games may use this in their official maps, and only TF exposes IsValveMap() currently
+ "always",
+#endif // TF_DLL
+ FCVAR_NONE,
+ "Allow use of point_servercommand entities in map. Potentially dangerous for untrusted maps.\n"
+ " disallow : Always disallow\n"
+#ifdef TF_DLL
+ " official : Allowed for valve maps only\n"
+#endif // TF_DLL
+ " always : Allow for all maps", sv_allow_point_servercommand_changed );
+
void ClientKill( edict_t *pEdict, const Vector &vecForce, bool bExplode = false )
{
CBasePlayer *pPlayer = static_cast<CBasePlayer*>( GetContainingEntity( pEdict ) );
@@ -569,7 +623,22 @@ void CPointServerCommand::InputCommand( inputdata_t& inputdata )
if ( !inputdata.value.String()[0] )
return;
- engine->ServerCommand( UTIL_VarArgs( "%s\n", inputdata.value.String() ) );
+ bool bAllowed = ( sAllowPointServerCommand == eAllowAlways );
+#ifdef TF_DLL
+ if ( sAllowPointServerCommand == eAllowOfficial )
+ {
+ bAllowed = TFGameRules() && TFGameRules()->IsValveMap();
+ }
+#endif // TF_DLL
+
+ if ( bAllowed )
+ {
+ engine->ServerCommand( UTIL_VarArgs( "%s\n", inputdata.value.String() ) );
+ }
+ else
+ {
+ Warning( "point_servercommand usage blocked by sv_allow_point_servercommand setting\n" );
+ }
}
BEGIN_DATADESC( CPointServerCommand )
@@ -600,7 +669,7 @@ void CC_DrawLine( const CCommand &args )
static ConCommand drawline("drawline", CC_DrawLine, "Draws line between two 3D Points.\n\tGreen if no collision\n\tRed is collides with something\n\tArguments: x1 y1 z1 x2 y2 z2", FCVAR_CHEAT);
//------------------------------------------------------------------------------
-// Purpose : Draw a cross at a points.
+// Purpose : Draw a cross at a points.
// Input :
// Output :
//------------------------------------------------------------------------------
diff --git a/mp/src/game/server/doors.h b/mp/src/game/server/doors.h
index 7658482c..9b485fe2 100644
--- a/mp/src/game/server/doors.h
+++ b/mp/src/game/server/doors.h
@@ -150,6 +150,8 @@ public:
bool ShouldLoopMoveSound( void ) { return m_bLoopMoveSound; }
bool m_bLoopMoveSound; // Move sound loops until stopped
+ virtual bool ShouldBlockNav() const OVERRIDE { return false; }
+
private:
void ChainUse( void ); ///< Chains +use on through to m_ChainTarget
void ChainTouch( CBaseEntity *pOther ); ///< Chains touch on through to m_ChainTarget
diff --git a/mp/src/game/server/episodic/ep2_gamestats.h b/mp/src/game/server/episodic/ep2_gamestats.h
index cc36301c..cef1f839 100644
--- a/mp/src/game/server/episodic/ep2_gamestats.h
+++ b/mp/src/game/server/episodic/ep2_gamestats.h
@@ -215,7 +215,7 @@ public:
{
Ep2LevelStats_t::EntityDeathsLump_t data;
char npcName[ 512 ];
- LoadBuffer.GetString( npcName, sizeof( npcName ) );
+ LoadBuffer.GetString( npcName );
LoadBuffer.Get( &data, sizeof( data ) );
pItem->m_dictEntityDeaths.Insert( npcName, data );
}
@@ -229,7 +229,7 @@ public:
{
Ep2LevelStats_t::WeaponLump_t data;
char weaponName[ 512 ];
- LoadBuffer.GetString( weaponName, sizeof( weaponName ) );
+ LoadBuffer.GetString( weaponName );
LoadBuffer.Get( &data, sizeof( data ) );
pItem->m_dictWeapons.Insert( weaponName, data );
}
@@ -240,7 +240,7 @@ public:
Assert( pItem );
Ep2LevelStats_t::SaveGameInfo_t *info = &pItem->m_SaveGameInfo;
char sz[ 512 ];
- LoadBuffer.GetString( sz, sizeof( sz ) );
+ LoadBuffer.GetString( sz );
info->m_sCurrentSaveFile = sz;
info->m_nCurrentSaveFileTime = LoadBuffer.GetInt();
int c = LoadBuffer.GetInt();
@@ -277,7 +277,7 @@ public:
{
Ep2LevelStats_t::GenericStatsLump_t data;
char pchStatName[ 512 ];
- LoadBuffer.GetString( pchStatName, sizeof( pchStatName ) );
+ LoadBuffer.GetString( pchStatName );
LoadBuffer.Get( &data, sizeof( data ) );
pItem->m_dictGeneric.Insert( pchStatName, data );
}
diff --git a/mp/src/game/server/func_break.cpp b/mp/src/game/server/func_break.cpp
index d0b815e2..e7043ea9 100644
--- a/mp/src/game/server/func_break.cpp
+++ b/mp/src/game/server/func_break.cpp
@@ -817,8 +817,6 @@ void CBreakable::VPhysicsCollision( int index, gamevcollisionevent_t *pEvent )
//-----------------------------------------------------------------------------
int CBreakable::OnTakeDamage( const CTakeDamageInfo &info )
{
- Vector vecTemp;
-
CTakeDamageInfo subInfo = info;
// If attacker can't do at least the min required damage to us, don't take any damage from them
@@ -832,8 +830,6 @@ int CBreakable::OnTakeDamage( const CTakeDamageInfo &info )
return 1;
}
- vecTemp = subInfo.GetInflictor()->GetAbsOrigin() - WorldSpaceCenter();
-
if (!IsBreakable())
return 0;
diff --git a/mp/src/game/server/gameinterface.cpp b/mp/src/game/server/gameinterface.cpp
index b20daf08..f6bbebb4 100644
--- a/mp/src/game/server/gameinterface.cpp
+++ b/mp/src/game/server/gameinterface.cpp
@@ -99,6 +99,7 @@
#include "tf_gamerules.h"
#include "tf_lobby.h"
#include "player_vs_environment/tf_population_manager.h"
+#include "workshop/maps_workshop.h"
extern ConVar tf_mm_trusted;
extern ConVar tf_mm_servermode;
@@ -559,11 +560,11 @@ void DrawAllDebugOverlays( void )
CServerGameDLL g_ServerGameDLL;
// INTERFACEVERSION_SERVERGAMEDLL_VERSION_8 is compatible with the latest since we're only adding things to the end, so expose that as well.
-EXPOSE_SINGLE_INTERFACE_GLOBALVAR(CServerGameDLL, IServerGameDLL008, INTERFACEVERSION_SERVERGAMEDLL_VERSION_8, g_ServerGameDLL );
+//EXPOSE_SINGLE_INTERFACE_GLOBALVAR(CServerGameDLL, IServerGameDLL008, INTERFACEVERSION_SERVERGAMEDLL_VERSION_8, g_ServerGameDLL );
EXPOSE_SINGLE_INTERFACE_GLOBALVAR(CServerGameDLL, IServerGameDLL, INTERFACEVERSION_SERVERGAMEDLL, g_ServerGameDLL);
// When bumping the version to this interface, check that our assumption is still valid and expose the older version in the same way
-COMPILE_TIME_ASSERT( INTERFACEVERSION_SERVERGAMEDLL_INT == 9 );
+COMPILE_TIME_ASSERT( INTERFACEVERSION_SERVERGAMEDLL_INT == 10 );
bool CServerGameDLL::DLLInit( CreateInterfaceFn appSystemFactory,
CreateInterfaceFn physicsFactory, CreateInterfaceFn fileSystemFactory,
@@ -1081,9 +1082,7 @@ bool g_bCheckForChainedActivate;
{ \
if ( bCheck ) \
{ \
- char msg[ 1024 ]; \
- Q_snprintf( msg, sizeof( msg ), "Entity (%i/%s/%s) failed to call base class Activate()\n", pClass->entindex(), pClass->GetClassname(), STRING( pClass->GetEntityName() ) ); \
- AssertMsg( g_bReceivedChainedActivate == true, msg ); \
+ AssertMsg( g_bReceivedChainedActivate, "Entity (%i/%s/%s) failed to call base class Activate()\n", pClass->entindex(), pClass->GetClassname(), STRING( pClass->GetEntityName() ) ); \
} \
g_bCheckForChainedActivate = false; \
}
@@ -1100,7 +1099,7 @@ void CServerGameDLL::ServerActivate( edict_t *pEdictList, int edictCount, int cl
if ( gEntList.ResetDeleteList() != 0 )
{
- Msg( "ERROR: Entity delete queue not empty on level start!\n" );
+ Msg( "%s", "ERROR: Entity delete queue not empty on level start!\n" );
}
for ( CBaseEntity *pClass = gEntList.FirstEnt(); pClass != NULL; pClass = gEntList.NextEnt(pClass) )
@@ -1150,6 +1149,7 @@ void CServerGameDLL::ServerActivate( edict_t *pEdictList, int edictCount, int cl
void CServerGameDLL::GameServerSteamAPIActivated( void )
{
#ifndef NO_STEAM
+ steamgameserverapicontext->Clear();
steamgameserverapicontext->Init();
if ( steamgameserverapicontext->SteamGameServer() && engine->IsDedicatedServer() )
{
@@ -1160,6 +1160,7 @@ void CServerGameDLL::GameServerSteamAPIActivated( void )
#ifdef TF_DLL
GCClientSystem()->GameServerActivate();
InventoryManager()->GameServerSteamAPIActivated();
+ TFMapsWorkshop()->GameServerSteamAPIActivated();
#endif
}
@@ -1937,6 +1938,52 @@ void CServerGameDLL::Status( void (*print) (const char *fmt, ...) )
}
//-----------------------------------------------------------------------------
+void CServerGameDLL::PrepareLevelResources( /* in/out */ char *pszMapName, size_t nMapNameSize,
+ /* in/out */ char *pszMapFile, size_t nMapFileSize )
+{
+#ifdef TF_DLL
+ TFMapsWorkshop()->PrepareLevelResources( pszMapName, nMapNameSize, pszMapFile, nMapFileSize );
+#endif // TF_DLL
+}
+
+//-----------------------------------------------------------------------------
+IServerGameDLL::ePrepareLevelResourcesResult
+CServerGameDLL::AsyncPrepareLevelResources( /* in/out */ char *pszMapName, size_t nMapNameSize,
+ /* in/out */ char *pszMapFile, size_t nMapFileSize,
+ float *flProgress /* = NULL */ )
+{
+#ifdef TF_DLL
+ return TFMapsWorkshop()->AsyncPrepareLevelResources( pszMapName, nMapNameSize, pszMapFile, nMapFileSize, flProgress );
+#endif // TF_DLL
+
+ if ( flProgress )
+ {
+ *flProgress = 1.f;
+ }
+ return IServerGameDLL::ePrepareLevelResources_Prepared;
+}
+
+//-----------------------------------------------------------------------------
+IServerGameDLL::eCanProvideLevelResult CServerGameDLL::CanProvideLevel( /* in/out */ char *pMapName, int nMapNameMax )
+{
+#ifdef TF_DLL
+ return TFMapsWorkshop()->OnCanProvideLevel( pMapName, nMapNameMax );
+#endif // TF_DLL
+ return IServerGameDLL::eCanProvideLevel_CannotProvide;
+}
+
+//-----------------------------------------------------------------------------
+bool CServerGameDLL::IsManualMapChangeOkay( const char **pszReason )
+{
+ if ( GameRules() )
+ {
+ return GameRules()->IsManualMapChangeOkay( pszReason );
+ }
+
+ return true;
+}
+
+//-----------------------------------------------------------------------------
// Purpose: Called during a transition, to build a map adjacency list
//-----------------------------------------------------------------------------
void CServerGameDLL::BuildAdjacentMapList( void )
@@ -2648,7 +2695,7 @@ void CServerGameClients::ClientActive( edict_t *pEdict, bool bLoadGame )
#if defined( TF_DLL )
Assert( pPlayer );
- if ( pPlayer && !pPlayer->IsFakeClient() )
+ if ( pPlayer && !pPlayer->IsFakeClient() && !pPlayer->IsHLTV() && !pPlayer->IsReplay() )
{
CSteamID steamID;
if ( pPlayer->GetSteamID( &steamID ) )
@@ -2657,7 +2704,10 @@ void CServerGameClients::ClientActive( edict_t *pEdict, bool bLoadGame )
}
else
{
- Log("WARNING: ClientActive, but we don't know his SteamID?\n");
+ if ( !pPlayer->IsReplay() && !pPlayer->IsHLTV() )
+ {
+ Log("WARNING: ClientActive, but we don't know his SteamID?\n");
+ }
}
}
#endif
@@ -2731,7 +2781,10 @@ void CServerGameClients::ClientDisconnect( edict_t *pEdict )
}
else
{
- Log("WARNING: ClientDisconnected, but we don't know his SteamID?\n");
+ if ( !player->IsReplay() && !player->IsHLTV() )
+ {
+ Log("WARNING: ClientDisconnected, but we don't know his SteamID?\n");
+ }
}
}
#endif
diff --git a/mp/src/game/server/gameinterface.h b/mp/src/game/server/gameinterface.h
index 91d6534c..3092d4f3 100644
--- a/mp/src/game/server/gameinterface.h
+++ b/mp/src/game/server/gameinterface.h
@@ -139,7 +139,19 @@ public:
virtual const char *GetServerBrowserGameData() OVERRIDE;
// Called to add output to the status command
- virtual void Status( void (*print) (const char *fmt, ...) );
+ virtual void Status( void (*print) (const char *fmt, ...) ) OVERRIDE;
+
+ virtual void PrepareLevelResources( /* in/out */ char *pszMapName, size_t nMapNameSize,
+ /* in/out */ char *pszMapFile, size_t nMapFileSize ) OVERRIDE;
+
+ virtual ePrepareLevelResourcesResult AsyncPrepareLevelResources( /* in/out */ char *pszMapName, size_t nMapNameSize,
+ /* in/out */ char *pszMapFile, size_t nMapFileSize,
+ float *flProgress = NULL ) OVERRIDE;
+
+ virtual eCanProvideLevelResult CanProvideLevel( /* in/out */ char *pMapName, int nMapNameMax ) OVERRIDE;
+
+ // Called to see if the game server is okay with a manual changelevel or map command
+ virtual bool IsManualMapChangeOkay( const char **pszReason ) OVERRIDE;
private:
diff --git a/mp/src/game/server/items.h b/mp/src/game/server/items.h
index 5e7672c6..bc1bb77e 100644
--- a/mp/src/game/server/items.h
+++ b/mp/src/game/server/items.h
@@ -82,9 +82,10 @@ public:
DECLARE_DATADESC();
protected:
virtual void ComeToRest( void );
+ bool m_bActivateWhenAtRest;
private:
- bool m_bActivateWhenAtRest;
+
COutputEvent m_OnPlayerTouch;
COutputEvent m_OnCacheInteraction;
diff --git a/mp/src/game/server/nav_area.cpp b/mp/src/game/server/nav_area.cpp
index 335e6c3b..656f675d 100644
--- a/mp/src/game/server/nav_area.cpp
+++ b/mp/src/game/server/nav_area.cpp
@@ -3707,7 +3707,7 @@ static Vector FindPositionInArea( CNavArea *area, NavCornerType corner )
pos = cornerPos + Vector( area->GetSizeX()*0.5f*multX, area->GetSizeY()*0.5f*multY, 0.0f );
if ( !area->IsOverlapping( pos ) )
{
- AssertMsg( false, UTIL_VarArgs( "A Hiding Spot can't be placed on its area at (%.0f %.0f %.0f)", cornerPos.x, cornerPos.y, cornerPos.z) );
+ AssertMsg( false, "A Hiding Spot can't be placed on its area at (%.0f %.0f %.0f)", cornerPos.x, cornerPos.y, cornerPos.z );
// Just pull the position to a small offset
pos = cornerPos + Vector( 1.0f*multX, 1.0f*multY, 0.0f );
@@ -4285,6 +4285,9 @@ bool CNavArea::ComputeLighting( void )
//--------------------------------------------------------------------------------------------------------------
CON_COMMAND_F( nav_update_lighting, "Recomputes lighting values", FCVAR_CHEAT )
{
+ if ( !UTIL_IsCommandIssuedByServerAdmin() )
+ return;
+
int numComputed = 0;
if ( args.ArgC() == 2 )
{
diff --git a/mp/src/game/server/nav_area.h b/mp/src/game/server/nav_area.h
index 3defa888..0c97a662 100644
--- a/mp/src/game/server/nav_area.h
+++ b/mp/src/game/server/nav_area.h
@@ -823,14 +823,9 @@ inline bool CNavArea::IsDegenerate( void ) const
//--------------------------------------------------------------------------------------------------------------
inline CNavArea *CNavArea::GetAdjacentArea( NavDirType dir, int i ) const
{
- for( int iter = 0; iter < m_connect[dir].Count(); ++iter )
- {
- if (i == 0)
- return m_connect[dir][iter].area;
- --i;
- }
-
- return NULL;
+ if ( ( i < 0 ) || ( i >= m_connect[dir].Count() ) )
+ return NULL;
+ return m_connect[dir][i].area;
}
//--------------------------------------------------------------------------------------------------------------
diff --git a/mp/src/game/server/nav_entities.cpp b/mp/src/game/server/nav_entities.cpp
index 83a7dd83..04951113 100644
--- a/mp/src/game/server/nav_entities.cpp
+++ b/mp/src/game/server/nav_entities.cpp
@@ -91,8 +91,7 @@ void CFuncNavCost::Spawn( void )
// chop space-delimited string into individual tokens
if ( tags )
{
- char *buffer = new char [ strlen( tags ) + 1 ];
- Q_strcpy( buffer, tags );
+ char *buffer = V_strdup ( tags );
for( char *token = strtok( buffer, " " ); token; token = strtok( NULL, " " ) )
{
diff --git a/mp/src/game/server/nav_file.cpp b/mp/src/game/server/nav_file.cpp
index 7de114ec..ea3bf5ad 100644
--- a/mp/src/game/server/nav_file.cpp
+++ b/mp/src/game/server/nav_file.cpp
@@ -1318,12 +1318,11 @@ const CUtlVector< Place > *CNavMesh::GetPlacesFromNavFile( bool *hasUnnamedPlace
if ( IsX360() )
{
// 360 has compressed NAVs
- CLZMA lzma;
- if ( lzma.IsCompressed( (unsigned char *)fileBuffer.Base() ) )
+ if ( CLZMA::IsCompressed( (unsigned char *)fileBuffer.Base() ) )
{
- int originalSize = lzma.GetActualSize( (unsigned char *)fileBuffer.Base() );
+ int originalSize = CLZMA::GetActualSize( (unsigned char *)fileBuffer.Base() );
unsigned char *pOriginalData = new unsigned char[originalSize];
- lzma.Uncompress( (unsigned char *)fileBuffer.Base(), pOriginalData );
+ CLZMA::Uncompress( (unsigned char *)fileBuffer.Base(), pOriginalData );
fileBuffer.AssumeMemory( pOriginalData, originalSize, originalSize, CUtlBuffer::READ_ONLY );
}
}
@@ -1411,12 +1410,11 @@ NavErrorType CNavMesh::Load( void )
if ( IsX360() )
{
// 360 has compressed NAVs
- CLZMA lzma;
- if ( lzma.IsCompressed( (unsigned char *)fileBuffer.Base() ) )
+ if ( CLZMA::IsCompressed( (unsigned char *)fileBuffer.Base() ) )
{
- int originalSize = lzma.GetActualSize( (unsigned char *)fileBuffer.Base() );
+ int originalSize = CLZMA::GetActualSize( (unsigned char *)fileBuffer.Base() );
unsigned char *pOriginalData = new unsigned char[originalSize];
- lzma.Uncompress( (unsigned char *)fileBuffer.Base(), pOriginalData );
+ CLZMA::Uncompress( (unsigned char *)fileBuffer.Base(), pOriginalData );
fileBuffer.AssumeMemory( pOriginalData, originalSize, originalSize, CUtlBuffer::READ_ONLY );
}
}
diff --git a/mp/src/game/server/nav_generate.cpp b/mp/src/game/server/nav_generate.cpp
index be9ce6b5..e10d01ea 100644
--- a/mp/src/game/server/nav_generate.cpp
+++ b/mp/src/game/server/nav_generate.cpp
@@ -1229,9 +1229,12 @@ void CNavMesh::RemoveOverlappingObstacleTopAreas()
static void CommandNavCheckStairs( void )
{
+ if ( !UTIL_IsCommandIssuedByServerAdmin() )
+ return;
+
TheNavMesh->MarkStairAreas();
}
-static ConCommand nav_check_stairs( "nav_check_stairs", CommandNavCheckStairs, "Update the nav mesh STAIRS attribute" );
+static ConCommand nav_check_stairs( "nav_check_stairs", CommandNavCheckStairs, "Update the nav mesh STAIRS attribute", FCVAR_CHEAT );
//--------------------------------------------------------------------------------------------------------------
/**
@@ -1445,6 +1448,9 @@ bool CNavArea::TestStairs( void )
//--------------------------------------------------------------------------------------------------------------
CON_COMMAND_F( nav_test_stairs, "Test the selected set for being on stairs", FCVAR_CHEAT )
{
+ if ( !UTIL_IsCommandIssuedByServerAdmin() )
+ return;
+
int count = 0;
const NavAreaVector &selectedSet = TheNavMesh->GetSelectedSet();
@@ -4932,5 +4938,8 @@ void CNavMesh::PostProcessCliffAreas()
CON_COMMAND_F( nav_gen_cliffs_approx, "Mark cliff areas, post-processing approximation", FCVAR_CHEAT )
{
+ if ( !UTIL_IsCommandIssuedByServerAdmin() )
+ return;
+
TheNavMesh->PostProcessCliffAreas();
}
diff --git a/mp/src/game/server/nav_mesh.cpp b/mp/src/game/server/nav_mesh.cpp
index 4c38a6f5..09326aaf 100644
--- a/mp/src/game/server/nav_mesh.cpp
+++ b/mp/src/game/server/nav_mesh.cpp
@@ -1700,6 +1700,9 @@ static ConCommand nav_clear_selected_set( "nav_clear_selected_set", CommandNavCl
//----------------------------------------------------------------------------------
CON_COMMAND_F( nav_dump_selected_set_positions, "Write the (x,y,z) coordinates of the centers of all selected nav areas to a file.", FCVAR_GAMEDLL | FCVAR_CHEAT )
{
+ if ( !UTIL_IsCommandIssuedByServerAdmin() )
+ return;
+
const NavAreaVector &selectedSet = TheNavMesh->GetSelectedSet();
CUtlBuffer fileBuffer( 4096, 1024*1024, CUtlBuffer::TEXT_BUFFER );
@@ -1732,6 +1735,9 @@ CON_COMMAND_F( nav_dump_selected_set_positions, "Write the (x,y,z) coordinates o
//----------------------------------------------------------------------------------
CON_COMMAND_F( nav_show_dumped_positions, "Show the (x,y,z) coordinate positions of the given dump file.", FCVAR_GAMEDLL | FCVAR_CHEAT )
{
+ if ( !UTIL_IsCommandIssuedByServerAdmin() )
+ return;
+
CUtlBuffer fileBuffer( 4096, 1024*1024, CUtlBuffer::TEXT_BUFFER );
// filename is local to game dir for Steam, so we need to prepend game dir for regular file save
@@ -1764,6 +1770,9 @@ CON_COMMAND_F( nav_show_dumped_positions, "Show the (x,y,z) coordinate positions
//----------------------------------------------------------------------------------
CON_COMMAND_F( nav_select_larger_than, "Select nav areas where both dimensions are larger than the given size.", FCVAR_GAMEDLL | FCVAR_CHEAT )
{
+ if ( !UTIL_IsCommandIssuedByServerAdmin() )
+ return;
+
if ( args.ArgC() > 1 )
{
float minSize = atof( args[1] );
@@ -2665,6 +2674,9 @@ void CNavMesh::CommandNavMarkWalkable( void )
{
Vector pos;
+ if ( !UTIL_IsCommandIssuedByServerAdmin() )
+ return;
+
if (nav_edit.GetBool())
{
// we are in edit mode, use the edit cursor's location
diff --git a/mp/src/game/server/networkstringtable_gamedll.h b/mp/src/game/server/networkstringtable_gamedll.h
index 9dbce97a..20965aa7 100644
--- a/mp/src/game/server/networkstringtable_gamedll.h
+++ b/mp/src/game/server/networkstringtable_gamedll.h
@@ -28,7 +28,7 @@ class CStringTableSaveRestoreOps;
#define MAX_CHOREO_SCENES_STRINGS ( 1 << MAX_CHOREO_SCENES_STRING_BITS )
#define CHOREO_SCENES_INVALID_STRING ( MAX_CHOREO_SCENES_STRINGS - 1 )
-#define MAX_PARTICLESYSTEMS_STRING_BITS 11
+#define MAX_PARTICLESYSTEMS_STRING_BITS 12
#define MAX_PARTICLESYSTEMS_STRINGS ( 1 << MAX_PARTICLESYSTEMS_STRING_BITS )
#define PARTICLESYSTEMS_INVALID_STRING ( MAX_PARTICLESYSTEMS_STRINGS - 1 )
diff --git a/mp/src/game/server/player.cpp b/mp/src/game/server/player.cpp
index a44ee551..e0e7ccd2 100644
--- a/mp/src/game/server/player.cpp
+++ b/mp/src/game/server/player.cpp
@@ -585,7 +585,9 @@ CBasePlayer::CBasePlayer( )
m_bForceOrigin = false;
m_hVehicle = NULL;
m_pCurrentCommand = NULL;
-
+ m_iLockViewanglesTickNumber = 0;
+ m_qangLockViewangles.Init();
+
// Setup our default FOV
m_iDefaultFOV = g_pGameRules->DefaultFOV();
@@ -976,7 +978,7 @@ void CBasePlayer::DamageEffect(float flDamage, int fDamageType)
}
else if (fDamageType & DMG_DROWN)
{
- //Red damage indicator
+ //Blue damage indicator
color32 blue = {0,0,128,128};
UTIL_ScreenFade( this, blue, 1.0f, 0.1f, FFADE_IN );
}
@@ -2325,6 +2327,7 @@ bool CBasePlayer::SetObserverMode(int mode )
break;
case OBS_MODE_CHASE :
+ case OBS_MODE_POI: // PASSTIME
case OBS_MODE_IN_EYE :
// udpate FOV and viewmodels
SetObserverTarget( m_hObserverTarget );
@@ -2420,8 +2423,7 @@ void CBasePlayer::CheckObserverSettings()
}
// check if our spectating target is still a valid one
-
- if ( m_iObserverMode == OBS_MODE_IN_EYE || m_iObserverMode == OBS_MODE_CHASE || m_iObserverMode == OBS_MODE_FIXED )
+ if ( m_iObserverMode == OBS_MODE_IN_EYE || m_iObserverMode == OBS_MODE_CHASE || m_iObserverMode == OBS_MODE_FIXED || m_iObserverMode == OBS_MODE_POI )
{
ValidateCurrentObserverTarget();
@@ -2633,7 +2635,10 @@ bool CBasePlayer::SetObserverTarget(CBaseEntity *target)
Vector dir, end;
Vector start = target->EyePosition();
- AngleVectors( target->EyeAngles(), &dir );
+ QAngle ang = target->EyeAngles();
+ ang.z = 0; // PASSTIME no view roll when spectating ball
+
+ AngleVectors( ang, &dir );
VectorNormalize( dir );
VectorMA( start, -64.0f, dir, end );
@@ -2643,7 +2648,7 @@ bool CBasePlayer::SetObserverTarget(CBaseEntity *target)
trace_t tr;
UTIL_TraceRay( ray, MASK_PLAYERSOLID, target, COLLISION_GROUP_PLAYER_MOVEMENT, &tr );
- JumptoPosition( tr.endpos, target->EyeAngles() );
+ JumptoPosition( tr.endpos, ang );
}
return true;
@@ -3411,6 +3416,8 @@ void CBasePlayer::ForceSimulation()
m_nSimulationTick = -1;
}
+ConVar sv_usercmd_custom_random_seed( "sv_usercmd_custom_random_seed", "1", FCVAR_CHEAT, "When enabled server will populate an additional random seed independent of the client" );
+
//-----------------------------------------------------------------------------
// Purpose:
// Input : *buf -
@@ -3437,6 +3444,16 @@ void CBasePlayer::ProcessUsercmds( CUserCmd *cmds, int numcmds, int totalcmds,
pCmd->MakeInert();
}
+ if ( sv_usercmd_custom_random_seed.GetBool() )
+ {
+ float fltTimeNow = float( Plat_FloatTime() * 1000.0 );
+ pCmd->server_random_seed = *reinterpret_cast<int*>( (char*)&fltTimeNow );
+ }
+ else
+ {
+ pCmd->server_random_seed = pCmd->random_seed;
+ }
+
ctx->cmds.AddToTail( *pCmd );
}
ctx->numcmds = numcmds;
@@ -7875,7 +7892,7 @@ void CMovementSpeedMod::InputSpeedMod(inputdata_t &data)
// Bring the weapon back
if ( HasSpawnFlags( SF_SPEED_MOD_SUPPRESS_WEAPONS ) && pPlayer->GetActiveWeapon() == NULL )
{
- pPlayer->SetActiveWeapon( pPlayer->Weapon_GetLast() );
+ pPlayer->SetActiveWeapon( pPlayer->GetLastWeapon() );
if ( pPlayer->GetActiveWeapon() )
{
pPlayer->GetActiveWeapon()->Deploy();
@@ -8857,8 +8874,6 @@ void CBasePlayer::SetPlayerName( const char *name )
Assert( strlen(name) > 0 );
Q_strncpy( m_szNetname, name, sizeof(m_szNetname) );
- // Be extra thorough
- Q_RemoveAllEvilCharacters( m_szNetname );
}
}
@@ -9386,4 +9401,4 @@ uint64 CBasePlayer::GetSteamIDAsUInt64( void )
return steamIDForPlayer.ConvertToUint64();
return 0;
}
-#endif // NO_STEAM \ No newline at end of file
+#endif // NO_STEAM
diff --git a/mp/src/game/server/player.h b/mp/src/game/server/player.h
index 8edefff3..e87af06d 100644
--- a/mp/src/game/server/player.h
+++ b/mp/src/game/server/player.h
@@ -415,7 +415,7 @@ public:
virtual bool Weapon_ShouldSetLast( CBaseCombatWeapon *pOldWeapon, CBaseCombatWeapon *pNewWeapon ) { return true; }
virtual bool Weapon_ShouldSelectItem( CBaseCombatWeapon *pWeapon );
void Weapon_DropSlot( int weaponSlot );
- CBaseCombatWeapon *Weapon_GetLast( void ) { return m_hLastWeapon.Get(); }
+ CBaseCombatWeapon *GetLastWeapon( void ) { return m_hLastWeapon.Get(); }
virtual void OnMyWeaponFired( CBaseCombatWeapon *weapon ); // call this when this player fires a weapon to allow other systems to react
virtual float GetTimeSinceWeaponFired( void ) const; // returns the time, in seconds, since this player fired a weapon
@@ -735,6 +735,8 @@ public:
bool IsPredictingWeapons( void ) const;
int CurrentCommandNumber() const;
const CUserCmd *GetCurrentUserCommand() const;
+ int GetLockViewanglesTickNumber() const { return m_iLockViewanglesTickNumber; }
+ QAngle GetLockViewanglesData() const { return m_qangLockViewangles; }
int GetFOV( void ); // Get the current FOV value
int GetDefaultFOV( void ) const; // Default FOV if not specified otherwise
@@ -891,7 +893,8 @@ public:
#if defined USES_ECON_ITEMS
CEconWearable *GetWearable( int i ) { return m_hMyWearables[i]; }
- int GetNumWearables( void ) { return m_hMyWearables.Count(); }
+ const CEconWearable *GetWearable( int i ) const { return m_hMyWearables[i]; }
+ int GetNumWearables( void ) const { return m_hMyWearables.Count(); }
#endif
private:
@@ -1058,6 +1061,8 @@ protected:
// Last received usercmd (in case we drop a lot of packets )
CUserCmd m_LastCmd;
CUserCmd *m_pCurrentCommand;
+ int m_iLockViewanglesTickNumber;
+ QAngle m_qangLockViewangles;
float m_flStepSoundTime; // time to check for next footstep sound
diff --git a/mp/src/game/server/player_command.cpp b/mp/src/game/server/player_command.cpp
index b607bbab..bf77b5d4 100644
--- a/mp/src/game/server/player_command.cpp
+++ b/mp/src/game/server/player_command.cpp
@@ -23,6 +23,7 @@ extern CMoveData *g_pMoveData; // This is a global because it is subclassed by e
extern ConVar sv_noclipduringpause;
ConVar sv_maxusrcmdprocessticks_warning( "sv_maxusrcmdprocessticks_warning", "-1", FCVAR_NONE, "Print a warning when user commands get dropped due to insufficient usrcmd ticks allocated, number of seconds to throttle, negative disabled" );
+static ConVar sv_maxusrcmdprocessticks_holdaim( "sv_maxusrcmdprocessticks_holdaim", "1", FCVAR_CHEAT, "Hold client aim for multiple server sim ticks when client-issued usrcmd contains multiple actions (0: off; 1: hold this server tick; 2+: hold multiple ticks)" );
//-----------------------------------------------------------------------------
// Purpose:
@@ -442,6 +443,12 @@ void CPlayerMove::RunCommand ( CBasePlayer *player, CUserCmd *ucmd, IMoveHelper
// Copy output
FinishMove( player, ucmd, g_pMoveData );
+ // If we have to restore the view angle then do so right now
+ if ( !player->IsBot() && ( gpGlobals->tickcount - player->GetLockViewanglesTickNumber() < sv_maxusrcmdprocessticks_holdaim.GetInt() ) )
+ {
+ player->pl.v_angle = player->GetLockViewanglesData();
+ }
+
// Let server invoke any needed impact functions
VPROF_SCOPE_BEGIN( "moveHelper->ProcessImpacts" );
moveHelper->ProcessImpacts();
diff --git a/mp/src/game/server/point_spotlight.cpp b/mp/src/game/server/point_spotlight.cpp
index 9ff28cf6..030537ed 100644
--- a/mp/src/game/server/point_spotlight.cpp
+++ b/mp/src/game/server/point_spotlight.cpp
@@ -56,6 +56,7 @@ private:
private:
bool m_bSpotlightOn;
bool m_bEfficientSpotlight;
+ bool m_bIgnoreSolid;
Vector m_vSpotlightTargetPos;
Vector m_vSpotlightCurrentPos;
Vector m_vSpotlightDir;
@@ -88,6 +89,7 @@ BEGIN_DATADESC( CPointSpotlight )
DEFINE_FIELD( m_vSpotlightDir, FIELD_VECTOR ),
DEFINE_FIELD( m_nHaloSprite, FIELD_INTEGER ),
+ DEFINE_KEYFIELD( m_bIgnoreSolid, FIELD_BOOLEAN, "IgnoreSolid" ),
DEFINE_KEYFIELD( m_flSpotlightMaxLength,FIELD_FLOAT, "SpotlightLength"),
DEFINE_KEYFIELD( m_flSpotlightGoalWidth,FIELD_FLOAT, "SpotlightWidth"),
DEFINE_KEYFIELD( m_flHDRColorScale, FIELD_FLOAT, "HDRColorScale" ),
@@ -118,6 +120,7 @@ CPointSpotlight::CPointSpotlight()
#endif
m_flHDRColorScale = 1.0f;
m_nMinDXLevel = 0;
+ m_bIgnoreSolid = false;
}
@@ -332,12 +335,21 @@ void CPointSpotlight::SpotlightCreate(void)
AngleVectors( GetAbsAngles(), &m_vSpotlightDir );
- trace_t tr;
- UTIL_TraceLine( GetAbsOrigin(), GetAbsOrigin() + m_vSpotlightDir * m_flSpotlightMaxLength, MASK_SOLID_BRUSHONLY, this, COLLISION_GROUP_NONE, &tr);
+ Vector vTargetPos;
+ if ( m_bIgnoreSolid )
+ {
+ vTargetPos = GetAbsOrigin() + m_vSpotlightDir * m_flSpotlightMaxLength;
+ }
+ else
+ {
+ trace_t tr;
+ UTIL_TraceLine( GetAbsOrigin(), GetAbsOrigin() + m_vSpotlightDir * m_flSpotlightMaxLength, MASK_SOLID_BRUSHONLY, this, COLLISION_GROUP_NONE, &tr );
+ vTargetPos = tr.endpos;
+ }
m_hSpotlightTarget = (CSpotlightEnd*)CreateEntityByName( "spotlight_end" );
m_hSpotlightTarget->Spawn();
- m_hSpotlightTarget->SetAbsOrigin( tr.endpos );
+ m_hSpotlightTarget->SetAbsOrigin( vTargetPos );
m_hSpotlightTarget->SetOwnerEntity( this );
m_hSpotlightTarget->m_clrRender = m_clrRender;
m_hSpotlightTarget->m_Radius = m_flSpotlightMaxLength;
@@ -381,9 +393,17 @@ Vector CPointSpotlight::SpotlightCurrentPos(void)
AngleVectors( GetAbsAngles(), &m_vSpotlightDir );
// Get beam end point. Only collide with solid objects, not npcs
- trace_t tr;
- UTIL_TraceLine( GetAbsOrigin(), GetAbsOrigin() + (m_vSpotlightDir * 2 * m_flSpotlightMaxLength), MASK_SOLID_BRUSHONLY, this, COLLISION_GROUP_NONE, &tr );
- return tr.endpos;
+ Vector vEndPos = GetAbsOrigin() + ( m_vSpotlightDir * 2 * m_flSpotlightMaxLength );
+ if ( m_bIgnoreSolid )
+ {
+ return vEndPos;
+ }
+ else
+ {
+ trace_t tr;
+ UTIL_TraceLine( GetAbsOrigin(), vEndPos, MASK_SOLID_BRUSHONLY, this, COLLISION_GROUP_NONE, &tr );
+ return tr.endpos;
+ }
}
//------------------------------------------------------------------------------
diff --git a/mp/src/game/server/props.cpp b/mp/src/game/server/props.cpp
index 648191db..9ba6c11b 100644
--- a/mp/src/game/server/props.cpp
+++ b/mp/src/game/server/props.cpp
@@ -1811,6 +1811,8 @@ LINK_ENTITY_TO_CLASS( dynamic_prop, CDynamicProp );
LINK_ENTITY_TO_CLASS( prop_dynamic, CDynamicProp );
LINK_ENTITY_TO_CLASS( prop_dynamic_override, CDynamicProp );
+IMPLEMENT_AUTO_LIST( IPhysicsPropAutoList );
+
BEGIN_DATADESC( CDynamicProp )
// Fields
diff --git a/mp/src/game/server/props.h b/mp/src/game/server/props.h
index 8db20f2f..7dc9f48a 100644
--- a/mp/src/game/server/props.h
+++ b/mp/src/game/server/props.h
@@ -327,7 +327,8 @@ protected:
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
-class CPhysicsProp : public CBreakableProp
+DECLARE_AUTO_LIST( IPhysicsPropAutoList );
+class CPhysicsProp : public CBreakableProp, public IPhysicsPropAutoList
{
DECLARE_CLASS( CPhysicsProp, CBreakableProp );
DECLARE_SERVERCLASS();
diff --git a/mp/src/game/server/recipientfilter.cpp b/mp/src/game/server/recipientfilter.cpp
index d39419c3..64889b31 100644
--- a/mp/src/game/server/recipientfilter.cpp
+++ b/mp/src/game/server/recipientfilter.cpp
@@ -341,7 +341,7 @@ CTeamRecipientFilter::CTeamRecipientFilter( int team, bool isReliable )
if ( pPlayer->GetTeamNumber() != team )
{
//If we're in the spectator team then we should be getting whatever messages the person I'm spectating gets.
- if ( pPlayer->GetTeamNumber() == TEAM_SPECTATOR && (pPlayer->GetObserverMode() == OBS_MODE_IN_EYE || pPlayer->GetObserverMode() == OBS_MODE_CHASE) )
+ if ( pPlayer->GetTeamNumber() == TEAM_SPECTATOR && (pPlayer->GetObserverMode() == OBS_MODE_IN_EYE || pPlayer->GetObserverMode() == OBS_MODE_CHASE || pPlayer->GetObserverMode() == OBS_MODE_POI) )
{
if ( pPlayer->GetObserverTarget() )
{
diff --git a/mp/src/game/server/sceneentity.cpp b/mp/src/game/server/sceneentity.cpp
index ccdc4cd4..f092624f 100644
--- a/mp/src/game/server/sceneentity.cpp
+++ b/mp/src/game/server/sceneentity.cpp
@@ -4951,8 +4951,9 @@ void CSceneManager::RemoveScenesInvolvingActor( CBaseFlex *pActor )
if ( !pActor )
return;
+ // This loop can remove items from m_ActiveScenes array, so loop through backwards.
int c = m_ActiveScenes.Count();
- for ( int i = 0; i < c; i++ )
+ for ( int i = c - 1 ; i >= 0; --i )
{
CSceneEntity *pScene = m_ActiveScenes[ i ].Get();
if ( !pScene )
diff --git a/mp/src/game/server/slideshow_display.cpp b/mp/src/game/server/slideshow_display.cpp
index 79e78841..12e19ceb 100644
--- a/mp/src/game/server/slideshow_display.cpp
+++ b/mp/src/game/server/slideshow_display.cpp
@@ -528,8 +528,8 @@ void CSlideshowDisplay::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;
@@ -562,7 +562,7 @@ void CSlideshowDisplay::BuildSlideShowImagesList( void )
{
// Couldn't find the list, so create it
iList = m_SlideKeywordList.AddToTail( new SlideKeywordList_t );
- Q_strcpy( m_SlideKeywordList[ iList ]->szSlideKeyword, pchKeyword );
+ V_strcpy_safe( m_SlideKeywordList[iList]->szSlideKeyword, pchKeyword );
}
pchKeyword = pNextKeyword;
@@ -581,7 +581,7 @@ void CSlideshowDisplay::BuildSlideShowImagesList( void )
{
// Couldn't find the generic list, so create it
iList = m_SlideKeywordList.AddToHead( new SlideKeywordList_t );
- Q_strcpy( m_SlideKeywordList[ iList ]->szSlideKeyword, "" );
+ V_strcpy_safe( m_SlideKeywordList[iList]->szSlideKeyword, "" );
}
if ( IsX360() )
diff --git a/mp/src/game/server/team_control_point.cpp b/mp/src/game/server/team_control_point.cpp
index 1bbec70a..a1288ad7 100644
--- a/mp/src/game/server/team_control_point.cpp
+++ b/mp/src/game/server/team_control_point.cpp
@@ -17,6 +17,7 @@
#ifdef TF_DLL
#include "tf_shareddefs.h"
+#include "tf_gamerules.h"
#endif
#define CONTROL_POINT_UNLOCK_THINK "UnlockThink"
@@ -269,6 +270,7 @@ void CTeamControlPoint::Precache( void )
#ifdef TF_DLL
PrecacheScriptSound( "Announcer.ControlPointContested" );
+ PrecacheScriptSound( "Announcer.ControlPointContested_Neutral" );
#endif
}
@@ -653,7 +655,15 @@ void CTeamControlPoint::InternalSetOwner( int iCapTeam, bool bMakeSound, int iNu
Assert( playerIndex > 0 && playerIndex <= gpGlobals->maxClients );
- PlayerCapped( ToBaseMultiplayerPlayer(UTIL_PlayerByIndex( playerIndex )) );
+ CBaseMultiplayerPlayer *pPlayer = ToBaseMultiplayerPlayer( UTIL_PlayerByIndex( playerIndex ) );
+ PlayerCapped( pPlayer );
+
+#ifdef TF_DLL
+ if ( TFGameRules() && TFGameRules()->IsHolidayActive( kHoliday_EOTL ) )
+ {
+ TFGameRules()->DropBonusDuck( pPlayer->GetAbsOrigin(), ToTFPlayer( pPlayer ), NULL, NULL, false, true );
+ }
+#endif
}
// Remap team to get first game team = 1
@@ -733,7 +743,7 @@ void CTeamControlPoint::SendCapString( int iCapTeam, int iNumCappingPlayers, int
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
-void CTeamControlPoint::CaptureBlocked( CBaseMultiplayerPlayer *pPlayer )
+void CTeamControlPoint::CaptureBlocked( CBaseMultiplayerPlayer *pPlayer, CBaseMultiplayerPlayer *pVictim )
{
if( strlen( STRING(m_iszPrintName) ) <= 0 )
return;
@@ -746,6 +756,10 @@ void CTeamControlPoint::CaptureBlocked( CBaseMultiplayerPlayer *pPlayer )
event->SetString( "cpname", STRING(m_iszPrintName) );
event->SetInt( "blocker", pPlayer->entindex() );
event->SetInt( "priority", 9 );
+ if ( pVictim )
+ {
+ event->SetInt( "victim", pVictim->entindex() );
+ }
gameeventmanager->FireEvent( event );
}
diff --git a/mp/src/game/server/team_control_point.h b/mp/src/game/server/team_control_point.h
index 816a3ac1..bfcfe100 100644
--- a/mp/src/game/server/team_control_point.h
+++ b/mp/src/game/server/team_control_point.h
@@ -82,7 +82,7 @@ public:
void SetCappersRequiredForTeam( int iGameTeam, int iCappers );
- void CaptureBlocked( CBaseMultiplayerPlayer *pPlayer );
+ void CaptureBlocked( CBaseMultiplayerPlayer *pPlayer, CBaseMultiplayerPlayer *pVictim );
int PointValue( void );
diff --git a/mp/src/game/server/team_control_point_master.cpp b/mp/src/game/server/team_control_point_master.cpp
index 956f7ddb..9b007e06 100644
--- a/mp/src/game/server/team_control_point_master.cpp
+++ b/mp/src/game/server/team_control_point_master.cpp
@@ -1056,65 +1056,44 @@ bool CTeamControlPointMaster::IsBaseControlPoint( int iPointIndex )
int CTeamControlPointMaster::GetBaseControlPoint( int iTeam )
{
int iRetVal = -1;
- int nLowestValue = 999, nHighestValue = -1;
- int iLowestIndex = 0, iHighestIndex = 0;
+ int nLowestValue = 999;
+ int nHighestValue = -1;
+ CTeamControlPoint *pLowestPoint = NULL;
+ CTeamControlPoint *pHighestPoint = NULL;
- for( int i = 0 ; i < (int)m_ControlPoints.Count() ; i++ )
+ for( unsigned int i = 0 ; i < m_ControlPoints.Count() ; i++ )
{
CTeamControlPoint *pPoint = m_ControlPoints[i];
- int iPointIndex = m_ControlPoints[i]->GetPointIndex();
-
- if ( PlayingMiniRounds() && iTeam > LAST_SHARED_TEAM )
+ if ( !PlayingMiniRounds() || ( IsInRound( pPoint ) && ( iTeam > LAST_SHARED_TEAM ) ) )
{
- if ( IsInRound( pPoint ) ) // is this point in the current round?
- {
- if ( iPointIndex > nHighestValue )
- {
- nHighestValue = iPointIndex;
- iHighestIndex = i;
- }
+ int nTempValue = pPoint->GetPointIndex();
- if ( iPointIndex < nLowestValue )
- {
- nLowestValue = iPointIndex;
- iLowestIndex = i;
- }
- }
- }
- else
- {
- if ( pPoint->GetDefaultOwner() != iTeam )
+ if ( nTempValue > nHighestValue )
{
- continue;
+ nHighestValue = nTempValue;
+ pHighestPoint = pPoint;
}
- // If it's the first or the last point, it's their base
- if ( iPointIndex == 0 || iPointIndex == (((int)m_ControlPoints.Count())-1) )
+ if ( nTempValue < nLowestValue )
{
- iRetVal = iPointIndex;
- break;
+ nLowestValue = nTempValue;
+ pLowestPoint = pPoint;
}
}
}
- if ( PlayingMiniRounds() && iTeam > LAST_SHARED_TEAM )
+ if ( pLowestPoint && pHighestPoint )
{
- if ( nLowestValue != 999 && nHighestValue != -1 )
+ // which point is owned by this team?
+ if ( ( pLowestPoint->GetDefaultOwner() == iTeam && pHighestPoint->GetDefaultOwner() == iTeam ) || // if the same team owns both, take the highest value to be the last point
+ ( pHighestPoint->GetDefaultOwner() == iTeam ) )
{
- CTeamControlPoint *pLowestPoint = m_ControlPoints[iLowestIndex];
- CTeamControlPoint *pHighestPoint = m_ControlPoints[iHighestIndex];
-
- // which point is owned by this team?
- if ( ( pLowestPoint->GetDefaultOwner() == iTeam && pHighestPoint->GetDefaultOwner() == iTeam ) || // if the same team owns both, take the highest value to be the last point
- ( pHighestPoint->GetDefaultOwner() == iTeam ) )
- {
- iRetVal = nHighestValue;
- }
- else if ( pLowestPoint->GetDefaultOwner() == iTeam )
- {
- iRetVal = nLowestValue;
- }
+ iRetVal = nHighestValue;
+ }
+ else if ( pLowestPoint->GetDefaultOwner() == iTeam )
+ {
+ iRetVal = nLowestValue;
}
}
diff --git a/mp/src/game/server/team_control_point_master.h b/mp/src/game/server/team_control_point_master.h
index 0c229a05..465a67dd 100644
--- a/mp/src/game/server/team_control_point_master.h
+++ b/mp/src/game/server/team_control_point_master.h
@@ -132,6 +132,7 @@ public:
float GetLastOwnershipChangeTime( void ) { return m_flLastOwnershipChangeTime; }
int GetCurrentRoundIndex() { return m_iCurrentRoundIndex; }
+ bool ShouldSwitchTeamsOnRoundWin( void ) { return m_bSwitchTeamsOnWin; }
private:
void EXPORT CPMThink( void );
diff --git a/mp/src/game/server/trigger_area_capture.cpp b/mp/src/game/server/trigger_area_capture.cpp
index 648a3b86..979ef4bc 100644
--- a/mp/src/game/server/trigger_area_capture.cpp
+++ b/mp/src/game/server/trigger_area_capture.cpp
@@ -535,7 +535,7 @@ void CTriggerAreaCapture::CaptureThink( void )
if ( !bRepeatBlocker )
{
- m_hPoint->CaptureBlocked( pBlockingPlayer );
+ m_hPoint->CaptureBlocked( pBlockingPlayer, NULL );
// Add this guy to our blocker list
int iNew = m_Blockers.AddToTail();
@@ -882,6 +882,12 @@ void CTriggerAreaCapture::EndCapture( int team )
m_nCapturingTeam = TEAM_UNASSIGNED;
SetCapTimeRemaining( 0 );
+ // play any special cap sounds. need to do this before we update the owner of the point.
+ if ( TeamplayRoundBasedRules() )
+ {
+ TeamplayRoundBasedRules()->PlaySpecialCapSounds( m_nOwningTeam, m_hPoint.Get() );
+ }
+
//there may have been more than one capper, but only report this one.
//he hasn't gotten points yet, and his name will go in the cap string if its needed
//first capper gets name sent and points given by flag.
@@ -912,12 +918,6 @@ void CTriggerAreaCapture::EndCapture( int team )
}
}
}
-
- // play any special cap sounds
- if ( TeamplayRoundBasedRules() )
- {
- TeamplayRoundBasedRules()->PlaySpecialCapSounds( m_nOwningTeam );
- }
}
//-----------------------------------------------------------------------------
@@ -1140,7 +1140,7 @@ bool CTriggerAreaCapture::CheckIfDeathCausesBlock( CBaseMultiplayerPlayer *pVict
if ( bBreakCap )
{
- m_hPoint->CaptureBlocked( pKiller );
+ m_hPoint->CaptureBlocked( pKiller, pVictim );
//BreakCapture( true );
}
diff --git a/mp/src/game/server/triggers.cpp b/mp/src/game/server/triggers.cpp
index 742976fb..1e317567 100644
--- a/mp/src/game/server/triggers.cpp
+++ b/mp/src/game/server/triggers.cpp
@@ -475,6 +475,7 @@ void CBaseTrigger::StartTouch(CBaseEntity *pOther)
{
// First entity to touch us that passes our filters
m_OnStartTouchAll.FireOutput( pOther, this );
+ StartTouchAll();
}
}
}
@@ -514,7 +515,10 @@ void CBaseTrigger::EndTouch(CBaseEntity *pOther)
else if ( hOther->IsPlayer() && !hOther->IsAlive() )
{
#ifdef STAGING_ONLY
- AssertMsg( 0, CFmtStr( "Dead player [%s] is still touching this trigger at [%f %f %f]", hOther->GetEntityName().ToCStr(), XYZ( hOther->GetAbsOrigin() ) ) );
+ if ( !HushAsserts() )
+ {
+ AssertMsg( false, "Dead player [%s] is still touching this trigger at [%f %f %f]", hOther->GetEntityName().ToCStr(), XYZ( hOther->GetAbsOrigin() ) );
+ }
Warning( "Dead player [%s] is still touching this trigger at [%f %f %f]", hOther->GetEntityName().ToCStr(), XYZ( hOther->GetAbsOrigin() ) );
#endif
m_hTouchingEntities.Remove( i );
@@ -530,6 +534,7 @@ void CBaseTrigger::EndTouch(CBaseEntity *pOther)
if ( !bFoundOtherTouchee /*&& !m_bDisabled*/ )
{
m_OnEndTouchAll.FireOutput(pOther, this);
+ EndTouchAll();
}
}
}
@@ -634,8 +639,8 @@ void CTriggerRemove::Touch( CBaseEntity *pOther )
BEGIN_DATADESC( CTriggerHurt )
// Function Pointers
- DEFINE_FUNCTION( RadiationThink ),
- DEFINE_FUNCTION( HurtThink ),
+ DEFINE_FUNCTION( CTriggerHurtShim::RadiationThinkShim ),
+ DEFINE_FUNCTION( CTriggerHurtShim::HurtThinkShim ),
// Fields
DEFINE_FIELD( m_flOriginalDamage, FIELD_FLOAT ),
@@ -661,6 +666,7 @@ END_DATADESC()
LINK_ENTITY_TO_CLASS( trigger_hurt, CTriggerHurt );
+IMPLEMENT_AUTO_LIST( ITriggerHurtAutoList );
//-----------------------------------------------------------------------------
// Purpose: Called when spawning, after keyvalues have been handled.
@@ -677,7 +683,7 @@ void CTriggerHurt::Spawn( void )
SetThink( NULL );
if (m_bitsDamageInflict & DMG_RADIATION)
{
- SetThink ( &CTriggerHurt::RadiationThink );
+ SetThink ( &CTriggerHurtShim::RadiationThinkShim );
SetNextThink( gpGlobals->curtime + random->RandomFloat(0.0, 0.5) );
}
}
@@ -723,6 +729,15 @@ bool CTriggerHurt::HurtEntity( CBaseEntity *pOther, float damage )
if ( !pOther->m_takedamage || !PassesTriggerFilters(pOther) )
return false;
+ // If player is disconnected, we're probably in this routine via the
+ // PhysicsRemoveTouchedList() function to make sure all Untouch()'s are called for the
+ // player. Calling TakeDamage() in this case can get into the speaking criteria, which
+ // will then loop through the control points and the touched list again. We shouldn't
+ // need to hurt players that are disconnected, so skip all of this...
+ bool bPlayerDisconnected = pOther->IsPlayer() && ( ((CBasePlayer *)pOther)->IsConnected() == false );
+ if ( bPlayerDisconnected )
+ return false;
+
if ( damage < 0 )
{
pOther->TakeHealth( -damage, m_bitsDamageInflict );
@@ -862,11 +877,29 @@ void CTriggerHurt::Touch( CBaseEntity *pOther )
{
if ( m_pfnThink == NULL )
{
- SetThink( &CTriggerHurt::HurtThink );
+ SetThink( &CTriggerHurtShim::HurtThinkShim );
SetNextThink( gpGlobals->curtime );
}
}
+//-----------------------------------------------------------------------------
+// Purpose: Checks if this point is in any trigger_hurt zones with positive damage
+//-----------------------------------------------------------------------------
+bool IsTakingTriggerHurtDamageAtPoint( const Vector &vecPoint )
+{
+ for ( int i = 0; i < ITriggerHurtAutoList::AutoList().Count(); i++ )
+ {
+ // Some maps use trigger_hurt with negative values as healing triggers; don't consider those
+ CTriggerHurt *pTrigger = static_cast<CTriggerHurt*>( ITriggerHurtAutoList::AutoList()[i] );
+ if ( !pTrigger->m_bDisabled && pTrigger->PointIsWithin( vecPoint ) && pTrigger->m_flDamage > 0.f )
+ {
+ return true;
+ }
+ }
+
+ return false;
+}
+
// ##################################################################################
// >> TriggerMultiple
@@ -2310,8 +2343,8 @@ class CTriggerTeleport : public CBaseTrigger
public:
DECLARE_CLASS( CTriggerTeleport, CBaseTrigger );
- void Spawn( void );
- void Touch( CBaseEntity *pOther );
+ virtual void Spawn( void ) OVERRIDE;
+ virtual void Touch( CBaseEntity *pOther ) OVERRIDE;
string_t m_iLandmark;
@@ -2326,14 +2359,11 @@ BEGIN_DATADESC( CTriggerTeleport )
END_DATADESC()
-
-
void CTriggerTeleport::Spawn( void )
{
InitTrigger();
}
-
//-----------------------------------------------------------------------------
// Purpose: Teleports the entity that touched us to the location of our target,
// setting the toucher's angles to our target's angles if they are a
@@ -2416,6 +2446,46 @@ LINK_ENTITY_TO_CLASS( info_teleport_destination, CPointEntity );
//-----------------------------------------------------------------------------
+// Teleport Relative trigger
+//-----------------------------------------------------------------------------
+class CTriggerTeleportRelative : public CBaseTrigger
+{
+public:
+ DECLARE_CLASS(CTriggerTeleportRelative, CBaseTrigger);
+
+ virtual void Spawn( void ) OVERRIDE;
+ virtual void Touch( CBaseEntity *pOther ) OVERRIDE;
+
+ Vector m_TeleportOffset;
+
+ DECLARE_DATADESC();
+};
+
+LINK_ENTITY_TO_CLASS( trigger_teleport_relative, CTriggerTeleportRelative );
+BEGIN_DATADESC( CTriggerTeleportRelative )
+ DEFINE_KEYFIELD( m_TeleportOffset, FIELD_VECTOR, "teleportoffset" )
+END_DATADESC()
+
+
+void CTriggerTeleportRelative::Spawn( void )
+{
+ InitTrigger();
+}
+
+void CTriggerTeleportRelative::Touch( CBaseEntity *pOther )
+{
+ if ( !PassesTriggerFilters(pOther) )
+ {
+ return;
+ }
+
+ const Vector finalPos = m_TeleportOffset + WorldSpaceCenter();
+ const Vector *momentum = &vec3_origin;
+
+ pOther->Teleport( &finalPos, NULL, momentum );
+}
+
+//-----------------------------------------------------------------------------
// Purpose: Saves the game when the player touches the trigger. Can be enabled or disabled
//-----------------------------------------------------------------------------
class CTriggerToggleSave : public CBaseTrigger
@@ -4822,6 +4892,78 @@ void CServerRagdollTrigger::EndTouch(CBaseEntity *pOther)
}
}
+
+//-----------------------------------------------------------------------------
+// Purpose: A trigger that adds impulse to touching entities
+//-----------------------------------------------------------------------------
+class CTriggerApplyImpulse : public CBaseTrigger
+{
+public:
+ DECLARE_CLASS( CTriggerApplyImpulse, CBaseTrigger );
+ DECLARE_DATADESC();
+
+ CTriggerApplyImpulse();
+
+ void Spawn( void );
+
+ void InputApplyImpulse( inputdata_t& );
+
+private:
+ Vector m_vecImpulseDir;
+ float m_flForce;
+};
+
+
+BEGIN_DATADESC( CTriggerApplyImpulse )
+ DEFINE_KEYFIELD( m_vecImpulseDir, FIELD_VECTOR, "impulse_dir" ),
+ DEFINE_KEYFIELD( m_flForce, FIELD_FLOAT, "force" ),
+ DEFINE_INPUTFUNC( FIELD_VOID, "ApplyImpulse", InputApplyImpulse ),
+END_DATADESC()
+
+
+LINK_ENTITY_TO_CLASS( trigger_apply_impulse, CTriggerApplyImpulse );
+
+
+CTriggerApplyImpulse::CTriggerApplyImpulse()
+{
+ m_flForce = 300.f;
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CTriggerApplyImpulse::Spawn()
+{
+ // Convert pushdir from angles to a vector
+ Vector vecAbsDir;
+ QAngle angPushDir = QAngle(m_vecImpulseDir.x, m_vecImpulseDir.y, m_vecImpulseDir.z);
+ AngleVectors(angPushDir, &vecAbsDir);
+
+ // Transform the vector into entity space
+ VectorIRotate( vecAbsDir, EntityToWorldTransform(), m_vecImpulseDir );
+
+ BaseClass::Spawn();
+
+ InitTrigger();
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CTriggerApplyImpulse::InputApplyImpulse( inputdata_t& )
+{
+ Vector vecImpulse = m_flForce * m_vecImpulseDir;
+ FOR_EACH_VEC( m_hTouchingEntities, i )
+ {
+ if ( m_hTouchingEntities[i] )
+ {
+ m_hTouchingEntities[i]->ApplyAbsVelocityImpulse( vecImpulse );
+ }
+ }
+}
+
#ifdef HL1_DLL
//----------------------------------------------------------------------------------
// func_friction
diff --git a/mp/src/game/server/triggers.h b/mp/src/game/server/triggers.h
index 7695d08c..6ae7312f 100644
--- a/mp/src/game/server/triggers.h
+++ b/mp/src/game/server/triggers.h
@@ -68,6 +68,8 @@ public:
virtual bool PassesTriggerFilters(CBaseEntity *pOther);
virtual void StartTouch(CBaseEntity *pOther);
virtual void EndTouch(CBaseEntity *pOther);
+ virtual void StartTouchAll() {}
+ virtual void EndTouchAll() {}
bool IsTouching( CBaseEntity *pOther );
CBaseEntity *GetTouchedEntityOfType( const char *sClassName );
@@ -164,7 +166,21 @@ protected:
// Purpose: Hurts anything that touches it. If the trigger has a targetname,
// firing it will toggle state.
//-----------------------------------------------------------------------------
-class CTriggerHurt : public CBaseTrigger
+
+// This class is to get around the fact that DEFINE_FUNCTION doesn't like multiple inheritance
+class CTriggerHurtShim : public CBaseTrigger
+{
+ virtual void RadiationThink( void ) = 0;
+ virtual void HurtThink( void ) = 0;
+
+public:
+
+ void RadiationThinkShim( void ){ RadiationThink(); }
+ void HurtThinkShim( void ){ HurtThink(); }
+};
+
+DECLARE_AUTO_LIST( ITriggerHurtAutoList );
+class CTriggerHurt : public CTriggerHurtShim, public ITriggerHurtAutoList
{
public:
CTriggerHurt()
@@ -173,7 +189,7 @@ public:
m_flDamageCap = 20.0f;
}
- DECLARE_CLASS( CTriggerHurt, CBaseTrigger );
+ DECLARE_CLASS( CTriggerHurt, CTriggerHurtShim );
void Spawn( void );
void RadiationThink( void );
@@ -207,4 +223,6 @@ public:
CUtlVector<EHANDLE> m_hurtEntities;
};
+bool IsTakingTriggerHurtDamageAtPoint( const Vector &vecPoint );
+
#endif // TRIGGERS_H
diff --git a/mp/src/game/server/util.cpp b/mp/src/game/server/util.cpp
index 8cd8f989..4b2008df 100644
--- a/mp/src/game/server/util.cpp
+++ b/mp/src/game/server/util.cpp
@@ -59,7 +59,7 @@ void DBG_AssertFunction( bool fExpr, const char *szExpr, const char *szFile, int
Q_snprintf(szOut,sizeof(szOut), "ASSERT FAILED:\n %s \n(%s@%d)\n%s", szExpr, szFile, szLine, szMessage);
else
Q_snprintf(szOut,sizeof(szOut), "ASSERT FAILED:\n %s \n(%s@%d)\n", szExpr, szFile, szLine);
- Warning( szOut);
+ Warning( "%s", szOut);
}
#endif // DEBUG
@@ -161,6 +161,11 @@ IServerNetworkable *CEntityFactoryDictionary::Create( const char *pClassName )
IEntityFactory *pFactory = FindFactory( pClassName );
if ( !pFactory )
{
+#ifdef STAGING_ONLY
+ static ConVarRef tf_bot_use_items( "tf_bot_use_items" );
+ if ( tf_bot_use_items.IsValid() && tf_bot_use_items.GetInt() )
+ return NULL;
+#endif
Warning("Attempted to create unknown entity type %s!\n", pClassName );
return NULL;
}
@@ -568,6 +573,24 @@ CBasePlayer *UTIL_PlayerByIndex( int playerIndex )
return pPlayer;
}
+CBasePlayer *UTIL_PlayerBySteamID( const CSteamID &steamID )
+{
+ CSteamID steamIDPlayer;
+ for ( int i = 1; i <= gpGlobals->maxClients; i++ )
+ {
+ CBasePlayer *pPlayer = UTIL_PlayerByIndex( i );
+ if ( !pPlayer )
+ continue;
+
+ if ( !pPlayer->GetSteamID( &steamIDPlayer ) )
+ continue;
+
+ if ( steamIDPlayer == steamID )
+ return pPlayer;
+ }
+ return NULL;
+}
+
CBasePlayer* UTIL_PlayerByName( const char *name )
{
if ( !name || !name[0] )
diff --git a/mp/src/game/server/util.h b/mp/src/game/server/util.h
index 92c341d8..c06cbfe9 100644
--- a/mp/src/game/server/util.h
+++ b/mp/src/game/server/util.h
@@ -222,6 +222,7 @@ float UTIL_GetSimulationInterval();
// NOTENOTE: Use UTIL_GetLocalPlayer instead of UTIL_PlayerByIndex IF you're in single player
// and you want the player.
CBasePlayer *UTIL_PlayerByIndex( int playerIndex );
+CBasePlayer *UTIL_PlayerBySteamID( const CSteamID &steamID );
// NOTENOTE: Use this instead of UTIL_PlayerByIndex IF you're in single player
// and you want the player.
diff --git a/mp/src/game/server/vote_controller.cpp b/mp/src/game/server/vote_controller.cpp
index 7dab54bb..a29b449f 100644
--- a/mp/src/game/server/vote_controller.cpp
+++ b/mp/src/game/server/vote_controller.cpp
@@ -14,6 +14,7 @@
#ifdef TF_DLL
#include "tf/tf_gamerules.h"
+#include "tf/tf_voteissues.h"
#endif
// memdbgon must be the last include file in a .cpp file!!!
@@ -38,15 +39,15 @@ LINK_ENTITY_TO_CLASS( vote_controller, CVoteController );
CVoteController *g_voteController = NULL;
-ConVar sv_vote_timer_duration("sv_vote_timer_duration", "15", FCVAR_DEVELOPMENTONLY, "How long to allow voting on an issue");
-ConVar sv_vote_command_delay("sv_vote_command_delay", "2", FCVAR_DEVELOPMENTONLY, "How long after a vote passes until the action happens", false, 0, true, 4.5);
-ConVar sv_allow_votes("sv_allow_votes", "1", FCVAR_NONE, "Allow voting?");
+ConVar sv_vote_timer_duration( "sv_vote_timer_duration", "15", FCVAR_DEVELOPMENTONLY, "How long to allow voting on an issue" );
+ConVar sv_vote_command_delay( "sv_vote_command_delay", "2", FCVAR_DEVELOPMENTONLY, "How long after a vote passes until the action happens", false, 0.f, true, 4.5f );
+ConVar sv_allow_votes( "sv_allow_votes", "1", FCVAR_NONE, "Allow voting?" );
ConVar sv_vote_failure_timer( "sv_vote_failure_timer", "300", FCVAR_NONE, "A vote that fails cannot be re-submitted for this long" );
#ifdef TF_DLL
ConVar sv_vote_failure_timer_mvm( "sv_vote_failure_timer_mvm", "120", FCVAR_NONE, "A vote that fails in MvM cannot be re-submitted for this long" );
#endif // TF_DLL
-ConVar sv_vote_creation_timer("sv_vote_creation_timer", "120", FCVAR_DEVELOPMENTONLY, "How often someone can individually call a vote.");
-ConVar sv_vote_quorum_ratio( "sv_vote_quorum_ratio", "0.6", FCVAR_HIDDEN, "The minimum ratio of players needed to vote on an issue to resolve it.", true, 0.1, true, 1.0 );
+ConVar sv_vote_creation_timer( "sv_vote_creation_timer", "150", FCVAR_NONE, "How long before a player can attempt to call another vote (in seconds)." );
+ConVar sv_vote_quorum_ratio( "sv_vote_quorum_ratio", "0.6", FCVAR_NOTIFY, "The minimum ratio of eligible players needed to pass a vote. Min 0.5, Max 1.0.", true, 0.1f, true, 1.0f );
ConVar sv_vote_allow_spectators( "sv_vote_allow_spectators", "0", FCVAR_NONE, "Allow spectators to vote?" );
ConVar sv_vote_ui_hide_disabled_issues( "sv_vote_ui_hide_disabled_issues", "1", FCVAR_NONE, "Suppress listing of disabled issues in the vote setup screen." );
@@ -61,7 +62,9 @@ public:
CVoteControllerSystem( char const *name ) : CAutoGameSystemPerFrame( name )
{
SetDefLessFunc( m_mapKickWatchList );
+ SetDefLessFunc( m_mapNameLockedList );
m_flNextKickCheckTime = 0.f;
+ m_flNextNameLockCheckTime = 0.f;
}
virtual void LevelInitPreEntity()
@@ -93,38 +96,54 @@ public:
break; // Constantly called code - resume on next pass
}
- CBasePlayer *pTarget = NULL;
- CSteamID steamIDPlayer;
- for ( int j = 1; j <= gpGlobals->maxClients; j++ )
+ CBasePlayer *pTarget = UTIL_PlayerBySteamID( m_mapKickWatchList.Key( i ) );
+ if ( pTarget )
{
- CBasePlayer *pPlayer = UTIL_PlayerByIndex( j );
- if ( !pPlayer )
- continue;
+ // Welcome back
+ engine->ServerCommand( CFmtStr( "kickid %d %s;", pTarget->GetUserID(), "Kicked by server." ) );
+ }
+ }
- if ( pPlayer->GetSteamID( &steamIDPlayer ) == false )
- continue;
+ m_flNextKickCheckTime = gpGlobals->curtime + 0.2f;
+ }
- if ( steamIDPlayer == m_mapKickWatchList.Key( i ) )
+ // Name lock management
+ if ( m_flNextNameLockCheckTime < gpGlobals->curtime )
+ {
+ FOR_EACH_MAP( m_mapNameLockedList, i )
+ {
+ CBasePlayer *pPlayer = UTIL_PlayerBySteamID( m_mapNameLockedList.Key( i ) );
+
+ // Time up?
+ if ( gpGlobals->curtime > m_mapNameLockedList[i] )
+ {
+ // Disable the lock if they're still here
+ if ( pPlayer )
{
- pTarget = pPlayer;
- break;
+ engine->ServerCommand( UTIL_VarArgs( "namelockid %d %d\n", pPlayer->GetUserID(), 0 ) );
}
- }
- if ( pTarget )
+ // Remove and break - this will re-run in 1 second
+ m_mapNameLockedList.RemoveAt( i );
+ break;
+ }
+ // See if they reconnected
+ else if ( pPlayer && !engine->IsPlayerNameLocked( pPlayer->edict() ) )
{
- // Welcome back
- engine->ServerCommand( CFmtStr( "kickid %d %s;", pTarget->GetUserID(), "Kicked by server." ) );
+ engine->ServerCommand( UTIL_VarArgs( "namelockid %d %d\n", pPlayer->GetUserID(), 1 ) );
}
}
- m_flNextKickCheckTime = gpGlobals->curtime + 0.2f;
+ m_flNextNameLockCheckTime = gpGlobals->curtime + 1.f;
}
}
}
void AddPlayerToKickWatchList( CSteamID steamID, float flDuration )
{
+ if ( !steamID.IsValid() || !steamID.BIndividualAccount() )
+ return;
+
flDuration = clamp( flDuration, 1.f, (float)k_nKickWatchListMaxDuration );
if ( m_mapKickWatchList.Find( steamID ) == m_mapKickWatchList.InvalidIndex() )
{
@@ -132,10 +151,24 @@ public:
}
}
+ void AddPlayerToNameLockedList( CSteamID steamID, float flDuration )
+ {
+ if ( !steamID.IsValid() || !steamID.BIndividualAccount() )
+ return;
+
+ flDuration = clamp( flDuration, 1.f, (float)k_nKickWatchListMaxDuration );
+ if ( m_mapNameLockedList.Find( steamID ) == m_mapNameLockedList.InvalidIndex() )
+ {
+ m_mapNameLockedList.Insert( steamID, ( gpGlobals->curtime + flDuration ) );
+ }
+ }
+
private:
CUtlMap< CSteamID, float > m_mapKickWatchList;
+ CUtlMap< CSteamID, float > m_mapNameLockedList;
float m_flNextKickCheckTime;
+ float m_flNextNameLockCheckTime;
};
CVoteControllerSystem VoteControllerSystem( "CVoteControllerSystem" );
@@ -185,7 +218,7 @@ CON_COMMAND( callvote, "Start a vote on an issue." )
}
CBasePlayer *pVoteCaller = UTIL_GetCommandClient();
- if( !pVoteCaller )
+ if ( !pVoteCaller )
return;
if ( !sv_vote_allow_spectators.GetBool() )
@@ -197,15 +230,21 @@ CON_COMMAND( callvote, "Start a vote on an issue." )
}
}
- // Prevent spamming commands
-#ifndef _DEBUG
+ if ( g_voteController->IsVoteActive() )
+ {
+ ClientPrint( pVoteCaller, HUD_PRINTCENTER, "#GameUI_vote_failed_vote_in_progress" );
+ return;
+ }
+
+ // Ask the controller if this is allowed
int nCooldown = 0;
- if ( !g_voteController->CanEntityCallVote( pVoteCaller, nCooldown ) )
+ vote_create_failed_t nError = VOTE_FAILED_GENERIC;
+
+ if ( !g_voteController->CanEntityCallVote( pVoteCaller, nCooldown, nError ) )
{
- g_voteController->SendVoteCreationFailedMessage( VOTE_FAILED_RATE_EXCEEDED, pVoteCaller, nCooldown );
+ g_voteController->SendVoteCreationFailedMessage( nError, pVoteCaller, nCooldown );
return;
}
-#endif
// Parameters
char szEmptyDetails[MAX_VOTE_DETAILS_LENGTH];
@@ -214,7 +253,7 @@ CON_COMMAND( callvote, "Start a vote on an issue." )
const char *arg3 = args.ArgC() >= 3 ? args[2] : szEmptyDetails;
// If we don't have any arguments, invoke VoteSetup UI
- if( args.ArgC() < 2 )
+ if ( args.ArgC() < 2 )
{
g_voteController->SetupVote( pVoteCaller->entindex() );
return;
@@ -252,7 +291,7 @@ void CVoteController::ResetData( void )
m_acceptingVotesTimer.Invalidate();
m_executeCommandTimer.Invalidate();
m_iEntityHoldingVote = -1;
- m_iOnlyTeamToVote = TEAM_INVALID;
+ m_iOnlyTeamToVote = TEAM_UNASSIGNED;
m_bIsYesNoVote = true;
for( int voteIndex = 0; voteIndex < ARRAYSIZE( m_nVotesCast ); ++voteIndex )
@@ -290,9 +329,22 @@ int CVoteController::UpdateTransmitState( void )
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
+bool CVoteController::IsVoteSystemEnabled( void )
+{
+#ifdef TF_DLL
+ if ( TFGameRules() && TFGameRules()->IsCompetitiveMode() )
+ return false;
+#endif // TF_DLL
+
+ return sv_allow_votes.GetBool();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
bool CVoteController::CanTeamCastVote( int iTeam ) const
{
- if ( m_iOnlyTeamToVote == TEAM_INVALID )
+ if ( m_iOnlyTeamToVote == TEAM_UNASSIGNED )
return true;
return iTeam == m_iOnlyTeamToVote;
@@ -310,7 +362,7 @@ bool CVoteController::SetupVote( int iEntIndex )
int nIssueCount = 0;
// Passing an nIssueCount of 0 triggers a "Voting disabled on server" message in the setup UI
- if ( sv_allow_votes.GetBool() )
+ if ( IsVoteSystemEnabled() )
{
for( int iIndex = 0; iIndex < m_potentialIssues.Count(); ++iIndex )
{
@@ -330,28 +382,28 @@ bool CVoteController::SetupVote( int iEntIndex )
filter.MakeReliable();
UserMessageBegin( filter, "VoteSetup" );
WRITE_BYTE( nIssueCount );
+ int nMsgSize = 0;
for( int iIndex = 0; iIndex < m_potentialIssues.Count(); ++iIndex )
{
CBaseIssue *pCurrentIssue = m_potentialIssues[iIndex];
if ( pCurrentIssue )
{
- if ( pCurrentIssue->IsEnabled() )
- {
- WRITE_STRING( pCurrentIssue->GetTypeString() );
- }
- else
- {
- // Don't send/display disabled issues when set
- if ( sv_vote_ui_hide_disabled_issues.GetBool() )
- continue;
-
- char szDisabledIssueStr[MAX_COMMAND_LENGTH + 12];
- V_strcpy( szDisabledIssueStr, pCurrentIssue->GetTypeString() );
- V_strcat( szDisabledIssueStr, " (Disabled on Server)", sizeof(szDisabledIssueStr) );
-
- WRITE_STRING( szDisabledIssueStr );
- }
+ // Don't send/display disabled issues when set
+ if ( !pCurrentIssue->IsEnabled() && sv_vote_ui_hide_disabled_issues.GetBool() )
+ continue;
+
+ // Don't exceed MAX_USER_MSG_DATA (hack)
+ nMsgSize += ( V_strlen( pCurrentIssue->GetTypeString() ) + 1 );
+ nMsgSize += ( V_strlen( pCurrentIssue->GetTypeStringLocalized() ) + 1 );
+ ++nMsgSize;
+ Assert( nMsgSize <= MAX_USER_MSG_DATA );
+ if ( nMsgSize > MAX_USER_MSG_DATA )
+ continue;
+
+ WRITE_STRING( pCurrentIssue->GetTypeString() );
+ WRITE_STRING( pCurrentIssue->GetTypeStringLocalized() );
+ WRITE_BYTE( pCurrentIssue->IsEnabled() );
}
}
@@ -368,29 +420,29 @@ bool CVoteController::CreateVote( int iEntIndex, const char *pszTypeString, cons
// Terrible Hack: Dedicated servers pass 99 as the EntIndex
bool bDedicatedServer = ( iEntIndex == DEDICATED_SERVER ) ? true : false;
- if( !sv_allow_votes.GetBool() )
+ if ( !IsVoteSystemEnabled() )
return false;
// Already running a vote?
- if( IsVoteActive() )
+ if ( IsVoteActive() )
return false;
CBasePlayer *pVoteCaller = UTIL_PlayerByIndex( iEntIndex );
- if( !pVoteCaller && !bDedicatedServer )
+ if ( !pVoteCaller && !bDedicatedServer )
return false;
// Find the issue the user is asking for
- for( int issueIndex = 0; issueIndex < m_potentialIssues.Count(); ++issueIndex )
+ for ( int issueIndex = 0; issueIndex < m_potentialIssues.Count(); ++issueIndex )
{
CBaseIssue *pCurrentIssue = m_potentialIssues[issueIndex];
if ( !pCurrentIssue )
return false;
- if( FStrEq( pszTypeString, pCurrentIssue->GetTypeString() ) )
+ if ( FStrEq( pszTypeString, pCurrentIssue->GetTypeString() ) )
{
vote_create_failed_t nErrorCode = VOTE_FAILED_GENERIC;
int nTime = 0;
- if( pCurrentIssue->CanCallVote( iEntIndex, pszDetailString, nErrorCode, nTime ) )
+ if ( pCurrentIssue->CanCallVote( iEntIndex, pszDetailString, nErrorCode, nTime ) )
{
// Establish a bunch of data on this particular issue
pCurrentIssue->SetIssueDetails( pszDetailString );
@@ -399,14 +451,7 @@ bool CVoteController::CreateVote( int iEntIndex, const char *pszTypeString, cons
m_iEntityHoldingVote = iEntIndex;
if ( !bDedicatedServer )
{
- if( pCurrentIssue->IsAllyRestrictedVote() )
- {
- m_iOnlyTeamToVote = GetVoterTeam( pVoteCaller );
- }
- else
- {
- m_iOnlyTeamToVote = TEAM_INVALID;
- }
+ m_iOnlyTeamToVote = ( pCurrentIssue->IsTeamRestrictedVote() ) ? GetVoterTeam( pVoteCaller ) : TEAM_UNASSIGNED;
}
// Now get our choices
@@ -442,10 +487,10 @@ bool CVoteController::CreateVote( int iEntIndex, const char *pszTypeString, cons
// Now the vote handling and UI
m_nPotentialVotes = pCurrentIssue->CountPotentialVoters();
- m_acceptingVotesTimer.Start( sv_vote_timer_duration.GetFloat() );
+ m_acceptingVotesTimer.Start( sv_vote_timer_duration.GetFloat() + random->RandomFloat( -1.f, 1.f ) );
// Force the vote holder to agree with a Yes/No vote
- if ( m_bIsYesNoVote && !bDedicatedServer )
+ if ( pCurrentIssue->IsYesNoVote() && !bDedicatedServer )
{
TryCastVote( iEntIndex, "Option1" );
}
@@ -458,7 +503,7 @@ bool CVoteController::CreateVote( int iEntIndex, const char *pszTypeString, cons
WRITE_BYTE( m_iEntityHoldingVote );
WRITE_STRING( pCurrentIssue->GetDisplayString() );
WRITE_STRING( pCurrentIssue->GetDetailsString() );
- WRITE_BOOL( m_bIsYesNoVote );
+ WRITE_BOOL( pCurrentIssue->IsYesNoVote() );
MessageEnd();
if ( !bDedicatedServer )
@@ -506,11 +551,7 @@ void CVoteController::SendVoteFailedToPassMessage( vote_create_failed_t nReason
{
Assert( m_potentialIssues[m_iActiveIssueIndex] );
- // See if we have a player target.
- CBasePlayer *pVoteTarget = m_potentialIssues[m_iActiveIssueIndex]->m_hPlayerTarget;
- bool bFakeClient = ( pVoteTarget && ( pVoteTarget->IsFakeClient() || pVoteTarget->IsHLTV() || pVoteTarget->IsReplay() ) );
-
- UTIL_LogPrintf( "Vote failed \"%s %s\" with code %i (proxy: %i) \n", m_potentialIssues[m_iActiveIssueIndex]->GetTypeString(), m_potentialIssues[m_iActiveIssueIndex]->GetDetailsString(), (int)nReason, bFakeClient );
+ UTIL_LogPrintf( "Vote failed \"%s %s\" with code %i\n", m_potentialIssues[m_iActiveIssueIndex]->GetTypeString(), m_potentialIssues[m_iActiveIssueIndex]->GetDetailsString(), (int)nReason );
CBroadcastRecipientFilter filter;
filter.MakeReliable();
@@ -526,24 +567,24 @@ void CVoteController::SendVoteFailedToPassMessage( vote_create_failed_t nReason
//-----------------------------------------------------------------------------
CVoteController::TryCastVoteResult CVoteController::TryCastVote( int iEntIndex, const char *pszVoteString )
{
- if( !sv_allow_votes.GetBool() )
+ if ( !IsVoteSystemEnabled() )
return CAST_FAIL_SERVER_DISABLE;
- if( iEntIndex >= ARRAYSIZE( m_nVotesCast ) )
+ if ( iEntIndex >= ARRAYSIZE( m_nVotesCast ) )
return CAST_FAIL_SYSTEM_ERROR;
- if( !IsVoteActive() )
+ if ( !IsVoteActive() )
return CAST_FAIL_NO_ACTIVE_ISSUE;
- if( m_executeCommandTimer.HasStarted() )
+ if ( m_executeCommandTimer.HasStarted() )
return CAST_FAIL_VOTE_CLOSED;
- if( m_potentialIssues[m_iActiveIssueIndex] && m_potentialIssues[m_iActiveIssueIndex]->IsAllyRestrictedVote() )
+ if ( m_potentialIssues[m_iActiveIssueIndex] && m_potentialIssues[m_iActiveIssueIndex]->IsTeamRestrictedVote() )
{
CBaseEntity *pVoteHolder = UTIL_EntityByIndex( m_iEntityHoldingVote );
CBaseEntity *pVoter = UTIL_EntityByIndex( iEntIndex );
- if( ( pVoteHolder == NULL ) || ( pVoter == NULL ) || ( GetVoterTeam( pVoteHolder ) != GetVoterTeam( pVoter ) ) )
+ if ( ( pVoteHolder == NULL ) || ( pVoter == NULL ) || ( GetVoterTeam( pVoteHolder ) != GetVoterTeam( pVoter ) ) )
{
return CAST_FAIL_TEAM_RESTRICTED;
}
@@ -552,7 +593,7 @@ CVoteController::TryCastVoteResult CVoteController::TryCastVote( int iEntIndex,
// Look for a previous vote
int nOldVote = m_nVotesCast[iEntIndex];
#ifndef DEBUG
- if( nOldVote != VOTE_UNCAST )
+ if ( nOldVote != VOTE_UNCAST )
{
return CAST_FAIL_NO_CHANGES;
}
@@ -644,67 +685,54 @@ void CVoteController::VoteControllerThink( void )
}
// Vote time is up - process the result
- if( m_acceptingVotesTimer.HasStarted() && m_acceptingVotesTimer.IsElapsed() )
+ if ( m_acceptingVotesTimer.HasStarted() && m_acceptingVotesTimer.IsElapsed() )
{
m_acceptingVotesTimer.Invalidate();
- int nVoteTally = 0;
- for ( int index = 0; index < MAX_VOTE_OPTIONS; index++ )
- {
- nVoteTally += m_nVoteOptionCount.Get( index );
- }
-
- bool bVotePassed = true;
-
- // for record-keeping
+ // For GC record-keeping
if ( m_potentialIssues[m_iActiveIssueIndex]->IsYesNoVote() )
{
m_potentialIssues[m_iActiveIssueIndex]->SetYesNoVoteCount( m_nVoteOptionCount[VOTE_OPTION1], m_nVoteOptionCount[VOTE_OPTION2], m_nPotentialVotes );
}
- // Have we exceeded the required ratio of Voted-vs-Abstained?
- if ( nVoteTally >= m_nPotentialVotes * sv_vote_quorum_ratio.GetFloat() )
- {
- int nWinningVoteOption = GetWinningVoteOption();
- Assert( nWinningVoteOption >= 0 && nWinningVoteOption < m_VoteOptions.Count() );
+ bool bVotePassed = false;
- if ( nWinningVoteOption >= 0 && nWinningVoteOption < MAX_VOTE_OPTIONS )
+ if ( GetNumVotesCast() >= ( m_nPotentialVotes * m_potentialIssues[m_iActiveIssueIndex]->GetQuorumRatio() ) )
+ {
+ int nPassingVoteOptionIndex = GetVoteIssueIndexWithHighestCount();
+ if ( nPassingVoteOptionIndex >= 0 && nPassingVoteOptionIndex < MAX_VOTE_OPTIONS )
{
- // YES/NO VOTES
+ // YES/NO VOTES - hard-wired to VOTE_OPTION1 (Yes)
if ( m_potentialIssues[m_iActiveIssueIndex]->IsYesNoVote() )
{
- // Option1 is Yes
- if ( nWinningVoteOption != VOTE_OPTION1 )
+ if ( nPassingVoteOptionIndex == VOTE_OPTION1 )
{
- SendVoteFailedToPassMessage( VOTE_FAILED_YES_MUST_EXCEED_NO );
- bVotePassed = false;
- }
+ bVotePassed = true;
+ }
}
- // GENERAL VOTES:
- // We set the details string after the vote, since that's when
- // we finally have a parameter to pass along and execute
- else if ( nWinningVoteOption < m_VoteOptions.Count() )
+ // GENERAL VOTES - as long as there's a quorum, go with the most popular choice
+ else
{
- m_potentialIssues[m_iActiveIssueIndex]->SetIssueDetails( m_VoteOptions[nWinningVoteOption] );
+ bVotePassed = true;
+
+ // We set the details string after the vote, since that's when
+ // we finally have a parameter to pass along and execute
+ m_potentialIssues[m_iActiveIssueIndex]->SetIssueDetails( m_VoteOptions[nPassingVoteOptionIndex] );
}
}
}
- else
- {
- SendVoteFailedToPassMessage( VOTE_FAILED_QUORUM_FAILURE );
- bVotePassed = false;
- }
- if ( bVotePassed )
+ if ( bVotePassed )
{
- m_executeCommandTimer.Start( sv_vote_command_delay.GetFloat() );
- m_resetVoteTimer.Start( 5.0 );
-
- // Target is not always a player (changelevel, etc)
+ // Always NULL check, as some votes don't target players (i.e. ChangeLevel)
CBasePlayer *pVoteTarget = m_potentialIssues[m_iActiveIssueIndex]->m_hPlayerTarget;
- bool bFakeClient = ( pVoteTarget && ( pVoteTarget->IsFakeClient() || pVoteTarget->IsHLTV() || pVoteTarget->IsReplay() ) );
- UTIL_LogPrintf( "Vote succeeded \"%s %s\" (proxy: %i) \n", m_potentialIssues[m_iActiveIssueIndex]->GetTypeString(), m_potentialIssues[m_iActiveIssueIndex]->GetDetailsString(), bFakeClient );
+ // Don't delay successful kick votes
+ float flDelay = IsPlayerBeingKicked( pVoteTarget ) ? 0.f : sv_vote_command_delay.GetFloat();
+ m_executeCommandTimer.Start( flDelay );
+ m_resetVoteTimer.Start( 5.f );
+
+ UTIL_LogPrintf( "Vote succeeded \"%s %s\"\n", m_potentialIssues[m_iActiveIssueIndex]->GetTypeString(), m_potentialIssues[m_iActiveIssueIndex]->GetDetailsString() );
CBroadcastRecipientFilter filter;
filter.MakeReliable();
@@ -717,8 +745,10 @@ void CVoteController::VoteControllerThink( void )
}
else
{
+ vote_create_failed_t nReason = m_potentialIssues[m_iActiveIssueIndex]->IsYesNoVote() ? VOTE_FAILED_YES_MUST_EXCEED_NO : VOTE_FAILED_QUORUM_FAILURE;
+ SendVoteFailedToPassMessage( nReason );
m_potentialIssues[m_iActiveIssueIndex]->OnVoteFailed( m_iEntityHoldingVote );
- m_resetVoteTimer.Start( 5.0 );
+ m_resetVoteTimer.Start( 5.f );
}
}
@@ -768,12 +798,15 @@ void CVoteController::CheckForEarlyVoteClose( void )
//-----------------------------------------------------------------------------
bool CVoteController::IsValidVoter( CBasePlayer *pWhom )
{
- if ( pWhom == NULL )
+ if ( !pWhom )
return false;
if ( !pWhom->IsConnected() )
return false;
+ if ( pWhom->GetTeamNumber() == TEAM_UNASSIGNED )
+ return false;
+
if ( !sv_vote_allow_spectators.GetBool() )
{
if ( pWhom->GetTeamNumber() == TEAM_SPECTATOR )
@@ -818,7 +851,7 @@ void CVoteController::RegisterIssue( CBaseIssue *pszNewIssue )
//-----------------------------------------------------------------------------
void CVoteController::ListIssues( CBasePlayer *pForWhom )
{
- if( !sv_allow_votes.GetBool() )
+ if ( !IsVoteSystemEnabled() )
return;
ClientPrint( pForWhom, HUD_PRINTCONSOLE, "---Vote commands---\n" );
@@ -832,45 +865,34 @@ void CVoteController::ListIssues( CBasePlayer *pForWhom )
}
//-----------------------------------------------------------------------------
-// Purpose:
+// Purpose: -1 when invalid
//-----------------------------------------------------------------------------
-int CVoteController::GetWinningVoteOption( void )
+int CVoteController::GetVoteIssueIndexWithHighestCount( void )
{
- if ( m_potentialIssues[m_iActiveIssueIndex]->IsYesNoVote() )
+ int nMaxIndex = -1;
+
+ // Legacy Yes/No system
+ if ( m_iActiveIssueIndex != INVALID_ISSUE && m_potentialIssues[m_iActiveIssueIndex]->IsYesNoVote() )
{
return ( m_nVoteOptionCount[VOTE_OPTION1] > m_nVoteOptionCount[VOTE_OPTION2] ) ? VOTE_OPTION1 : VOTE_OPTION2;
}
+ // Which option had the most votes?
else
{
- CUtlVector <int> pVoteCounts;
+ int nMaxCount = 0;
- // Which option had the most votes?
- // driller: Need to handle ties
- int nHighest = m_nVoteOptionCount[0];
+ // TODO: Handle ties
for ( int iIndex = 0; iIndex < m_nVoteOptionCount.Count(); iIndex ++ )
{
- nHighest = ( ( nHighest < m_nVoteOptionCount[iIndex] ) ? m_nVoteOptionCount[iIndex] : nHighest );
- pVoteCounts.AddToTail( m_nVoteOptionCount[iIndex] );
- }
-
- m_nHighestCountIndex = -1;
- for ( int iIndex = 0; iIndex < m_nVoteOptionCount.Count(); iIndex++ )
- {
- if ( m_nVoteOptionCount[iIndex] == nHighest )
+ if ( m_nVoteOptionCount[iIndex] && m_nVoteOptionCount[iIndex] > nMaxCount )
{
- m_nHighestCountIndex = iIndex;
- // henryg: break on first match, not last. this avoids a crash
- // if we are all tied at zero and we pick something beyond the
- // last vote option. this code really ought to ignore attempts
- // to tally votes for options beyond the last valid one!
- break;
+ nMaxCount = m_nVoteOptionCount[iIndex];
+ nMaxIndex = iIndex;
}
}
-
- return m_nHighestCountIndex;
}
- return -1;
+ return nMaxIndex;
}
//-----------------------------------------------------------------------------
@@ -898,11 +920,12 @@ void CVoteController::TrackVoteCaller( CBasePlayer *pPlayer )
//-----------------------------------------------------------------------------
// Purpose: Check the history of steamIDs that called votes and test against a timer
//-----------------------------------------------------------------------------
-bool CVoteController::CanEntityCallVote( CBasePlayer *pPlayer, int &nCooldown )
+bool CVoteController::CanEntityCallVote( CBasePlayer *pPlayer, int &nCooldown, vote_create_failed_t &nErrorCode )
{
if ( !pPlayer )
return false;
-
+
+#ifndef _DEBUG
CSteamID steamID;
pPlayer->GetSteamID( &steamID );
@@ -913,11 +936,15 @@ bool CVoteController::CanEntityCallVote( CBasePlayer *pPlayer, int &nCooldown )
// Timer elapsed?
nCooldown = (int)( m_VoteCallers[ iIdx ] - gpGlobals->curtime );
if ( nCooldown > 0 )
+ {
+ nErrorCode = VOTE_FAILED_RATE_EXCEEDED;
return false;
+ }
// Expired
m_VoteCallers.Remove( iIdx );
}
+#endif
return true;
};
@@ -925,17 +952,61 @@ bool CVoteController::CanEntityCallVote( CBasePlayer *pPlayer, int &nCooldown )
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
+int CVoteController::GetNumVotesCast( void )
+{
+ int nVoteTally = 0;
+
+ for ( int index = 0; index < MAX_VOTE_OPTIONS; index++ )
+ {
+ nVoteTally += m_nVoteOptionCount.Get( index );
+ }
+
+ return nVoteTally;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
void CVoteController::AddPlayerToKickWatchList( CSteamID steamID, float flDuration )
{
VoteControllerSystem.AddPlayerToKickWatchList( steamID, flDuration );
}
//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CVoteController::AddPlayerToNameLockedList( CSteamID steamID, float flDuration, int nUserID )
+{
+ engine->ServerCommand( UTIL_VarArgs( "namelockid %d %d\n", nUserID, 1 ) );
+
+ VoteControllerSystem.AddPlayerToNameLockedList( steamID, flDuration );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+bool CVoteController::IsPlayerBeingKicked( CBasePlayer *pPlayer )
+{
+#ifdef TF_DLL
+ if ( pPlayer && m_iActiveIssueIndex != INVALID_ISSUE )
+ {
+ CKickIssue *pKickIssue = dynamic_cast< CKickIssue* >( m_potentialIssues[m_iActiveIssueIndex] );
+ if ( pKickIssue )
+ {
+ return pKickIssue->m_hPlayerTarget == pPlayer;
+ }
+ }
+#endif // TF_DLL
+
+ return false;
+}
+
+//-----------------------------------------------------------------------------
// Purpose: BaseIssue
//-----------------------------------------------------------------------------
CBaseIssue::CBaseIssue( const char *pszTypeString )
{
- Q_strcpy( m_szTypeString, pszTypeString );
+ V_strcpy_safe( m_szTypeString, pszTypeString );
m_iNumYesVotes = 0;
m_iNumNoVotes = 0;
@@ -979,13 +1050,13 @@ const char *CBaseIssue::GetDetailsString( void )
//-----------------------------------------------------------------------------
void CBaseIssue::SetIssueDetails( const char *pszDetails )
{
- Q_strcpy( m_szDetailsString, pszDetails );
+ V_strcpy_safe( m_szDetailsString, pszDetails );
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
-bool CBaseIssue::IsAllyRestrictedVote( void )
+bool CBaseIssue::IsTeamRestrictedVote( void )
{
return false;
}
@@ -1030,7 +1101,7 @@ void CBaseIssue::OnVoteFailed( int iEntityHoldingVote )
// Need to create a new one
FailedVote *pNewFailedVote = new FailedVote;
int iIndex = m_FailedVotes.AddToTail( pNewFailedVote );
- Q_strcpy( m_FailedVotes[iIndex]->szFailedVoteParameter, GetDetailsString() );
+ V_strcpy_safe( m_FailedVotes[iIndex]->szFailedVoteParameter, GetDetailsString() );
m_FailedVotes[iIndex]->flLockoutTime = gpGlobals->curtime + sv_vote_failure_timer.GetFloat();
}
}
@@ -1184,4 +1255,12 @@ bool CBaseIssue::GetVoteOptions( CUtlVector <const char*> &vecNames )
return true;
}
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+float CBaseIssue::GetQuorumRatio( void )
+{
+ return sv_vote_quorum_ratio.GetFloat();
+}
+
diff --git a/mp/src/game/server/vote_controller.h b/mp/src/game/server/vote_controller.h
index ccc55cd5..a3f82ff6 100644
--- a/mp/src/game/server/vote_controller.h
+++ b/mp/src/game/server/vote_controller.h
@@ -20,17 +20,18 @@
class CBaseIssue // Base class concept for vote issues (i.e. Kick Player). Created per level-load and destroyed by CVoteController's dtor.
{
public:
- CBaseIssue(const char *typeString);
- virtual ~CBaseIssue();
+ CBaseIssue( const char *typeString );
+ virtual ~CBaseIssue();
const char *GetTypeString( void ); // Connection between console command and specific type of issue
- virtual const char *GetDetailsString();
+ virtual const char *GetTypeStringLocalized( void ) { return ""; } // When empty, the client uses the classname string and prepends "#Vote_"
+ virtual const char *GetDetailsString( void );
virtual void SetIssueDetails( const char *pszDetails ); // We need to know the details part of the con command for later
virtual void OnVoteFailed( int iEntityHoldingVote ); // The moment the vote fails, also has some time for feedback before the window goes away
virtual void OnVoteStarted( void ) {} // Called as soon as the vote starts
virtual bool IsEnabled( void ) { return false; } // Query the issue to see if it's enabled
virtual bool CanTeamCallVote( int iTeam ) const; // Can someone on the given team call this vote?
virtual bool CanCallVote( int nEntIndex, const char *pszDetails, vote_create_failed_t &nFailCode, int &nTime ); // Can this guy hold a vote on this issue?
- virtual bool IsAllyRestrictedVote( void ); // Can only members of the same team vote on this?
+ virtual bool IsTeamRestrictedVote( void ); // Restrict access and visibility of this vote to a specific team?
virtual const char *GetDisplayString( void ) = 0; // The string that will be passed to the client for display
virtual void ExecuteCommand( void ) = 0; // Where the magic happens. Do your thing.
virtual void ListIssueDetails( CBasePlayer *pForWhom ) = 0; // Someone would like to know all your valid details
@@ -42,6 +43,7 @@ public:
virtual bool GetVoteOptions( CUtlVector <const char*> &vecNames ); // We use this to generate options for voting
virtual bool BRecordVoteFailureEventForEntity( int iVoteCallingEntityIndex ) const { return iVoteCallingEntityIndex != DEDICATED_SERVER; }
void SetIssueCooldownDuration( float flDuration ) { m_flNextCallTime = gpGlobals->curtime + flDuration; } // The issue can not be raised again for this period of time (in seconds)
+ virtual float GetQuorumRatio( void ); // Each issue can decide the required ratio of voted-vs-abstained
CHandle< CBasePlayer > m_hPlayerTarget; // If the target of the issue is a player, we should store them here
@@ -54,11 +56,9 @@ protected:
float flLockoutTime;
};
- CUtlVector<FailedVote *> m_FailedVotes;
-
- char m_szTypeString[MAX_COMMAND_LENGTH];
- char m_szDetailsString[MAX_VOTE_DETAILS_LENGTH];
-
+ CUtlVector< FailedVote* > m_FailedVotes;
+ char m_szTypeString[MAX_COMMAND_LENGTH];
+ char m_szDetailsString[MAX_VOTE_DETAILS_LENGTH];
int m_iNumYesVotes;
int m_iNumNoVotes;
int m_iNumPotentialVotes;
@@ -89,6 +89,7 @@ public:
virtual void Spawn( void );
virtual int UpdateTransmitState( void );
+ virtual bool IsVoteSystemEnabled( void );
bool SetupVote( int iEntIndex ); // This creates a list of issues for the UI
bool CreateVote( int iEntIndex, const char *pszTypeString, const char *pszDetailString ); // This is what the UI passes in
@@ -101,12 +102,15 @@ public:
void SendVoteFailedToPassMessage( vote_create_failed_t nReason );
void VoteChoice_Increment( int nVoteChoice );
void VoteChoice_Decrement( int nVoteChoice );
- int GetWinningVoteOption( void );
+ int GetVoteIssueIndexWithHighestCount( void );
void TrackVoteCaller( CBasePlayer *pPlayer );
- bool CanEntityCallVote( CBasePlayer *pPlayer, int &nCooldown );
+ bool CanEntityCallVote( CBasePlayer *pPlayer, int &nCooldown, vote_create_failed_t &nErrorCode );
bool IsVoteActive( void ) { return m_iActiveIssueIndex != INVALID_ISSUE; }
+ int GetNumVotesCast( void );
- void AddPlayerToKickWatchList( CSteamID steamID, float flDuration );
+ void AddPlayerToKickWatchList( CSteamID steamID, float flDuration ); // Band-aid until we figure out how player's avoid kick votes
+ void AddPlayerToNameLockedList( CSteamID steamID, float flDuration, int nUserID );
+ bool IsPlayerBeingKicked( CBasePlayer *pPlayer );
protected:
void ResetData( void );
@@ -123,7 +127,6 @@ protected:
CountdownTimer m_resetVoteTimer; // when the current vote will end
int m_nVotesCast[MAX_PLAYERS + 1]; // arrays are zero-based and player indices are one-based
int m_iEntityHoldingVote;
- int m_nHighestCountIndex;
CUtlVector <CBaseIssue *> m_potentialIssues;
CUtlVector <const char *> m_VoteOptions;
diff --git a/mp/src/game/shared/GameStats.cpp b/mp/src/game/shared/GameStats.cpp
index d01e56fb..7351647b 100644
--- a/mp/src/game/shared/GameStats.cpp
+++ b/mp/src/game/shared/GameStats.cpp
@@ -46,6 +46,11 @@ extern const ConVar *sv_cheats;
#endif
#endif
+#ifdef CLIENT_DLL
+ // Ensure this is declared in the client dll so everyone finds the same one.
+ ConVar dev_loadtime_mainmenu("dev_loadtime_mainmenu", "0.0", FCVAR_HIDDEN );
+#endif
+
// NOTE: This has to be the last file included!
#include "tier0/memdbgon.h"
@@ -141,7 +146,7 @@ CBaseGameStats_Driver::CBaseGameStats_Driver( void ) :
m_bDidVoiceChat( false )
{
- m_szLoadedUserID[0] = 0;;
+ m_szLoadedUserID[0] = 0;
m_tLastUpload = 0;
m_LastUserCmd.Reset();
}
@@ -1061,6 +1066,33 @@ void CBaseGameStats_Driver::SendData()
ResetData();
}
+#ifdef CLIENT_DLL
+ // Adds the main menu load time to the specified key values, but only ever does the work once.
+ static void AddLoadTimeMainMenu( KeyValues* pKV )
+ {
+ Assert( pKV );
+ float loadTimeMainMenu = dev_loadtime_mainmenu.GetFloat();
+ if ( loadTimeMainMenu > 0.0f ) {
+ pKV->SetFloat( "LoadTimeMainMenu", loadTimeMainMenu );
+ // Only want to set this once, clear it to 0.0 here. The other code will only ever set it once.
+ dev_loadtime_mainmenu.SetValue( 0.0f );
+ }
+ }
+
+ // Adds the map load time to the specified key values, but clears the elapsed data to 0.0 for next computation.
+ static void AddLoadTimeMap(KeyValues* pKV)
+ {
+ static ConVarRef dev_loadtime_map_elapsed( "dev_loadtime_map_elapsed" );
+ float loadTimeMap = dev_loadtime_map_elapsed.GetFloat();
+ if ( loadTimeMap > 0.0f )
+ {
+ pKV->SetFloat( "LoadTimeMap", loadTimeMap );
+ dev_loadtime_map_elapsed.SetValue( 0.0f );
+ }
+ }
+
+#endif
+
bool CBaseGameStats_Driver::AddBaseDataForSend( KeyValues *pKV, StatSendType_t sendType )
{
switch ( sendType )
@@ -1074,6 +1106,12 @@ bool CBaseGameStats_Driver::AddBaseDataForSend( KeyValues *pKV, StatSendType_t s
pKVData->SetInt( "TotalLevelTime", m_flTotalTimeInLevels );
pKVData->SetInt( "NumLevels", m_iNumLevels );
pKV->AddSubKey( pKVData );
+
+ AddLoadTimeMainMenu( pKV );
+ // If the user quits directly from the map, we still want to (possibly) capture their map load time, so
+ // do add it here. It will not be added if it was already attached to a session.
+ AddLoadTimeMap( pKV );
+
return true;
}
#endif
@@ -1141,6 +1179,9 @@ bool CBaseGameStats_Driver::AddBaseDataForSend( KeyValues *pKV, StatSendType_t s
int mapTime = gpGlobals->realtime - m_flLevelStartTime;
pKV->SetInt( "MapTime", mapTime );
+ AddLoadTimeMainMenu(pKV);
+ AddLoadTimeMap(pKV);
+
return true;
}
#endif
@@ -1177,6 +1218,10 @@ void CBaseGameStats_Driver::ResetData()
OverWriteCharsWeHate( cpu.m_szProcessorID );
pKV->SetString( "CPUID", cpu.m_szProcessorID );
pKV->SetFloat( "CPUGhz", cpu.m_Speed * ( 1.0 / 1.0e9 ) );
+ pKV->SetUint64( "CPUModel", cpu.m_nModel );
+ pKV->SetUint64( "CPUFeatures0", cpu.m_nFeatures[ 0 ] );
+ pKV->SetUint64( "CPUFeatures1", cpu.m_nFeatures[ 1 ] );
+ pKV->SetUint64( "CPUFeatures2", cpu.m_nFeatures[ 2 ] );
pKV->SetInt( "NumCores", cpu.m_nPhysicalProcessors );
MaterialAdapterInfo_t gpu;
diff --git a/mp/src/game/shared/ModelSoundsCache.cpp b/mp/src/game/shared/ModelSoundsCache.cpp
index e6ad628b..4f4f10fb 100644
--- a/mp/src/game/shared/ModelSoundsCache.cpp
+++ b/mp/src/game/shared/ModelSoundsCache.cpp
@@ -68,7 +68,7 @@ void CModelSoundsCache::Restore( CUtlBuffer& buf )
{
char soundname[ 512 ];
- buf.GetString( soundname, sizeof( soundname ) );
+ buf.GetString( soundname );
int idx = soundemitterbase->GetSoundIndex( soundname );
if ( idx != -1 )
diff --git a/mp/src/game/shared/Multiplayer/multiplayer_animstate.cpp b/mp/src/game/shared/Multiplayer/multiplayer_animstate.cpp
index 4d1ad4fe..2734eba0 100644
--- a/mp/src/game/shared/Multiplayer/multiplayer_animstate.cpp
+++ b/mp/src/game/shared/Multiplayer/multiplayer_animstate.cpp
@@ -91,6 +91,10 @@ CMultiPlayerAnimState::CMultiPlayerAnimState( CBasePlayer *pPlayer, MultiPlayerM
m_flMaxGroundSpeed = 0.0f;
+ // If you are forcing aim yaw, your code is almost definitely broken if you don't include a delay between
+ // teleporting and forcing yaw. This is due to an unfortunate interaction between the command lookback window,
+ // and the fact that m_flEyeYaw is never propogated from the server to the client.
+ // TODO: Fix this after Halloween 2014.
m_bForceAimYaw = false;
Init( pPlayer, movementData );
@@ -1655,6 +1659,10 @@ void CMultiPlayerAnimState::ComputePoseParam_AimYaw( CStudioHdr *pStudioHdr )
bool bMoving = ( vecVelocity.Length() > 1.0f ) ? true : false;
// If we are moving or are prone and undeployed.
+ // If you are forcing aim yaw, your code is almost definitely broken if you don't include a delay between
+ // teleporting and forcing yaw. This is due to an unfortunate interaction between the command lookback window,
+ // and the fact that m_flEyeYaw is never propogated from the server to the client.
+ // TODO: Fix this after Halloween 2014.
if ( bMoving || m_bForceAimYaw )
{
// The feet match the eye direction when moving - the move yaw takes care of the rest.
@@ -1688,6 +1696,10 @@ void CMultiPlayerAnimState::ComputePoseParam_AimYaw( CStudioHdr *pStudioHdr )
m_flGoalFeetYaw = AngleNormalize( m_flGoalFeetYaw );
if ( m_flGoalFeetYaw != m_flCurrentFeetYaw )
{
+ // If you are forcing aim yaw, your code is almost definitely broken if you don't include a delay between
+ // teleporting and forcing yaw. This is due to an unfortunate interaction between the command lookback window,
+ // and the fact that m_flEyeYaw is never propogated from the server to the client.
+ // TODO: Fix this after Halloween 2014.
if ( m_bForceAimYaw )
{
m_flCurrentFeetYaw = m_flGoalFeetYaw;
diff --git a/mp/src/game/shared/Multiplayer/multiplayer_animstate.h b/mp/src/game/shared/Multiplayer/multiplayer_animstate.h
index 007533a1..a3c7937a 100644
--- a/mp/src/game/shared/Multiplayer/multiplayer_animstate.h
+++ b/mp/src/game/shared/Multiplayer/multiplayer_animstate.h
@@ -63,6 +63,10 @@ enum PlayerAnimEvent_t
PLAYERANIMEVENT_STUN_BEGIN,
PLAYERANIMEVENT_STUN_MIDDLE,
PLAYERANIMEVENT_STUN_END,
+ PLAYERANIMEVENT_PASSTIME_THROW_BEGIN,
+ PLAYERANIMEVENT_PASSTIME_THROW_MIDDLE,
+ PLAYERANIMEVENT_PASSTIME_THROW_END,
+ PLAYERANIMEVENT_PASSTIME_THROW_CANCEL,
PLAYERANIMEVENT_ATTACK_PRIMARY_SUPER,
@@ -203,6 +207,10 @@ public:
bool VerifyAnimLayerInSlot( int iGestureSlot );
// Feet.
+ // If you are forcing aim yaw, your code is almost definitely broken if you don't include a delay between
+ // teleporting and forcing yaw. This is due to an unfortunate interaction between the command lookback window,
+ // and the fact that m_flEyeYaw is never propogated from the server to the client.
+ // TODO: Fix this after Halloween 2014.
bool m_bForceAimYaw;
protected:
diff --git a/mp/src/game/shared/SceneCache.cpp b/mp/src/game/shared/SceneCache.cpp
index 0728c27b..c993ef46 100644
--- a/mp/src/game/shared/SceneCache.cpp
+++ b/mp/src/game/shared/SceneCache.cpp
@@ -59,7 +59,7 @@ void CSceneCache::Restore( CUtlBuffer& buf )
for ( int i = 0; i < c; ++i )
{
char soundname[ 512 ];
- buf.GetString( soundname, sizeof( soundname ) );
+ buf.GetString( soundname );
int idx = soundemitterbase->GetSoundIndex( soundname );
if ( idx != -1 )
diff --git a/mp/src/game/shared/SoundEmitterSystem.cpp b/mp/src/game/shared/SoundEmitterSystem.cpp
index 7b641c20..39aca858 100644
--- a/mp/src/game/shared/SoundEmitterSystem.cpp
+++ b/mp/src/game/shared/SoundEmitterSystem.cpp
@@ -337,6 +337,15 @@ public:
FinishLog();
#endif
}
+
+ void Flush()
+ {
+ Assert( soundemitterbase );
+#if !defined( CLIENT_DLL )
+ FinishLog();
+#endif
+ soundemitterbase->Flush();
+ }
void InternalPrecacheWaves( int soundIndex )
{
@@ -998,10 +1007,7 @@ void S_SoundEmitterSystemFlush( void )
// save the current soundscape
// kill the system
- g_SoundEmitterSystem.Shutdown();
-
- // restart the system
- g_SoundEmitterSystem.Init();
+ g_SoundEmitterSystem.Flush();
#if !defined( CLIENT_DLL )
// Redo precache all wave files... (this should work now that we have dynamic string tables)
diff --git a/mp/src/game/shared/SpriteTrail.h b/mp/src/game/shared/SpriteTrail.h
index 3e4fb763..2248dc99 100644
--- a/mp/src/game/shared/SpriteTrail.h
+++ b/mp/src/game/shared/SpriteTrail.h
@@ -82,8 +82,8 @@ private:
enum
{
// NOTE: # of points max must be a power of two!
- MAX_SPRITE_TRAIL_POINTS = 64,
- MAX_SPRITE_TRAIL_MASK = 0x3F,
+ MAX_SPRITE_TRAIL_POINTS = 256,
+ MAX_SPRITE_TRAIL_MASK = MAX_SPRITE_TRAIL_POINTS - 1,
};
TrailPoint_t *GetTrailPoint( int n );
@@ -114,6 +114,11 @@ private:
string_t m_iszSpriteName;
bool m_bAnimate;
bool m_bDrawForMoveParent;
+
+#if defined( CLIENT_DLL )
+public:
+ void SetUpdateTime(float setTo){ m_flUpdateTime = setTo; }
+#endif
};
#endif // SPRITETRAIL_H
diff --git a/mp/src/game/shared/activitylist.cpp b/mp/src/game/shared/activitylist.cpp
index 4c882d47..49e93e93 100644
--- a/mp/src/game/shared/activitylist.cpp
+++ b/mp/src/game/shared/activitylist.cpp
@@ -1802,6 +1802,11 @@ void ActivityList_RegisterSharedActivities( void )
REGISTER_SHARED_ACTIVITY( ACT_MP_ATTACK_SWIM_GRENADE_ITEM2 );
REGISTER_SHARED_ACTIVITY( ACT_MP_ATTACK_AIRWALK_GRENADE_ITEM2 );
+ // Passtime
+ REGISTER_SHARED_ACTIVITY( ACT_MP_STAND_PASSTIME );
+ REGISTER_SHARED_ACTIVITY( ACT_MP_RUN_PASSTIME );
+ REGISTER_SHARED_ACTIVITY( ACT_MP_CROUCHWALK_PASSTIME );
+
// Flinches
REGISTER_SHARED_ACTIVITY( ACT_MP_GESTURE_FLINCH );
REGISTER_SHARED_ACTIVITY( ACT_MP_GESTURE_FLINCH_PRIMARY );
@@ -1943,6 +1948,7 @@ void ActivityList_RegisterSharedActivities( void )
REGISTER_SHARED_ACTIVITY ( ACT_MP_DOUBLEJUMP_CROUCH_ITEM1 );
REGISTER_SHARED_ACTIVITY ( ACT_MP_DOUBLEJUMP_CROUCH_ITEM2 );
REGISTER_SHARED_ACTIVITY ( ACT_MP_DOUBLEJUMP_CROUCH_LOSERSTATE );
+ REGISTER_SHARED_ACTIVITY ( ACT_MP_DOUBLEJUMP_CROUCH_PASSTIME );
REGISTER_SHARED_ACTIVITY( ACT_MP_GESTURE_VC_HANDMOUTH );
REGISTER_SHARED_ACTIVITY( ACT_MP_GESTURE_VC_FINGERPOINT );
@@ -2004,6 +2010,11 @@ void ActivityList_RegisterSharedActivities( void )
REGISTER_SHARED_ACTIVITY( ACT_MP_STUN_MIDDLE );
REGISTER_SHARED_ACTIVITY( ACT_MP_STUN_END );
+ REGISTER_SHARED_ACTIVITY( ACT_MP_PASSTIME_THROW_BEGIN );
+ REGISTER_SHARED_ACTIVITY( ACT_MP_PASSTIME_THROW_MIDDLE );
+ REGISTER_SHARED_ACTIVITY( ACT_MP_PASSTIME_THROW_END );
+ REGISTER_SHARED_ACTIVITY( ACT_MP_PASSTIME_THROW_CANCEL );
+
REGISTER_SHARED_ACTIVITY ( ACT_VM_UNUSABLE );
REGISTER_SHARED_ACTIVITY ( ACT_VM_UNUSABLE_TO_USABLE );
REGISTER_SHARED_ACTIVITY ( ACT_VM_USABLE_TO_UNUSABLE );
@@ -2304,6 +2315,42 @@ void ActivityList_RegisterSharedActivities( void )
REGISTER_SHARED_ACTIVITY( ACT_BOT_PANIC_START );
REGISTER_SHARED_ACTIVITY( ACT_BOT_PANIC_END );
+ REGISTER_SHARED_ACTIVITY( ACT_ENGINEER_REVOLVER_DRAW );
+ REGISTER_SHARED_ACTIVITY( ACT_ENGINEER_REVOLVER_IDLE );
+ REGISTER_SHARED_ACTIVITY( ACT_ENGINEER_REVOLVER_PRIMARYATTACK );
+ REGISTER_SHARED_ACTIVITY( ACT_ENGINEER_REVOLVER_RELOAD );
+
+ REGISTER_SHARED_ACTIVITY( ACT_KART_IDLE );
+ REGISTER_SHARED_ACTIVITY( ACT_KART_ACTION_SHOOT );
+ REGISTER_SHARED_ACTIVITY( ACT_KART_ACTION_DASH );
+ REGISTER_SHARED_ACTIVITY( ACT_KART_JUMP_START );
+ REGISTER_SHARED_ACTIVITY( ACT_KART_JUMP_FLOAT );
+ REGISTER_SHARED_ACTIVITY( ACT_KART_JUMP_LAND );
+ REGISTER_SHARED_ACTIVITY( ACT_KART_IMPACT );
+ REGISTER_SHARED_ACTIVITY( ACT_KART_IMPACT_BIG );
+ REGISTER_SHARED_ACTIVITY( ACT_KART_GESTURE_POSITIVE );
+ REGISTER_SHARED_ACTIVITY( ACT_KART_GESTURE_NEGATIVE );
+
+ REGISTER_SHARED_ACTIVITY( ACT_GRAPPLE_DRAW );
+ REGISTER_SHARED_ACTIVITY( ACT_GRAPPLE_IDLE );
+ REGISTER_SHARED_ACTIVITY( ACT_GRAPPLE_FIRE_START );
+ REGISTER_SHARED_ACTIVITY( ACT_GRAPPLE_FIRE_IDLE );
+ REGISTER_SHARED_ACTIVITY( ACT_GRAPPLE_PULL_START );
+ REGISTER_SHARED_ACTIVITY( ACT_GRAPPLE_PULL_IDLE );
+ REGISTER_SHARED_ACTIVITY( ACT_GRAPPLE_PULL_END );
+
+ REGISTER_SHARED_ACTIVITY( ACT_PRIMARY_VM_INSPECT_START );
+ REGISTER_SHARED_ACTIVITY( ACT_PRIMARY_VM_INSPECT_IDLE );
+ REGISTER_SHARED_ACTIVITY( ACT_PRIMARY_VM_INSPECT_END );
+
+ REGISTER_SHARED_ACTIVITY( ACT_SECONDARY_VM_INSPECT_START );
+ REGISTER_SHARED_ACTIVITY( ACT_SECONDARY_VM_INSPECT_IDLE );
+ REGISTER_SHARED_ACTIVITY( ACT_SECONDARY_VM_INSPECT_END );
+
+ REGISTER_SHARED_ACTIVITY( ACT_MELEE_VM_INSPECT_START );
+ REGISTER_SHARED_ACTIVITY( ACT_MELEE_VM_INSPECT_IDLE );
+ REGISTER_SHARED_ACTIVITY( ACT_MELEE_VM_INSPECT_END );
+
AssertMsg( g_HighestActivity == LAST_SHARED_ACTIVITY - 1, "Not all activities from ai_activity.h registered in activitylist.cpp" );
}
diff --git a/mp/src/game/shared/ai_activity.h b/mp/src/game/shared/ai_activity.h
index 3d3207c9..0f5bba44 100644
--- a/mp/src/game/shared/ai_activity.h
+++ b/mp/src/game/shared/ai_activity.h
@@ -1631,6 +1631,11 @@ typedef enum
ACT_MP_ATTACK_SWIM_GRENADE_ITEM2,
ACT_MP_ATTACK_AIRWALK_GRENADE_ITEM2,
+ // Passtime
+ ACT_MP_STAND_PASSTIME,
+ ACT_MP_RUN_PASSTIME,
+ ACT_MP_CROUCHWALK_PASSTIME,
+
// Flinches
ACT_MP_GESTURE_FLINCH,
ACT_MP_GESTURE_FLINCH_PRIMARY,
@@ -1771,6 +1776,7 @@ typedef enum
ACT_MP_DOUBLEJUMP_CROUCH_ITEM1,
ACT_MP_DOUBLEJUMP_CROUCH_ITEM2,
ACT_MP_DOUBLEJUMP_CROUCH_LOSERSTATE,
+ ACT_MP_DOUBLEJUMP_CROUCH_PASSTIME,
ACT_MP_GESTURE_VC_HANDMOUTH,
ACT_MP_GESTURE_VC_FINGERPOINT,
@@ -1832,6 +1838,11 @@ typedef enum
ACT_MP_STUN_MIDDLE,
ACT_MP_STUN_END,
+ ACT_MP_PASSTIME_THROW_BEGIN,
+ ACT_MP_PASSTIME_THROW_MIDDLE,
+ ACT_MP_PASSTIME_THROW_END,
+ ACT_MP_PASSTIME_THROW_CANCEL,
+
ACT_VM_UNUSABLE,
ACT_VM_UNUSABLE_TO_USABLE,
ACT_VM_USABLE_TO_UNUSABLE,
@@ -2138,6 +2149,45 @@ typedef enum
ACT_BOT_PANIC_START,
ACT_BOT_PANIC_END,
+ ACT_ENGINEER_REVOLVER_DRAW,
+ ACT_ENGINEER_REVOLVER_IDLE,
+ ACT_ENGINEER_REVOLVER_PRIMARYATTACK,
+ ACT_ENGINEER_REVOLVER_RELOAD,
+
+ // Kart!
+ ACT_KART_IDLE,
+ ACT_KART_ACTION_SHOOT,
+ ACT_KART_ACTION_DASH,
+ ACT_KART_JUMP_START,
+ ACT_KART_JUMP_FLOAT,
+ ACT_KART_JUMP_LAND,
+ ACT_KART_IMPACT,
+ ACT_KART_IMPACT_BIG,
+ ACT_KART_GESTURE_POSITIVE,
+ ACT_KART_GESTURE_NEGATIVE,
+
+ // grappling hook
+ ACT_GRAPPLE_DRAW,
+ ACT_GRAPPLE_IDLE,
+ ACT_GRAPPLE_FIRE_START,
+ ACT_GRAPPLE_FIRE_IDLE,
+ ACT_GRAPPLE_PULL_START,
+ ACT_GRAPPLE_PULL_IDLE,
+ ACT_GRAPPLE_PULL_END,
+
+ // inspect
+ ACT_PRIMARY_VM_INSPECT_START,
+ ACT_PRIMARY_VM_INSPECT_IDLE,
+ ACT_PRIMARY_VM_INSPECT_END,
+
+ ACT_SECONDARY_VM_INSPECT_START,
+ ACT_SECONDARY_VM_INSPECT_IDLE,
+ ACT_SECONDARY_VM_INSPECT_END,
+
+ ACT_MELEE_VM_INSPECT_START,
+ ACT_MELEE_VM_INSPECT_IDLE,
+ ACT_MELEE_VM_INSPECT_END,
+
// this is the end of the global activities, private per-monster activities start here.
LAST_SHARED_ACTIVITY,
} Activity;
diff --git a/mp/src/game/shared/animation.cpp b/mp/src/game/shared/animation.cpp
index 0f6dd754..97561581 100644
--- a/mp/src/game/shared/animation.cpp
+++ b/mp/src/game/shared/animation.cpp
@@ -339,6 +339,77 @@ int CStudioHdr::CActivityToSequenceMapping::SelectWeightedSequence( CStudioHdr *
}
+int CStudioHdr::CActivityToSequenceMapping::SelectWeightedSequenceFromModifiers( CStudioHdr *pstudiohdr, int activity, CUtlSymbol *pActivityModifiers, int iModifierCount )
+{
+ if ( !pstudiohdr->SequencesAvailable() )
+ {
+ return ACTIVITY_NOT_AVAILABLE;
+ }
+
+ VerifySequenceIndex( pstudiohdr );
+
+ if ( pstudiohdr->GetNumSeq() == 1 )
+ {
+ return ( ::GetSequenceActivity( pstudiohdr, 0, NULL ) == activity ) ? 0 : ACTIVITY_NOT_AVAILABLE;
+ }
+
+ if (!ValidateAgainst(pstudiohdr))
+ {
+ AssertMsg1(false, "CStudioHdr %s has changed its vmodel pointer without reinitializing its activity mapping! Now performing emergency reinitialization.", pstudiohdr->pszName());
+ ExecuteOnce(DebuggerBreakIfDebugging());
+ Reinitialize(pstudiohdr);
+ }
+
+ // a null m_pSequenceTuples just means that this studio header has no activities.
+ if (!m_pSequenceTuples)
+ return ACTIVITY_NOT_AVAILABLE;
+
+ // get the data for the given activity
+ HashValueType dummy( activity, 0, 0, 0 );
+ UtlHashHandle_t handle = m_ActToSeqHash.Find(dummy);
+ if (!m_ActToSeqHash.IsValidHandle(handle))
+ {
+ return ACTIVITY_NOT_AVAILABLE;
+ }
+ const HashValueType * __restrict actData = &m_ActToSeqHash[handle];
+
+ // go through each sequence and give it a score
+ int top_score = -1;
+ CUtlVector<int> topScoring( actData->count, actData->count );
+ for ( int i = 0; i < actData->count; i++ )
+ {
+ SequenceTuple * __restrict sequenceInfo = m_pSequenceTuples + actData->startingIdx + i;
+ int score = 0;
+ // count matching activity modifiers
+ for ( int m = 0; m < iModifierCount; m++ )
+ {
+ int num_modifiers = sequenceInfo->iNumActivityModifiers;
+ for ( int k = 0; k < num_modifiers; k++ )
+ {
+ if ( sequenceInfo->pActivityModifiers[ k ] == pActivityModifiers[ m ] )
+ {
+ score++;
+ break;
+ }
+ }
+ }
+ if ( score > top_score )
+ {
+ topScoring.RemoveAll();
+ topScoring.AddToTail( sequenceInfo->seqnum );
+ top_score = score;
+ }
+ }
+
+ // randomly pick between the highest scoring sequences ( NOTE: this method of selecting a sequence ignores activity weights )
+ if ( IsInPrediction() )
+ {
+ return topScoring[ SharedRandomInt( "SelectWeightedSequence", 0, topScoring.Count() - 1 ) ];
+ }
+
+ return topScoring[ RandomInt( 0, topScoring.Count() - 1 ) ];
+}
+
#endif
@@ -446,9 +517,9 @@ int LookupSequence( CStudioHdr *pstudiohdr, const char *label )
void GetSequenceLinearMotion( CStudioHdr *pstudiohdr, int iSequence, const float poseParameter[], Vector *pVec )
{
- if (! pstudiohdr)
+ if ( !pstudiohdr)
{
- Msg( "Bad pstudiohdr in GetSequenceLinearMotion()!\n" );
+ ExecuteNTimes( 20, Msg( "Bad pstudiohdr in GetSequenceLinearMotion()!\n" ) );
return;
}
@@ -460,11 +531,7 @@ void GetSequenceLinearMotion( CStudioHdr *pstudiohdr, int iSequence, const float
// Don't spam on bogus model
if ( pstudiohdr->GetNumSeq() > 0 )
{
- static int msgCount = 0;
- while ( ++msgCount <= 10 )
- {
- Msg( "Bad sequence (%i out of %i max) in GetSequenceLinearMotion() for model '%s'!\n", iSequence, pstudiohdr->GetNumSeq(), pstudiohdr->pszName() );
- }
+ ExecuteNTimes( 20, Msg( "Bad sequence (%i out of %i max) in GetSequenceLinearMotion() for model '%s'!\n", iSequence, pstudiohdr->GetNumSeq(), pstudiohdr->pszName() ) );
}
pVec->Init();
return;
@@ -849,7 +916,7 @@ const char *GetBodygroupName( CStudioHdr *pstudiohdr, int iGroup )
int FindBodygroupByName( CStudioHdr *pstudiohdr, const char *name )
{
- if ( !pstudiohdr )
+ if ( !pstudiohdr || !pstudiohdr->IsValid() )
return -1;
int group;
diff --git a/mp/src/game/shared/base_playeranimstate.cpp b/mp/src/game/shared/base_playeranimstate.cpp
index d90655ac..768e4f17 100644
--- a/mp/src/game/shared/base_playeranimstate.cpp
+++ b/mp/src/game/shared/base_playeranimstate.cpp
@@ -269,7 +269,7 @@ void CBasePlayerAnimState::ComputeMainSequence()
int animDesired = SelectWeightedSequence( TranslateActivity(idealActivity) );
#if !defined( HL1_CLIENT_DLL ) && !defined ( HL1_DLL )
- if ( pPlayer->GetSequenceActivity( pPlayer->GetSequence() ) == pPlayer->GetSequenceActivity( animDesired ) )
+ if ( !ShouldResetMainSequence( pPlayer->GetSequence(), animDesired ) )
return;
#endif
@@ -289,8 +289,13 @@ void CBasePlayerAnimState::ComputeMainSequence()
#endif
}
+bool CBasePlayerAnimState::ShouldResetMainSequence( int iCurrentSequence, int iNewSequence )
+{
+ if ( !GetOuter() )
+ return false;
-
+ return GetOuter()->GetSequenceActivity( iCurrentSequence ) != GetOuter()->GetSequenceActivity( iNewSequence );
+}
void CBasePlayerAnimState::UpdateAimSequenceLayers(
diff --git a/mp/src/game/shared/base_playeranimstate.h b/mp/src/game/shared/base_playeranimstate.h
index 0b1f6b34..5c84755a 100644
--- a/mp/src/game/shared/base_playeranimstate.h
+++ b/mp/src/game/shared/base_playeranimstate.h
@@ -234,6 +234,7 @@ private:
void EstimateYaw();
+ virtual bool ShouldResetMainSequence( int iCurrentSequence, int iNewSequence );
void ComputeMainSequence();
void ComputeAimSequence();
diff --git a/mp/src/game/shared/basecombatcharacter_shared.cpp b/mp/src/game/shared/basecombatcharacter_shared.cpp
index c032cd54..32e823fa 100644
--- a/mp/src/game/shared/basecombatcharacter_shared.cpp
+++ b/mp/src/game/shared/basecombatcharacter_shared.cpp
@@ -90,8 +90,23 @@ bool CBaseCombatCharacter::Weapon_CanSwitchTo( CBaseCombatWeapon *pWeapon )
if ( m_hActiveWeapon )
{
- if ( !m_hActiveWeapon->CanHolster() )
+ if ( !m_hActiveWeapon->CanHolster() && !pWeapon->ForceWeaponSwitch() )
return false;
+
+ if ( IsPlayer() )
+ {
+ CBasePlayer *pPlayer = (CBasePlayer *)this;
+ // check if active weapon force the last weapon to switch
+ if ( m_hActiveWeapon->ForceWeaponSwitch() )
+ {
+ // last weapon wasn't allowed to switch, don't allow to switch to new weapon
+ CBaseCombatWeapon *pLastWeapon = pPlayer->GetLastWeapon();
+ if ( pLastWeapon && pWeapon != pLastWeapon && !pLastWeapon->CanHolster() && !pWeapon->ForceWeaponSwitch() )
+ {
+ return false;
+ }
+ }
+ }
}
return true;
diff --git a/mp/src/game/shared/basecombatweapon_shared.cpp b/mp/src/game/shared/basecombatweapon_shared.cpp
index 4ab20c12..616dcf47 100644
--- a/mp/src/game/shared/basecombatweapon_shared.cpp
+++ b/mp/src/game/shared/basecombatweapon_shared.cpp
@@ -1149,7 +1149,7 @@ float CBaseCombatWeapon::GetViewModelSequenceDuration()
return vm->SequenceDuration();
}
-bool CBaseCombatWeapon::IsViewModelSequenceFinished( void )
+bool CBaseCombatWeapon::IsViewModelSequenceFinished( void ) const
{
// These are not valid activities and always complete immediately
if ( GetActivity() == ACT_RESET || GetActivity() == ACT_INVALID )
@@ -1452,7 +1452,12 @@ selects and deploys each weapon as you pass it. (sjb)
bool CBaseCombatWeapon::Deploy( )
{
MDLCACHE_CRITICAL_SECTION();
- return DefaultDeploy( (char*)GetViewModel(), (char*)GetWorldModel(), GetDrawActivity(), (char*)GetAnimPrefix() );
+ bool bResult = DefaultDeploy( (char*)GetViewModel(), (char*)GetWorldModel(), GetDrawActivity(), (char*)GetAnimPrefix() );
+
+ // override pose parameters
+ PoseParameterOverride( false );
+
+ return bResult;
}
Activity CBaseCombatWeapon::GetDrawActivity( void )
@@ -1511,6 +1516,9 @@ bool CBaseCombatWeapon::Holster( CBaseCombatWeapon *pSwitchingTo )
RescindReloadHudHint();
}
+ // reset pose parameters
+ PoseParameterOverride( true );
+
return true;
}
@@ -1775,8 +1783,8 @@ void CBaseCombatWeapon::ItemPostFrame( void )
// -----------------------
// Reload pressed / Clip Empty
- // -----------------------
- if ( ( pOwner->m_nButtons & IN_RELOAD ) && UsesClipsForAmmo1() && !m_bInReload )
+ // Can only start the Reload Cycle after the firing cycle
+ if ( ( pOwner->m_nButtons & IN_RELOAD ) && m_flNextPrimaryAttack <= gpGlobals->curtime && UsesClipsForAmmo1() && !m_bInReload )
{
// reload when reload is pressed, or if no buttons are down and weapon is empty.
Reload();
@@ -2440,23 +2448,53 @@ bool CBaseCombatWeapon::IsLocked( CBaseEntity *pAsker )
//-----------------------------------------------------------------------------
Activity CBaseCombatWeapon::ActivityOverride( Activity baseAct, bool *pRequired )
{
- acttable_t *pTable = ActivityList();
- int actCount = ActivityListCount();
+ int actCount = 0;
+ acttable_t *pTable = ActivityList( actCount );
- for ( int i = 0; i < actCount; i++, pTable++ )
+ for ( int i = 0; i < actCount; i++ )
{
- if ( baseAct == pTable->baseAct )
+ const acttable_t& act = pTable[i];
+ if ( baseAct == act.baseAct )
{
if (pRequired)
{
- *pRequired = pTable->required;
+ *pRequired = act.required;
}
- return (Activity)pTable->weaponAct;
+ return (Activity)act.weaponAct;
}
}
return baseAct;
}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CBaseCombatWeapon::PoseParameterOverride( bool bReset )
+{
+ CBaseCombatCharacter *pOwner = GetOwner();
+ if ( !pOwner )
+ return;
+
+ CStudioHdr *pStudioHdr = pOwner->GetModelPtr();
+ if ( !pStudioHdr )
+ return;
+
+ int iCount = 0;
+ poseparamtable_t *pPoseParamList = PoseParamList( iCount );
+ if ( pPoseParamList )
+ {
+ for ( int i=0; i<iCount; ++i )
+ {
+ int iPoseParam = pOwner->LookupPoseParameter( pStudioHdr, pPoseParamList[i].pszName );
+
+ if ( iPoseParam != -1 )
+ pOwner->SetPoseParameter( iPoseParam, bReset ? 0 : pPoseParamList[i].flValue );
+ }
+ }
+}
+
+
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
@@ -2745,6 +2783,13 @@ void* SendProxy_SendNonLocalWeaponDataTable( const SendProp *pProp, const void *
}
REGISTER_SEND_PROXY_NON_MODIFIED_POINTER( SendProxy_SendNonLocalWeaponDataTable );
+#else
+void CBaseCombatWeapon::RecvProxy_WeaponState( const CRecvProxyData *pData, void *pStruct, void *pOut )
+{
+ CBaseCombatWeapon *pWeapon = (CBaseCombatWeapon*)pStruct;
+ pWeapon->m_iState = pData->m_Value.m_Int;
+ pWeapon->UpdateVisibility();
+}
#endif
#if PREDICTION_ERROR_CHECK_LEVEL > 1
@@ -2818,7 +2863,7 @@ BEGIN_NETWORK_TABLE(CBaseCombatWeapon, DT_BaseCombatWeapon)
RecvPropDataTable("LocalActiveWeaponData", 0, 0, &REFERENCE_RECV_TABLE(DT_LocalActiveWeaponData)),
RecvPropInt( RECVINFO(m_iViewModelIndex)),
RecvPropInt( RECVINFO(m_iWorldModelIndex)),
- RecvPropInt( RECVINFO(m_iState )),
+ RecvPropInt( RECVINFO(m_iState), 0, &CBaseCombatWeapon::RecvProxy_WeaponState ),
RecvPropEHandle( RECVINFO(m_hOwner ) ),
#endif
END_NETWORK_TABLE()
diff --git a/mp/src/game/shared/basecombatweapon_shared.h b/mp/src/game/shared/basecombatweapon_shared.h
index 2c712923..d4964d83 100644
--- a/mp/src/game/shared/basecombatweapon_shared.h
+++ b/mp/src/game/shared/basecombatweapon_shared.h
@@ -55,8 +55,7 @@ class CUserCmd;
// Put this in your derived class definition to declare it's activity table
// UNDONE: Cascade these?
#define DECLARE_ACTTABLE() static acttable_t m_acttable[];\
- acttable_t *ActivityList( void );\
- int ActivityListCount( void );
+ virtual acttable_t *ActivityList( int &iActivityCount ) OVERRIDE;
// You also need to include the activity table itself in your class' implementation:
// e.g.
@@ -73,8 +72,7 @@ class CUserCmd;
// activity table.
// UNDONE: Cascade these?
#define IMPLEMENT_ACTTABLE(className) \
- acttable_t *className::ActivityList( void ) { return m_acttable; } \
- int className::ActivityListCount( void ) { return ARRAYSIZE(m_acttable); } \
+ acttable_t *className::ActivityList( int &iActivityCount ) { iActivityCount = ARRAYSIZE(m_acttable); return m_acttable; }
typedef struct
{
@@ -83,6 +81,29 @@ typedef struct
bool required;
} acttable_t;
+
+struct poseparamtable_t
+{
+ const char *pszName;
+ float flValue;
+};
+
+// Put this in your derived class definition to declare it's poseparam table
+#define DECLARE_POSEPARAMTABLE() static poseparamtable_t m_poseparamtable[];\
+ virtual poseparamtable_t* PoseParamList( int &iPoseParamCount ) { return NULL; }
+
+// You also need to include the activity table itself in your class' implementation:
+// e.g.
+// acttable_t CTFGrapplingHook::m_poseparamtable[] =
+// {
+// { "r_arm", 2 },
+// };
+//
+// The grapplinghook overrides the r_arm pose param, value to 2.
+
+#define IMPLEMENT_POSEPARAMTABLE(className)\
+ poseparamtable_t* className::PoseParamList( int &iPoseParamCount ) { iPoseParamCount = ARRAYSIZE(m_poseparamtable); return m_poseparamtable; }
+
class CHudTexture;
class Color;
@@ -208,7 +229,7 @@ public:
virtual bool SendWeaponAnim( int iActivity );
virtual void SendViewModelAnim( int nSequence );
float GetViewModelSequenceDuration(); // Return how long the current view model sequence is.
- bool IsViewModelSequenceFinished( void ); // Returns if the viewmodel's current animation is finished
+ bool IsViewModelSequenceFinished( void ) const; // Returns if the viewmodel's current animation is finished
virtual void SetViewModel();
@@ -224,7 +245,7 @@ public:
bool UsesSecondaryAmmo( void ); // returns true if the weapon actually uses secondary ammo
void GiveDefaultAmmo( void );
- virtual bool CanHolster( void ) { return TRUE; }; // returns true if the weapon can be holstered
+ virtual bool CanHolster( void ) const { return TRUE; }; // returns true if the weapon can be holstered
virtual bool DefaultDeploy( char *szViewModel, char *szWeaponModel, int iActivity, char *szAnimExt );
virtual bool CanDeploy( void ) { return true; } // return true if the weapon's allowed to deploy
virtual bool Deploy( void ); // returns true is deploy was successful
@@ -266,8 +287,7 @@ public:
bool DefaultReload( int iClipSize1, int iClipSize2, int iActivity );
bool ReloadsSingly( void ) const;
- virtual bool AutoFiresFullClip( void ) { return false; }
- virtual bool CanOverload( void ) { return false; }
+ virtual bool AutoFiresFullClip( void ) const { return false; }
virtual void UpdateAutoFire( void );
// Weapon firing
@@ -308,7 +328,7 @@ public:
virtual void SetActivity( Activity act, float duration );
inline void SetActivity( Activity eActivity ) { m_Activity = eActivity; }
- inline Activity GetActivity( void ) { return m_Activity; }
+ inline Activity GetActivity( void ) const { return m_Activity; }
virtual void AddViewKick( void ); // Add in the view kick for the weapon
@@ -349,6 +369,7 @@ public:
virtual int GetWeight( void ) const;
virtual bool AllowsAutoSwitchTo( void ) const;
virtual bool AllowsAutoSwitchFrom( void ) const;
+ virtual bool ForceWeaponSwitch( void ) const { return false; }
virtual int GetWeaponFlags( void ) const;
virtual int GetSlot( void ) const;
virtual int GetPosition( void ) const;
@@ -387,8 +408,10 @@ public:
virtual CHudTexture const *GetSpriteZoomedAutoaim( void ) const;
virtual Activity ActivityOverride( Activity baseAct, bool *pRequired );
- virtual acttable_t* ActivityList( void ) { return NULL; }
- virtual int ActivityListCount( void ) { return 0; }
+ virtual acttable_t* ActivityList( int &iActivityCount ) { return NULL; }
+
+ virtual void PoseParameterOverride( bool bReset );
+ virtual poseparamtable_t* PoseParamList( int &iPoseParamCount ) { return NULL; }
virtual void Activate( void );
@@ -577,6 +600,9 @@ public:
IMPLEMENT_NETWORK_VAR_FOR_DERIVED( m_nNextThinkTick );
+#ifdef CLIENT_DLL
+ static void RecvProxy_WeaponState( const CRecvProxyData *pData, void *pStruct, void *pOut );
+#endif
int WeaponState() const { return m_iState; }
// Weapon data
diff --git a/mp/src/game/shared/baseentity_shared.cpp b/mp/src/game/shared/baseentity_shared.cpp
index a843543f..376cd34e 100644
--- a/mp/src/game/shared/baseentity_shared.cpp
+++ b/mp/src/game/shared/baseentity_shared.cpp
@@ -636,10 +636,17 @@ void CBaseEntity::SetPredictionRandomSeed( const CUserCmd *cmd )
if ( !cmd )
{
m_nPredictionRandomSeed = -1;
+#ifdef GAME_DLL
+ m_nPredictionRandomSeedServer = -1;
+#endif
+
return;
}
m_nPredictionRandomSeed = ( cmd->random_seed );
+#ifdef GAME_DLL
+ m_nPredictionRandomSeedServer = ( cmd->server_random_seed );
+#endif
}
@@ -1679,7 +1686,7 @@ void CBaseEntity::FireBullets( const FireBulletsInfo_t &info )
int iSeed = 0;
if ( IsPlayer() )
{
- iSeed = CBaseEntity::GetPredictionRandomSeed() & 255;
+ iSeed = CBaseEntity::GetPredictionRandomSeed( info.m_bUseServerRandomSeed ) & 255;
}
#if defined( HL2MP ) && defined( GAME_DLL )
diff --git a/mp/src/game/shared/baseentity_shared.h b/mp/src/game/shared/baseentity_shared.h
index b5c95ba6..52a90ab4 100644
--- a/mp/src/game/shared/baseentity_shared.h
+++ b/mp/src/game/shared/baseentity_shared.h
@@ -119,9 +119,13 @@ inline CBaseEntity *CBaseEntity::GetEffectEntity() const
return m_hEffectEntity.Get();
}
-inline int CBaseEntity::GetPredictionRandomSeed( void )
+inline int CBaseEntity::GetPredictionRandomSeed( bool bUseUnSyncedServerPlatTime )
{
+#ifdef GAME_DLL
+ return bUseUnSyncedServerPlatTime ? m_nPredictionRandomSeedServer : m_nPredictionRandomSeed;
+#else
return m_nPredictionRandomSeed;
+#endif
}
inline CBasePlayer *CBaseEntity::GetPredictionPlayer( void )
diff --git a/mp/src/game/shared/baseplayer_shared.cpp b/mp/src/game/shared/baseplayer_shared.cpp
index cba09eb7..70056463 100644
--- a/mp/src/game/shared/baseplayer_shared.cpp
+++ b/mp/src/game/shared/baseplayer_shared.cpp
@@ -342,7 +342,7 @@ Vector CBasePlayer::EyePosition( )
#ifdef CLIENT_DLL
if ( IsObserver() )
{
- if ( GetObserverMode() == OBS_MODE_CHASE )
+ if ( GetObserverMode() == OBS_MODE_CHASE || GetObserverMode() == OBS_MODE_POI )
{
if ( IsLocalPlayer() )
{
@@ -1035,7 +1035,7 @@ void CBasePlayer::SelectItem( const char *pstr, int iSubType )
// Make sure the current weapon can be holstered
if ( GetActiveWeapon() )
{
- if ( !GetActiveWeapon()->CanHolster() )
+ if ( !GetActiveWeapon()->CanHolster() && !pItem->ForceWeaponSwitch() )
return;
ResetAutoaim( );
@@ -1703,6 +1703,7 @@ void CBasePlayer::CalcObserverView( Vector& eyeOrigin, QAngle& eyeAngles, float&
case OBS_MODE_IN_EYE : CalcInEyeCamView( eyeOrigin, eyeAngles, fov );
break;
+ case OBS_MODE_POI : // PASSTIME
case OBS_MODE_CHASE : CalcChaseCamView( eyeOrigin, eyeAngles, fov );
break;
diff --git a/mp/src/game/shared/baseprojectile.cpp b/mp/src/game/shared/baseprojectile.cpp
index 54a0e9bc..f2ff3fdd 100644
--- a/mp/src/game/shared/baseprojectile.cpp
+++ b/mp/src/game/shared/baseprojectile.cpp
@@ -20,6 +20,11 @@ BEGIN_NETWORK_TABLE( CBaseProjectile, DT_BaseProjectile )
END_NETWORK_TABLE()
+#ifndef CLIENT_DLL
+IMPLEMENT_AUTO_LIST( IBaseProjectileAutoList );
+#endif // !CLIENT_DLL
+
+
//-----------------------------------------------------------------------------
// Purpose: Constructor.
//-----------------------------------------------------------------------------
diff --git a/mp/src/game/shared/baseprojectile.h b/mp/src/game/shared/baseprojectile.h
index d87b9fdd..9f16f828 100644
--- a/mp/src/game/shared/baseprojectile.h
+++ b/mp/src/game/shared/baseprojectile.h
@@ -28,7 +28,12 @@
// Base Projectile.
//
//=============================================================================
+#ifdef CLIENT_DLL
class CBaseProjectile : public CBaseAnimating
+#else // CLIENT_DLL
+DECLARE_AUTO_LIST( IBaseProjectileAutoList );
+class CBaseProjectile : public CBaseAnimating, public IBaseProjectileAutoList
+#endif // !CLIENT_DLL
{
public:
DECLARE_CLASS( CBaseProjectile, CBaseAnimating );
@@ -39,10 +44,12 @@ public:
virtual void Spawn();
#ifdef GAME_DLL
+ virtual int GetBaseProjectileType() const { return -1; } // no base
+ virtual int GetProjectileType() const { return -1; } // no type
virtual int GetDestroyableHitCount( void ) const { return m_iDestroyableHitCount; }
void IncrementDestroyableHitCount( void ) { ++m_iDestroyableHitCount; }
- bool CanCollideWithTeammates() const { return m_bCanCollideWithTeammates; }
+ virtual bool CanCollideWithTeammates() const { return m_bCanCollideWithTeammates; }
virtual float GetCollideWithTeammatesDelay() const { return 0.25f; }
#endif // GAME_DLL
diff --git a/mp/src/game/shared/cam_thirdperson.cpp b/mp/src/game/shared/cam_thirdperson.cpp
index 81db62d4..02d7753b 100644
--- a/mp/src/game/shared/cam_thirdperson.cpp
+++ b/mp/src/game/shared/cam_thirdperson.cpp
@@ -21,10 +21,6 @@ static Vector CAM_HULL_MAX( CAM_HULL_OFFSET, CAM_HULL_OFFSET, CAM_HULL_OFFSET);
extern const ConVar *sv_cheats;
-extern ConVar cam_idealdist;
-extern ConVar cam_idealdistright;
-extern ConVar cam_idealdistup;
-
void CAM_ToThirdPerson(void);
void CAM_ToFirstPerson(void);
@@ -103,16 +99,6 @@ void CThirdPersonManager::Update( void )
}
-Vector CThirdPersonManager::GetDesiredCameraOffset( void )
-{
- if ( IsOverridingThirdPerson() == true )
- {
- return Vector( cam_idealdist.GetFloat(), cam_idealdistright.GetFloat(), cam_idealdistup.GetFloat() );
- }
-
- return m_vecDesiredCameraOffset;
-}
-
Vector CThirdPersonManager::GetFinalCameraOffset( void )
{
Vector vDesired = GetDesiredCameraOffset();
@@ -157,7 +143,7 @@ Vector CThirdPersonManager::GetDistanceFraction( void )
return Vector( flFraction, flFraction, flUpFraction );
}
-void CThirdPersonManager::PositionCamera( CBasePlayer *pPlayer, QAngle angles )
+void CThirdPersonManager::PositionCamera( CBasePlayer *pPlayer, const QAngle& angles )
{
if ( pPlayer )
{
diff --git a/mp/src/game/shared/cam_thirdperson.h b/mp/src/game/shared/cam_thirdperson.h
index 8271a642..54dfecaa 100644
--- a/mp/src/game/shared/cam_thirdperson.h
+++ b/mp/src/game/shared/cam_thirdperson.h
@@ -42,25 +42,25 @@ class CThirdPersonManager
public:
CThirdPersonManager();
- void SetCameraOffsetAngles( Vector vecOffset ) { m_vecCameraOffset = vecOffset; }
- Vector GetCameraOffsetAngles( void ) { return m_vecCameraOffset; }
+ void SetCameraOffsetAngles( const Vector& vecOffset ) { m_vecCameraOffset = vecOffset; }
+ const Vector& GetCameraOffsetAngles( void ) const { return m_vecCameraOffset; }
- void SetDesiredCameraOffset( Vector vecOffset ) { m_vecDesiredCameraOffset = vecOffset; }
- Vector GetDesiredCameraOffset( void );
+ void SetDesiredCameraOffset( const Vector& vecOffset ) { m_vecDesiredCameraOffset = vecOffset; }
+ const Vector& GetDesiredCameraOffset( void ) const { return m_vecDesiredCameraOffset; }
Vector GetFinalCameraOffset( void );
- void SetCameraOrigin( Vector vecOffset ) { m_vecCameraOrigin = vecOffset; }
- Vector GetCameraOrigin( void ) { return m_vecCameraOrigin; }
+ void SetCameraOrigin( const Vector& vecOffset ) { m_vecCameraOrigin = vecOffset; }
+ const Vector& GetCameraOrigin( void ) const { return m_vecCameraOrigin; }
void Update( void );
- void PositionCamera( CBasePlayer *pPlayer, QAngle angles );
+ void PositionCamera( CBasePlayer *pPlayer, const QAngle& angles );
void UseCameraOffsets( bool bUse ) { m_bUseCameraOffsets = bUse; }
bool UsingCameraOffsets( void ) { return m_bUseCameraOffsets; }
- QAngle GetCameraViewAngles( void ) { return m_ViewAngles; }
+ const QAngle& GetCameraViewAngles( void ) const { return m_ViewAngles; }
Vector GetDistanceFraction( void );
diff --git a/mp/src/game/shared/effect_dispatch_data.cpp b/mp/src/game/shared/effect_dispatch_data.cpp
index e295991f..8128468e 100644
--- a/mp/src/game/shared/effect_dispatch_data.cpp
+++ b/mp/src/game/shared/effect_dispatch_data.cpp
@@ -116,7 +116,7 @@
SendPropInt( SENDINFO_NOCHECK( m_nMaterial ), MAX_MODEL_INDEX_BITS, SPROP_UNSIGNED ),
SendPropInt( SENDINFO_NOCHECK( m_nDamageType ), 32, SPROP_UNSIGNED ),
- SendPropInt( SENDINFO_NOCHECK( m_nHitBox ), 11, SPROP_UNSIGNED ),
+ SendPropInt( SENDINFO_NOCHECK( m_nHitBox ), 12, SPROP_UNSIGNED ),
SendPropInt( SENDINFO_NAME( m_nEntIndex, entindex ), MAX_EDICT_BITS, SPROP_UNSIGNED ),
diff --git a/mp/src/game/shared/eventlist.cpp b/mp/src/game/shared/eventlist.cpp
index 84014b49..f52f8021 100644
--- a/mp/src/game/shared/eventlist.cpp
+++ b/mp/src/game/shared/eventlist.cpp
@@ -249,4 +249,7 @@ void EventList_RegisterSharedEvents( void )
REGISTER_SHARED_ANIMEVENT( AE_WPN_PLAYWPNSOUND, AE_TYPE_CLIENT | AE_TYPE_SERVER );
REGISTER_SHARED_ANIMEVENT( AE_RD_ROBOT_POP_PANELS_OFF, AE_TYPE_CLIENT | AE_TYPE_SERVER );
+
+ REGISTER_SHARED_ANIMEVENT( AE_TAUNT_ENABLE_MOVE, AE_TYPE_CLIENT | AE_TYPE_SERVER );
+ REGISTER_SHARED_ANIMEVENT( AE_TAUNT_DISABLE_MOVE, AE_TYPE_CLIENT | AE_TYPE_SERVER );
} \ No newline at end of file
diff --git a/mp/src/game/shared/eventlist.h b/mp/src/game/shared/eventlist.h
index c4944616..69c6f0ca 100644
--- a/mp/src/game/shared/eventlist.h
+++ b/mp/src/game/shared/eventlist.h
@@ -87,6 +87,9 @@ typedef enum
AE_RD_ROBOT_POP_PANELS_OFF,
+ AE_TAUNT_ENABLE_MOVE,
+ AE_TAUNT_DISABLE_MOVE,
+
LAST_SHARED_ANIMEVENT,
} Animevent;
diff --git a/mp/src/game/shared/expressionsample.h b/mp/src/game/shared/expressionsample.h
index 663328dc..006db6d0 100644
--- a/mp/src/game/shared/expressionsample.h
+++ b/mp/src/game/shared/expressionsample.h
@@ -69,6 +69,7 @@ private:
class ICurveDataAccessor
{
public:
+ virtual ~ICurveDataAccessor(){}
virtual float GetDuration() = 0;
virtual bool CurveHasEndTime() = 0; // only matters for events
virtual int GetDefaultCurveType() = 0;
diff --git a/mp/src/game/shared/gamemovement.cpp b/mp/src/game/shared/gamemovement.cpp
index 8b5921bd..76e4f22f 100644
--- a/mp/src/game/shared/gamemovement.cpp
+++ b/mp/src/game/shared/gamemovement.cpp
@@ -2147,7 +2147,7 @@ void CGameMovement::FullObserverMove( void )
{
int mode = player->GetObserverMode();
- if ( mode == OBS_MODE_IN_EYE || mode == OBS_MODE_CHASE )
+ if ( mode == OBS_MODE_IN_EYE || mode == OBS_MODE_CHASE || mode == OBS_MODE_POI )
{
CBaseEntity * target = player->GetObserverTarget();
diff --git a/mp/src/game/shared/gamerules.h b/mp/src/game/shared/gamerules.h
index 347f7941..5ba66820 100644
--- a/mp/src/game/shared/gamerules.h
+++ b/mp/src/game/shared/gamerules.h
@@ -418,6 +418,8 @@ public:
virtual bool IsHolidayActive( /*EHoliday*/ int eHoliday ) const { return false; }
+ virtual bool IsManualMapChangeOkay( const char **pszReason ){ return true; }
+
#ifndef CLIENT_DLL
private:
float m_flNextVerboseLogOutput;
diff --git a/mp/src/game/shared/mp_shareddefs.cpp b/mp/src/game/shared/mp_shareddefs.cpp
index 66a5e0e3..a4204357 100644
--- a/mp/src/game/shared/mp_shareddefs.cpp
+++ b/mp/src/game/shared/mp_shareddefs.cpp
@@ -158,6 +158,7 @@ const char *g_pszMPConcepts[] =
"TLK_PLAYER_CAST_MONOCULOUS", // MP_CONCEPT_PLAYER_CAST_MONOCULOUS
"TLK_PLAYER_CAST_METEOR_SWARM", // MP_CONCEPT_PLAYER_CAST_METEOR_SWARM
"TLK_PLAYER_CAST_SKELETON_HORDE", // MP_CONCEPT_PLAYER_CAST_SKELETON_HORDE
+ "TLK_PLAYER_CAST_BOMB_HEAD_CURSE", // MP_CONCEPT_PLAYER_CAST_BOMB_HEAD_CURSE
"TLK_PLAYER_SPELL_FIREBALL", // MP_CONCEPT_PLAYER_SPELL_FIREBALL
"TLK_PLAYER_SPELL_MERASMUS_ZAP", // MP_CONCEPT_PLAYER_SPELL_MERASMUS_ZAP
@@ -171,6 +172,7 @@ const char *g_pszMPConcepts[] =
"TLK_PLAYER_SPELL_MONOCULOUS", // MP_CONCEPT_PLAYER_SPELL_MONOCULOUS
"TLK_PLAYER_SPELL_METEOR_SWARM", // MP_CONCEPT_PLAYER_SPELL_METEOR_SWARM
"TLK_PLAYER_SPELL_SKELETON_HORDE", // MP_CONCEPT_PLAYER_SPELL_SKELETON_HORDE
+ "TLK_PLAYER_SPELL_BOMB_HEAD_CURSE", // MP_CONCEPT_PLAYER_SPELL_BOMB_HEAD_CURSE
// Events.
"TLK_PLAYER_SPELL_PICKUP_COMMON", // MP_CONCEPT_PLAYER_SPELL_PICKUP_COMMON
@@ -189,6 +191,8 @@ const char *g_pszMPConcepts[] =
"TLK_TAUNT_EUREKA_EFFECT", // MP_CONCEPT_TAUNT_EUREKA_EFFECT_TELEPORT
"TLK_COMBO_KILLED", // MP_CONCEPT_COMBO_KILLED
+
+ "TLK_PLAYER_ASK_FOR_BALL", // MP_CONCEPT_PLAYER_ASK_FOR_BALL
};
COMPILE_TIME_ASSERT( ARRAYSIZE( g_pszMPConcepts ) == MP_TF_CONCEPT_COUNT );
diff --git a/mp/src/game/shared/mp_shareddefs.h b/mp/src/game/shared/mp_shareddefs.h
index d0fa99c8..c65cbac2 100644
--- a/mp/src/game/shared/mp_shareddefs.h
+++ b/mp/src/game/shared/mp_shareddefs.h
@@ -167,6 +167,7 @@ enum
MP_CONCEPT_PLAYER_CAST_MONOCULOUS, // "TLK_PLAYER_CAST_MONOCULOUS"
MP_CONCEPT_PLAYER_CAST_METEOR_SWARM, // "TLK_PLAYER_CAST_METEOR_SWARM"
MP_CONCEPT_PLAYER_CAST_SKELETON_HORDE, // "TLK_PLAYER_CAST_SKELETON_HORDE"
+ MP_CONCEPT_PLAYER_CAST_BOMB_HEAD_CURSE, // "TLK_PLAYER_CAST_BOMB_HEAD_CURSE"
MP_CONCEPT_PLAYER_SPELL_FIREBALL, // "TLK_PLAYER_SPELL_FIREBALL"
MP_CONCEPT_PLAYER_SPELL_MERASMUS_ZAP, // "TLK_PLAYER_SPELL_MERASMUS_ZAP"
@@ -180,6 +181,7 @@ enum
MP_CONCEPT_PLAYER_SPELL_MONOCULOUS, // "TLK_PLAYER_SPELL_MONOCULOUS"
MP_CONCEPT_PLAYER_SPELL_METEOR_SWARM, // "TLK_PLAYER_SPELL_METEOR_SWARM"
MP_CONCEPT_PLAYER_SPELL_SKELETON_HORDE, // "TLK_PLAYER_SPELL_SKELETON_HORDE"
+ MP_CONCEPT_PLAYER_SPELL_BOMB_HEAD_CURSE, // "TLK_PLAYER_SPELL_BOMB_HEAD_CURSE"
// Events.
MP_CONCEPT_PLAYER_SPELL_PICKUP_COMMON, // "TLK_PLAYER_SPELL_PICKUP_COMMON"
@@ -198,6 +200,7 @@ enum
MP_CONCEPT_TAUNT_EUREKA_EFFECT_TELEPORT,// "TLK_TAUNT_EUREKA_EFFECT"
MP_CONCEPT_COMBO_KILLED, // "TLK_COMBO_KILLED"
+ MP_CONCEPT_PLAYER_ASK_FOR_BALL, // "TLK_PLAYER_ASK_FOR_BALL"
MP_TF_CONCEPT_COUNT
diff --git a/mp/src/game/shared/multiplay_gamerules.cpp b/mp/src/game/shared/multiplay_gamerules.cpp
index 16cfe297..ae26bde6 100644
--- a/mp/src/game/shared/multiplay_gamerules.cpp
+++ b/mp/src/game/shared/multiplay_gamerules.cpp
@@ -85,7 +85,8 @@ ConVar mp_show_voice_icons( "mp_show_voice_icons", "1", FCVAR_REPLICATED, "Show
#ifdef GAME_DLL
-ConVar tv_delaymapchange( "tv_delaymapchange", "0", 0, "Delays map change until broadcast is complete" );
+ConVar tv_delaymapchange( "tv_delaymapchange", "0", FCVAR_NONE, "Delays map change until broadcast is complete" );
+ConVar tv_delaymapchange_protect( "tv_delaymapchange_protect", "1", FCVAR_NONE, "Protect against doing a manual map change if HLTV is broadcasting and has not caught up with a major game event such as round_end" );
ConVar mp_restartgame( "mp_restartgame", "0", FCVAR_GAMEDLL, "If non-zero, game will restart in the specified number of seconds" );
ConVar mp_restartgame_immediate( "mp_restartgame_immediate", "0", FCVAR_GAMEDLL, "If non-zero, game will restart immediately" );
@@ -278,7 +279,7 @@ CMultiplayRules::CMultiplayRules()
if ( cfgfile && cfgfile[0] )
{
- char szCommand[256];
+ char szCommand[MAX_PATH];
Log( "Executing dedicated server config file %s\n", cfgfile );
Q_snprintf( szCommand,sizeof(szCommand), "exec %s\n", cfgfile );
@@ -292,7 +293,7 @@ CMultiplayRules::CMultiplayRules()
if ( cfgfile && cfgfile[0] )
{
- char szCommand[256];
+ char szCommand[MAX_PATH];
Log( "Executing listen server config file %s\n", cfgfile );
Q_snprintf( szCommand,sizeof(szCommand), "exec %s\n", cfgfile );
@@ -1164,7 +1165,7 @@ ConVarRef suitcharger( "sk_suitcharger" );
void CMultiplayRules::GetNextLevelName( char *pszNextMap, int bufsize, bool bRandom /* = false */ )
{
- char mapcfile[256];
+ char mapcfile[MAX_PATH];
DetermineMapCycleFilename( mapcfile, sizeof(mapcfile), false );
// Check the time of the mapcycle file and re-populate the list of level names if the file has been modified
@@ -1182,10 +1183,7 @@ ConVarRef suitcharger( "sk_suitcharger" );
// If map cycle file has changed or this is the first time through ...
if ( m_nMapCycleTimeStamp != nMapCycleTimeStamp )
{
- // Reset map index and map cycle timestamp
- m_nMapCycleTimeStamp = nMapCycleTimeStamp;
- m_nMapCycleindex = 0;
-
+ // Reload
LoadMapCycleFile();
}
}
@@ -1209,7 +1207,7 @@ ConVarRef suitcharger( "sk_suitcharger" );
void CMultiplayRules::DetermineMapCycleFilename( char *pszResult, int nSizeResult, bool bForceSpew )
{
- static char szLastResult[ 256];
+ static char szLastResult[ MAX_PATH ];
const char *pszVar = mapcyclefile.GetString();
if ( *pszVar == '\0' )
@@ -1223,7 +1221,7 @@ ConVarRef suitcharger( "sk_suitcharger" );
return;
}
- char szRecommendedName[ 256 ];
+ char szRecommendedName[ MAX_PATH ];
V_sprintf_safe( szRecommendedName, "cfg/%s", pszVar );
// First, look for a mapcycle file in the cfg directory, which is preferred
@@ -1274,7 +1272,12 @@ ConVarRef suitcharger( "sk_suitcharger" );
}
}
- void CMultiplayRules::LoapMapCycleFileIntoVector( const char *pszMapCycleFile, CUtlVector<char *> &mapList )
+ void CMultiplayRules::LoadMapCycleFileIntoVector( const char *pszMapCycleFile, CUtlVector<char *> &mapList )
+ {
+ CMultiplayRules::RawLoadMapCycleFileIntoVector( pszMapCycleFile, mapList );
+ }
+
+ void CMultiplayRules::RawLoadMapCycleFileIntoVector( const char *pszMapCycleFile, CUtlVector<char *> &mapList )
{
CUtlBuffer buf;
if ( !filesystem->ReadFile( pszMapCycleFile, "GAME", buf ) )
@@ -1293,13 +1296,6 @@ ConVarRef suitcharger( "sk_suitcharger" );
{
bIgnore = true;
}
- else if ( !engine->IsMapValid( mapList[i] ) )
- {
- bIgnore = true;
-
- // If the engine doesn't consider it a valid map remove it from the lists
- Warning( "Invalid map '%s' included in map cycle file. Ignored.\n", mapList[i] );
- }
if ( bIgnore )
{
@@ -1321,6 +1317,27 @@ ConVarRef suitcharger( "sk_suitcharger" );
mapList.RemoveAll();
}
+ bool CMultiplayRules::IsManualMapChangeOkay( const char **pszReason )
+ {
+ if ( HLTVDirector()->IsActive() && ( HLTVDirector()->GetDelay() >= HLTV_MIN_DIRECTOR_DELAY ) )
+ {
+ if ( tv_delaymapchange.GetBool() && tv_delaymapchange_protect.GetBool() )
+ {
+ float flLastEvent = GetLastMajorEventTime();
+ if ( flLastEvent > -1 )
+ {
+ if ( flLastEvent > ( gpGlobals->curtime - ( HLTVDirector()->GetDelay() + 3 ) ) ) // +3 second delay to prevent instant change after a major event
+ {
+ *pszReason = "\n***WARNING*** Map change blocked. HLTV is broadcasting and has not caught up to the last major game event yet.\nYou can disable this check by setting the value of the server convar \"tv_delaymapchange_protect\" to 0.\n";
+ return false;
+ }
+ }
+ }
+ }
+
+ return true;
+ }
+
bool CMultiplayRules::IsMapInMapCycle( const char *pszName )
{
for ( int i = 0; i < m_MapList.Count(); i++ )
@@ -1338,7 +1355,7 @@ ConVarRef suitcharger( "sk_suitcharger" );
{
char szNextMap[MAX_MAP_NAME];
- if ( nextlevel.GetString() && *nextlevel.GetString() && engine->IsMapValid( nextlevel.GetString() ) )
+ if ( nextlevel.GetString() && *nextlevel.GetString() )
{
Q_strncpy( szNextMap, nextlevel.GetString(), sizeof( szNextMap ) );
}
@@ -1353,13 +1370,19 @@ ConVarRef suitcharger( "sk_suitcharger" );
void CMultiplayRules::LoadMapCycleFile( void )
{
- char mapcfile[256];
+ int nOldCycleIndex = m_nMapCycleindex;
+ m_nMapCycleindex = 0;
+
+ char mapcfile[MAX_PATH];
DetermineMapCycleFilename( mapcfile, sizeof(mapcfile), false );
FreeMapCycleFileVector( m_MapList );
+ const int nMapCycleTimeStamp = filesystem->GetPathTime( mapcfile, "GAME" );
+ m_nMapCycleTimeStamp = nMapCycleTimeStamp;
+
// Repopulate map list from mapcycle file
- LoapMapCycleFileIntoVector( mapcfile, m_MapList );
+ LoadMapCycleFileIntoVector( mapcfile, m_MapList );
// Load server's mapcycle into network string table for client-side voting
if ( g_pStringTableServerMapCycle )
@@ -1466,16 +1489,29 @@ ConVarRef suitcharger( "sk_suitcharger" );
}
#endif
- // If the current map selection is in the list, set m_nMapCycleindex to the map that follows it.
- for ( int i = 0; i < m_MapList.Count(); i++ )
+ // If the current map is in the same location in the new map cycle, keep that index. This gives better behavior
+ // when reloading a map cycle that has the current map in it multiple times.
+ int nOldPreviousMap = ( nOldCycleIndex == 0 ) ? ( m_MapList.Count() - 1 ) : ( nOldCycleIndex - 1 );
+ if ( nOldCycleIndex >= 0 && nOldCycleIndex < m_MapList.Count() &&
+ nOldPreviousMap >= 0 && nOldPreviousMap < m_MapList.Count() &&
+ V_strcmp( STRING( gpGlobals->mapname ), m_MapList[ nOldPreviousMap ] ) == 0 )
{
- if ( V_strcmp( STRING( gpGlobals->mapname ), m_MapList[i] ) == 0 )
+ // The old index is still valid, and falls after our current map in the new cycle, use it
+ m_nMapCycleindex = nOldCycleIndex;
+ }
+ else
+ {
+ // Otherwise, if the current map selection is in the list, set m_nMapCycleindex to the map that follows it.
+ for ( int i = 0; i < m_MapList.Count(); i++ )
{
- m_nMapCycleindex = i;
- IncrementMapCycleIndex();
- break;
+ if ( V_strcmp( STRING( gpGlobals->mapname ), m_MapList[i] ) == 0 )
+ {
+ m_nMapCycleindex = i;
+ IncrementMapCycleIndex();
+ break;
+ }
}
- }
+ }
}
void CMultiplayRules::ChangeLevelToMap( const char *pszMap )
@@ -1556,7 +1592,7 @@ ConVarRef suitcharger( "sk_suitcharger" );
Msg( "Skipping: %s\tNext map: %s\n", szSkippedMap, szNextMap );
- if ( nextlevel.GetString() && *nextlevel.GetString() && engine->IsMapValid( nextlevel.GetString() ) )
+ if ( nextlevel.GetString() && *nextlevel.GetString() )
{
Msg( "Warning! \"nextlevel\" is set to \"%s\" and will override the next map to be played.\n", nextlevel.GetString() );
}
@@ -1624,10 +1660,6 @@ ConVarRef suitcharger( "sk_suitcharger" );
pPlayer->OnAchievementEarned( nAchievementID );
}
}
- else if ( FStrEq( pszCommand, "SendServerMapCycle" ) )
- {
- LoadMapCycleFile();
- }
}
}
diff --git a/mp/src/game/shared/multiplay_gamerules.h b/mp/src/game/shared/multiplay_gamerules.h
index 08e06e4a..b74dd34f 100644
--- a/mp/src/game/shared/multiplay_gamerules.h
+++ b/mp/src/game/shared/multiplay_gamerules.h
@@ -239,20 +239,26 @@ public:
virtual void GetNextLevelName( char *szNextMap, int bufsize, bool bRandom = false );
static void DetermineMapCycleFilename( char *pszResult, int nSizeResult, bool bForceSpew );
- static void LoapMapCycleFileIntoVector ( const char *pszMapCycleFile, CUtlVector<char *> &mapList );
+ virtual void LoadMapCycleFileIntoVector ( const char *pszMapCycleFile, CUtlVector<char *> &mapList );
static void FreeMapCycleFileVector ( CUtlVector<char *> &mapList );
+ // LoadMapCycleFileIntoVector without the fixups inherited versions of gamerules may provide
+ static void RawLoadMapCycleFileIntoVector ( const char *pszMapCycleFile, CUtlVector<char *> &mapList );
+
bool IsMapInMapCycle( const char *pszName );
+ virtual bool IsManualMapChangeOkay( const char **pszReason ) OVERRIDE;
+
protected:
virtual bool UseSuicidePenalty() { return true; } // apply point penalty for suicide?
+ virtual float GetLastMajorEventTime( void ){ return -1.0f; }
public:
virtual void ChangeLevel( void );
protected:
virtual void GoToIntermission( void );
- void LoadMapCycleFile( void );
+ virtual void LoadMapCycleFile( void );
void ChangeLevelToMap( const char *pszMap );
float m_flIntermissionEndTime;
diff --git a/mp/src/game/shared/particle_parse.cpp b/mp/src/game/shared/particle_parse.cpp
index db15685d..28c559e2 100644
--- a/mp/src/game/shared/particle_parse.cpp
+++ b/mp/src/game/shared/particle_parse.cpp
@@ -567,4 +567,37 @@ void StopParticleEffects( CBaseEntity *pEntity )
}
static ConCommand particle_test_stop("particle_test_stop", CC_Particle_Test_Stop, "Stops all particle systems on the selected entities.\n\tArguments: {entity_name} / {class_name} / no argument picks what player is looking at ", FCVAR_CHEAT);
-#endif //CLIENT_DLL
+#endif //!CLIENT_DLL
+
+#if defined( CLIENT_DLL ) && defined( STAGING_ONLY )
+
+ void CC_DispatchParticle( const CCommand& args )
+ {
+ C_BasePlayer *pLocalPlayer = C_BasePlayer::GetLocalPlayer();
+ if ( !pLocalPlayer )
+ return;
+
+ if ( args.ArgC() < 2 )
+ {
+ DevMsg( "Use: dispatch_particle {particle_name} {surface_offset_distance}\n" );
+ return;
+ }
+
+ float flSurfaceOffsetDistance = 0.f;
+ if ( args.ArgC() == 3 )
+ {
+ flSurfaceOffsetDistance = atof( args[2] );
+ }
+
+ Vector vForward;
+ pLocalPlayer->GetVectors( &vForward, NULL, NULL );
+ trace_t tr;
+ UTIL_TraceLine( pLocalPlayer->EyePosition(), pLocalPlayer->EyePosition() + vForward * 3000, MASK_SOLID_BRUSHONLY, NULL, &tr );
+
+ Vector vTargetDeathPos = tr.endpos;
+ DispatchParticleEffect( args[1], vTargetDeathPos + flSurfaceOffsetDistance * tr.plane.normal, vec3_angle );
+ }
+
+ static ConCommand dispatch_particle( "dispatch_particle", CC_DispatchParticle, "Dispatch specified particle effect 50 units away from the lookat surface normal.\n\tArguments: {particle_name} {surface_offset_distance}", FCVAR_CHEAT );
+
+#endif // CLIENT_DLL && STAGING_ONLY
diff --git a/mp/src/game/shared/particle_property.cpp b/mp/src/game/shared/particle_property.cpp
index 5b5c2603..fe108721 100644
--- a/mp/src/game/shared/particle_property.cpp
+++ b/mp/src/game/shared/particle_property.cpp
@@ -618,7 +618,9 @@ void CParticleProperty::UpdateControlPoint( ParticleEffectList_t *pEffect, int i
if ( !pAnimating->C_BaseAnimating::GetAttachment( pPoint->iAttachmentPoint, attachmentToWorld ) )
{
Warning( "Cannot update control point %d for effect '%s'.\n", pPoint->iAttachmentPoint, pEffect->pParticleEffect->GetEffectName() );
- attachmentToWorld = pAnimating->RenderableToWorldTransform();
+ // Remove the effect cause this warning means something is orphaned
+ StopParticlesNamed( pEffect->pParticleEffect->GetEffectName() );
+ return;
}
}
@@ -627,7 +629,7 @@ void CParticleProperty::UpdateControlPoint( ParticleEffectList_t *pEffect, int i
MatrixVectors( vMat.As3x4(), &vecForward, &vecRight, &vecUp );
MatrixPosition( vMat.As3x4(), vecOrigin );
- if ( pEffect->pParticleEffect->m_pDef->IsViewModelEffect() )
+ if ( pEffect->pParticleEffect->GetIsViewModelEffect() )
{
FormatViewModelAttachment( vecOrigin, true );
}
diff --git a/mp/src/game/shared/ragdoll_shared.cpp b/mp/src/game/shared/ragdoll_shared.cpp
index e77e9a75..0fc50772 100644
--- a/mp/src/game/shared/ragdoll_shared.cpp
+++ b/mp/src/game/shared/ragdoll_shared.cpp
@@ -40,7 +40,7 @@ void CRagdollLowViolenceManager::SetLowViolence( const char *pMapName )
#if !defined( CLIENT_DLL )
// the server doesn't worry about low violence during multiplayer games
- if ( g_pGameRules->IsMultiplayer() )
+ if ( g_pGameRules && g_pGameRules->IsMultiplayer() )
{
m_bLowViolence = false;
}
@@ -742,8 +742,12 @@ bool ShouldRemoveThisRagdoll( CBaseAnimating *pRagdoll )
return false;
*/
+ // Bail if we have a null ragdoll pointer.
+ if ( !pRagdoll->m_pRagdoll )
+ return true;
+
Vector vMins, vMaxs;
-
+
Vector origin = pRagdoll->m_pRagdoll->GetRagdollOrigin();
pRagdoll->m_pRagdoll->GetRagdollBounds( vMins, vMaxs );
diff --git a/mp/src/game/shared/shareddefs.h b/mp/src/game/shared/shareddefs.h
index 11156a36..5236693f 100644
--- a/mp/src/game/shared/shareddefs.h
+++ b/mp/src/game/shared/shareddefs.h
@@ -151,6 +151,8 @@ typedef enum
VOTE_FAILED_MAP_NOT_VALID,
VOTE_FAILED_CANNOT_KICK_FOR_TIME,
VOTE_FAILED_CANNOT_KICK_DURING_ROUND,
+ VOTE_FAILED_VOTE_IN_PROGRESS,
+ VOTE_FAILED_KICK_LIMIT_REACHED,
// TF-specific?
VOTE_FAILED_MODIFICATION_ALREADY_ACTIVE,
@@ -455,6 +457,7 @@ enum {
OBS_MODE_FIXED, // view from a fixed camera position
OBS_MODE_IN_EYE, // follow a player in first person view
OBS_MODE_CHASE, // follow a player in third person view
+ OBS_MODE_POI, // PASSTIME point of interest - game objective, big fight, anything interesting; added in the middle of the enum due to tons of hard-coded "<ROAMING" enum compares
OBS_MODE_ROAMING, // free roaming
NUM_OBSERVER_MODES,
@@ -688,6 +691,7 @@ struct FireBulletsInfo_t
m_vecDirShooting.Init( VEC_T_NAN, VEC_T_NAN, VEC_T_NAN );
#endif
m_bPrimaryAttack = true;
+ m_bUseServerRandomSeed = false;
}
FireBulletsInfo_t( int nShots, const Vector &vecSrc, const Vector &vecDir, const Vector &vecSpread, float flDistance, int nAmmoType, bool bPrimaryAttack = true )
@@ -706,6 +710,7 @@ struct FireBulletsInfo_t
m_pAdditionalIgnoreEnt = NULL;
m_flDamageForceScale = 1.0f;
m_bPrimaryAttack = bPrimaryAttack;
+ m_bUseServerRandomSeed = false;
}
int m_iShots;
@@ -722,6 +727,7 @@ struct FireBulletsInfo_t
CBaseEntity *m_pAttacker;
CBaseEntity *m_pAdditionalIgnoreEnt;
bool m_bPrimaryAttack;
+ bool m_bUseServerRandomSeed;
};
//-----------------------------------------------------------------------------
diff --git a/mp/src/game/shared/takedamageinfo.cpp b/mp/src/game/shared/takedamageinfo.cpp
index e9062d80..f3eb84c3 100644
--- a/mp/src/game/shared/takedamageinfo.cpp
+++ b/mp/src/game/shared/takedamageinfo.cpp
@@ -61,6 +61,7 @@ void CTakeDamageInfo::Init( CBaseEntity *pInflictor, CBaseEntity *pAttacker, CBa
m_iPlayerPenetrationCount = 0;
m_flDamageBonus = 0.f;
m_bForceFriendlyFire = false;
+ m_flDamageForForce = 0.f;
}
CTakeDamageInfo::CTakeDamageInfo()
diff --git a/mp/src/game/shared/takedamageinfo.h b/mp/src/game/shared/takedamageinfo.h
index a18493e0..43dfdf49 100644
--- a/mp/src/game/shared/takedamageinfo.h
+++ b/mp/src/game/shared/takedamageinfo.h
@@ -64,6 +64,8 @@ public:
Vector GetDamageForce() const;
void SetDamageForce( const Vector &damageForce );
void ScaleDamageForce( float flScaleAmount );
+ float GetDamageForForceCalc() const;
+ void SetDamageForForceCalc( const float flScaleAmount );
Vector GetDamagePosition() const;
void SetDamagePosition( const Vector &damagePosition );
@@ -129,6 +131,8 @@ protected:
EHANDLE m_hDamageBonusProvider; // Who gave us the ability to do extra damage?
bool m_bForceFriendlyFire; // Ideally this would be a dmg type, but we can't add more
+ float m_flDamageForForce;
+
DECLARE_SIMPLE_DATADESC();
};
@@ -289,6 +293,16 @@ inline void CTakeDamageInfo::ScaleDamageForce( float flScaleAmount )
m_vecDamageForce *= flScaleAmount;
}
+inline float CTakeDamageInfo::GetDamageForForceCalc() const
+{
+ return m_flDamageForForce;
+}
+
+inline void CTakeDamageInfo::SetDamageForForceCalc( float flDamage )
+{
+ m_flDamageForForce = flDamage;
+}
+
inline Vector CTakeDamageInfo::GetDamagePosition() const
{
return m_vecDamagePosition;
diff --git a/mp/src/game/shared/teamplay_gamerules.h b/mp/src/game/shared/teamplay_gamerules.h
index 952895eb..6be6082c 100644
--- a/mp/src/game/shared/teamplay_gamerules.h
+++ b/mp/src/game/shared/teamplay_gamerules.h
@@ -87,7 +87,7 @@ public:
virtual bool TimerMayExpire( void ) { return true; }
// A game has been won by the specified team
- virtual void SetWinningTeam( int team, int iWinReason, bool bForceMapReset = true, bool bSwitchTeams = false, bool bDontAddScore = false ) { return; }
+ virtual void SetWinningTeam( int team, int iWinReason, bool bForceMapReset = true, bool bSwitchTeams = false, bool bDontAddScore = false, bool bFinal = false ) { return; }
virtual void SetStalemate( int iReason, bool bForceMapReset = true, bool bSwitchTeams = false ) { return; }
// Used to determine if all players should switch teams
diff --git a/mp/src/game/shared/teamplay_round_timer.cpp b/mp/src/game/shared/teamplay_round_timer.cpp
index 6c6ccb77..e0739e77 100644
--- a/mp/src/game/shared/teamplay_round_timer.cpp
+++ b/mp/src/game/shared/teamplay_round_timer.cpp
@@ -44,6 +44,14 @@
#define ROUND_SETUP_2SECS "Announcer.RoundBegins2Seconds"
#define ROUND_SETUP_1SECS "Announcer.RoundBegins1Seconds"
+#ifdef TF_CLIENT_DLL
+#define MERASMUS_SETUP_5SECS "Merasmus.RoundBegins5Seconds"
+#define MERASMUS_SETUP_4SECS "Merasmus.RoundBegins4Seconds"
+#define MERASMUS_SETUP_3SECS "Merasmus.RoundBegins3Seconds"
+#define MERASMUS_SETUP_2SECS "Merasmus.RoundBegins2Seconds"
+#define MERASMUS_SETUP_1SECS "Merasmus.RoundBegins1Seconds"
+#endif
+
#define ROUND_START_BELL "Ambient.Siren"
#define ROUND_TIMER_TIME_ADDED "Announcer.TimeAdded"
@@ -283,6 +291,14 @@ void CTeamRoundTimer::Precache( void )
PrecacheScriptSound( ROUND_TIMER_TIME_ADDED_LOSER );
PrecacheScriptSound( ROUND_TIMER_TIME_ADDED_WINNER );
PrecacheScriptSound( ROUND_START_BELL );
+
+#ifdef TF_CLIENT_DLL
+ PrecacheScriptSound( MERASMUS_SETUP_5SECS );
+ PrecacheScriptSound( MERASMUS_SETUP_4SECS );
+ PrecacheScriptSound( MERASMUS_SETUP_3SECS );
+ PrecacheScriptSound( MERASMUS_SETUP_2SECS );
+ PrecacheScriptSound( MERASMUS_SETUP_1SECS );
+#endif // TF_CLIENT_DLL
#endif // TF_DLL || TF_CLIENT_DLL
}
@@ -575,7 +591,16 @@ const char *CTeamRoundTimer::GetTimeWarningSound( int nWarning )
case RT_WARNING_5SECS:
if ( m_nState == RT_STATE_SETUP )
{
- pszRetVal = ROUND_SETUP_5SECS;
+#ifdef TF_CLIENT_DLL
+ if ( TFGameRules() && TFGameRules()->IsHalloweenScenario( CTFGameRules::HALLOWEEN_SCENARIO_DOOMSDAY ) )
+ {
+ pszRetVal = MERASMUS_SETUP_5SECS;
+ }
+ else
+#endif
+ {
+ pszRetVal = ROUND_SETUP_5SECS;
+ }
}
else
{
@@ -585,7 +610,16 @@ const char *CTeamRoundTimer::GetTimeWarningSound( int nWarning )
case RT_WARNING_4SECS:
if ( m_nState == RT_STATE_SETUP )
{
- pszRetVal = ROUND_SETUP_4SECS;
+#ifdef TF_CLIENT_DLL
+ if ( TFGameRules() && TFGameRules()->IsHalloweenScenario( CTFGameRules::HALLOWEEN_SCENARIO_DOOMSDAY ) )
+ {
+ pszRetVal = MERASMUS_SETUP_4SECS;
+ }
+ else
+#endif
+ {
+ pszRetVal = ROUND_SETUP_4SECS;
+ }
}
else
{
@@ -595,7 +629,16 @@ const char *CTeamRoundTimer::GetTimeWarningSound( int nWarning )
case RT_WARNING_3SECS:
if ( m_nState == RT_STATE_SETUP )
{
- pszRetVal = ROUND_SETUP_3SECS;
+#ifdef TF_CLIENT_DLL
+ if ( TFGameRules() && TFGameRules()->IsHalloweenScenario( CTFGameRules::HALLOWEEN_SCENARIO_DOOMSDAY ) )
+ {
+ pszRetVal = MERASMUS_SETUP_3SECS;
+ }
+ else
+#endif
+ {
+ pszRetVal = ROUND_SETUP_3SECS;
+ }
}
else
{
@@ -605,7 +648,16 @@ const char *CTeamRoundTimer::GetTimeWarningSound( int nWarning )
case RT_WARNING_2SECS:
if ( m_nState == RT_STATE_SETUP )
{
- pszRetVal = ROUND_SETUP_2SECS;
+#ifdef TF_CLIENT_DLL
+ if ( TFGameRules() && TFGameRules()->IsHalloweenScenario( CTFGameRules::HALLOWEEN_SCENARIO_DOOMSDAY ) )
+ {
+ pszRetVal = MERASMUS_SETUP_2SECS;
+ }
+ else
+#endif
+ {
+ pszRetVal = ROUND_SETUP_2SECS;
+ }
}
else
{
@@ -615,7 +667,16 @@ const char *CTeamRoundTimer::GetTimeWarningSound( int nWarning )
case RT_WARNING_1SECS:
if ( m_nState == RT_STATE_SETUP )
{
- pszRetVal = ROUND_SETUP_1SECS;
+#ifdef TF_CLIENT_DLL
+ if ( TFGameRules() && TFGameRules()->IsHalloweenScenario( CTFGameRules::HALLOWEEN_SCENARIO_DOOMSDAY ) )
+ {
+ pszRetVal = MERASMUS_SETUP_1SECS;
+ }
+ else
+#endif
+ {
+ pszRetVal = ROUND_SETUP_1SECS;
+ }
}
else
{
diff --git a/mp/src/game/shared/teamplay_round_timer.h b/mp/src/game/shared/teamplay_round_timer.h
index fd2e7613..df94a271 100644
--- a/mp/src/game/shared/teamplay_round_timer.h
+++ b/mp/src/game/shared/teamplay_round_timer.h
@@ -80,7 +80,7 @@ public:
bool IsStopWatchTimer( void ) { return m_bStopWatchTimer; }
float GetStopWatchTotalTime( void ) { return m_flTotalTime; }
bool IsRoundMaxTimerSet( void ) { return m_nTimerMaxLength > 0; }
-
+ int GetTimerInitialLength( void ) { return m_nTimerInitialLength; }
private:
void CalculateOutputMessages( void );
diff --git a/mp/src/game/shared/teamplayroundbased_gamerules.cpp b/mp/src/game/shared/teamplayroundbased_gamerules.cpp
index 3930798d..8d2b3e00 100644
--- a/mp/src/game/shared/teamplayroundbased_gamerules.cpp
+++ b/mp/src/game/shared/teamplayroundbased_gamerules.cpp
@@ -35,17 +35,15 @@
#if defined(TF_CLIENT_DLL) || defined(TF_DLL)
#include "tf_gamerules.h"
- #if defined(TF_CLIENT_DLL) || defined(TF_DLL)
- #include "tf_lobby.h"
- #ifdef GAME_DLL
- #include "player_vs_environment/tf_population_manager.h"
- #include "../server/tf/tf_gc_server.h"
- #include "../server/tf/tf_objective_resource.h"
- #else
- #include "../client/tf/tf_gc_client.h"
- #include "../client/tf/c_tf_objective_resource.h"
- #endif // GAME_DLL
- #endif // #if defined(TF_CLIENT_DLL) || defined(TF_DLL)
+ #include "tf_lobby.h"
+ #ifdef GAME_DLL
+ #include "player_vs_environment/tf_population_manager.h"
+ #include "../server/tf/tf_gc_server.h"
+ #include "../server/tf/tf_objective_resource.h"
+ #else
+ #include "../client/tf/tf_gc_client.h"
+ #include "../client/tf/c_tf_objective_resource.h"
+ #endif // GAME_DLL
#endif
// memdbgon must be the last include file in a .cpp file!!!
@@ -196,9 +194,14 @@ ConVar mp_maxrounds( "mp_maxrounds", "0", FCVAR_REPLICATED | FCVAR_NOTIFY, "max
ConVar mp_winlimit( "mp_winlimit", "0", FCVAR_REPLICATED | FCVAR_NOTIFY, "Max score one team can reach before server changes maps", true, 0, false, 0 );
ConVar mp_disable_respawn_times( "mp_disable_respawn_times", "0", FCVAR_NOTIFY | FCVAR_REPLICATED );
ConVar mp_bonusroundtime( "mp_bonusroundtime", "15", FCVAR_REPLICATED, "Time after round win until round restarts", true, 5, true, 15 );
+ConVar mp_bonusroundtime_final( "mp_bonusroundtime_final", "15", FCVAR_REPLICATED, "Time after final round ends until round restarts", true, 5, true, 300 );
ConVar mp_stalemate_meleeonly( "mp_stalemate_meleeonly", "0", FCVAR_REPLICATED | FCVAR_NOTIFY, "Restrict everyone to melee weapons only while in Sudden Death." );
ConVar mp_forceautoteam( "mp_forceautoteam", "0", FCVAR_REPLICATED | FCVAR_NOTIFY, "Automatically assign players to teams when joining." );
+#if defined( _DEBUG ) || defined( STAGING_ONLY )
+ConVar mp_developer( "mp_developer", "0", FCVAR_ARCHIVE | FCVAR_REPLICATED | FCVAR_NOTIFY, "1: basic conveniences (instant respawn and class change, etc). 2: add combat conveniences (infinite ammo, buddha, etc)" );
+#endif // _DEBUG || STAGING_ONLY
+
#ifdef GAME_DLL
ConVar mp_showroundtransitions( "mp_showroundtransitions", "0", FCVAR_CHEAT | FCVAR_DEVELOPMENTONLY, "Show gamestate round transitions." );
ConVar mp_enableroundwaittime( "mp_enableroundwaittime", "1", FCVAR_REPLICATED, "Enable timers to wait between rounds." );
@@ -358,25 +361,21 @@ CTeamplayRoundBasedRules::CTeamplayRoundBasedRules( void )
m_flNextRespawnWave.Set( i, 0 );
m_TeamRespawnWaveTimes.Set( i, -1.0f );
- m_bTeamReady.Set( i, false );
-
#ifdef GAME_DLL
m_flOriginalTeamRespawnWaveTime[i] = -1.0f;
#endif
}
- for ( int i = 0; i < MAX_PLAYERS; i++ )
- {
- m_bPlayerReady.Set( i, false );
- }
-
m_bInOvertime = false;
m_bInSetup = false;
m_bSwitchedTeamsThisRound = false;
m_flStopWatchTotalTime = -1.0f;
m_bMultipleTrains = false;
+ m_bAllowBetweenRounds = true;
#ifdef GAME_DLL
+ ListenForGameEvent( "server_changelevel_failed" );
+
m_pCurStateInfo = NULL;
State_Transition( GR_STATE_PREGAME );
@@ -390,8 +389,8 @@ CTeamplayRoundBasedRules::CTeamplayRoundBasedRules( void )
SetRoundToPlayNext( NULL_STRING );
m_bInWaitingForPlayers = false;
m_bAwaitingReadyRestart = false;
- m_flRestartRoundTime = -1;
- m_flMapResetTime = 0;
+ m_flRestartRoundTime = -1.0f;
+ m_flMapResetTime = 0.0f;
m_bPrevRoundWasWaitingForPlayers = false;
m_iWinningTeam = TEAM_UNASSIGNED;
@@ -400,12 +399,13 @@ CTeamplayRoundBasedRules::CTeamplayRoundBasedRules( void )
m_bAllowStalemateAtTimelimit = false;
m_bChangelevelAfterStalemate = false;
- m_flRoundStartTime = 0;
- m_flNewThrottledAlertTime = 0;
- m_flStartBalancingTeamsAt = 0;
+ m_flRoundStartTime = 0.0f;
+ m_flNewThrottledAlertTime = 0.0f;
+ m_flStartBalancingTeamsAt = 0.0f;
m_bPrintedUnbalanceWarning = false;
- m_flFoundUnbalancedTeamsTime = -1;
+ m_flFoundUnbalancedTeamsTime = -1.0f;
m_flWaitingForPlayersTimeEnds = 0.0f;
+ m_flLastTeamWin = -1.0f;
m_nRoundsPlayed = 0;
m_bUseAddScoreAnim = false;
@@ -413,18 +413,20 @@ CTeamplayRoundBasedRules::CTeamplayRoundBasedRules( void )
m_bStopWatch = false;
m_bAwaitingReadyRestart = false;
- if ( IsInTournamentMode() == true )
+ if ( IsInTournamentMode() )
{
m_bAwaitingReadyRestart = true;
}
- m_flAutoBalanceQueueTimeEnd = -1;
+ m_flAutoBalanceQueueTimeEnd = -1.0f;
m_nAutoBalanceQueuePlayerIndex = -1;
m_nAutoBalanceQueuePlayerScore = -1;
SetDefLessFunc( m_GameTeams );
m_bCheatsEnabledDuringLevel = false;
+ ResetPlayerAndTeamReadyState();
+
#endif
}
@@ -580,6 +582,22 @@ float CTeamplayRoundBasedRules::GetRespawnTimeScalar( int iTeam )
return flScale;
}
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CTeamplayRoundBasedRules::FireGameEvent( IGameEvent * event )
+{
+#ifdef GAME_DLL
+ const char *eventName = event->GetName();
+ if ( g_fGameOver && !Q_strcmp( eventName, "server_changelevel_failed" ) )
+ {
+ Warning( "In gameover, but failed to load the next map. Trying next map in cycle.\n" );
+ nextlevel.SetValue( "" );
+ ChangeLevel();
+ }
+#endif
+}
+
#ifdef GAME_DLL
//-----------------------------------------------------------------------------
// Purpose:
@@ -616,7 +634,7 @@ void CTeamplayRoundBasedRules::Think( void )
// Don't run this code again
m_flIntermissionEndTime = 0.f;
- }
+ }
return;
}
@@ -853,7 +871,14 @@ void CTeamplayRoundBasedRules::CheckWaitingForPlayers( void )
mp_waitingforplayers_restart.SetValue( 0 );
}
- if( (mp_waitingforplayers_cancel.GetBool() || IsInItemTestingMode()) && IsInTournamentMode() == false )
+ bool bCancelWait = ( mp_waitingforplayers_cancel.GetBool() || IsInItemTestingMode() ) && !IsInTournamentMode();
+
+#if defined( _DEBUG ) || defined( STAGING_ONLY )
+ if ( mp_developer.GetBool() )
+ bCancelWait = true;
+#endif // _DEBUG || STAGING_ONLY
+
+ if ( bCancelWait )
{
// Cancel the wait period and manually Resume() the timer if
// it's not supposed to start paused at the beginning of a round.
@@ -975,11 +1000,7 @@ void CTeamplayRoundBasedRules::CheckRestartRound( void )
int iDelayMax = 60;
#if defined(TF_CLIENT_DLL) || defined(TF_DLL)
-#ifdef STAGING_ONLY
- if ( TFGameRules() && ( TFGameRules()->IsMannVsMachineMode() || TFGameRules()->IsRatedTournamentMode() ) )
-#else
- if ( TFGameRules() && TFGameRules()->IsMannVsMachineMode() )
-#endif // STAGING_ONLY
+ if ( TFGameRules() && ( TFGameRules()->IsMannVsMachineMode() || TFGameRules()->IsCompetitiveMode() ) )
{
iDelayMax = 180;
}
@@ -1068,7 +1089,7 @@ void CTeamplayRoundBasedRules::CheckRestartRound( void )
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
-bool CTeamplayRoundBasedRules::CheckTimeLimit( void )
+bool CTeamplayRoundBasedRules::CheckTimeLimit( bool bAllowEnd /*= true*/ )
{
if ( IsInPreMatch() == true )
return false;
@@ -1095,18 +1116,21 @@ bool CTeamplayRoundBasedRules::CheckTimeLimit( void )
bSwitchDueToTime = false;
}
- if( GetTimeLeft() <= 0 || m_bChangelevelAfterStalemate || bSwitchDueToTime )
+ if ( GetTimeLeft() <= 0 || m_bChangelevelAfterStalemate || bSwitchDueToTime )
{
- IGameEvent *event = gameeventmanager->CreateEvent( "teamplay_game_over" );
- if ( event )
+ if ( bAllowEnd )
{
- event->SetString( "reason", "Reached Time Limit" );
- gameeventmanager->FireEvent( event );
- }
+ IGameEvent *event = gameeventmanager->CreateEvent( "teamplay_game_over" );
+ if ( event )
+ {
+ event->SetString( "reason", "Reached Time Limit" );
+ gameeventmanager->FireEvent( event );
+ }
- SendTeamScoresEvent();
+ SendTeamScoresEvent();
- GoToIntermission();
+ GoToIntermission();
+ }
return true;
}
}
@@ -1145,20 +1169,23 @@ int CTeamplayRoundBasedRules::GetTimeLeft( void )
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
-bool CTeamplayRoundBasedRules::CheckNextLevelCvar( void )
+bool CTeamplayRoundBasedRules::CheckNextLevelCvar( bool bAllowEnd /*= true*/ )
{
if ( m_bForceMapReset )
{
- if ( nextlevel.GetString() && *nextlevel.GetString() && engine->IsMapValid( nextlevel.GetString() ) )
+ if ( nextlevel.GetString() && *nextlevel.GetString() )
{
- IGameEvent *event = gameeventmanager->CreateEvent( "teamplay_game_over" );
- if ( event )
+ if ( bAllowEnd )
{
- event->SetString( "reason", "NextLevel CVAR" );
- gameeventmanager->FireEvent( event );
- }
+ IGameEvent *event = gameeventmanager->CreateEvent( "teamplay_game_over" );
+ if ( event )
+ {
+ event->SetString( "reason", "NextLevel CVAR" );
+ gameeventmanager->FireEvent( event );
+ }
- GoToIntermission();
+ GoToIntermission();
+ }
return true;
}
}
@@ -1169,7 +1196,7 @@ bool CTeamplayRoundBasedRules::CheckNextLevelCvar( void )
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
-bool CTeamplayRoundBasedRules::CheckWinLimit( void )
+bool CTeamplayRoundBasedRules::CheckWinLimit( bool bAllowEnd /*= true*/ )
{
// has one team won the specified number of rounds?
int iWinLimit = mp_winlimit.GetInt();
@@ -1183,14 +1210,17 @@ bool CTeamplayRoundBasedRules::CheckWinLimit( void )
if ( pTeam->GetScore() >= iWinLimit )
{
- IGameEvent *event = gameeventmanager->CreateEvent( "teamplay_game_over" );
- if ( event )
+ if ( bAllowEnd )
{
- event->SetString( "reason", "Reached Win Limit" );
- gameeventmanager->FireEvent( event );
- }
+ IGameEvent *event = gameeventmanager->CreateEvent( "teamplay_game_over" );
+ if ( event )
+ {
+ event->SetString( "reason", "Reached Win Limit" );
+ gameeventmanager->FireEvent( event );
+ }
- GoToIntermission();
+ GoToIntermission();
+ }
return true;
}
}
@@ -1202,20 +1232,23 @@ bool CTeamplayRoundBasedRules::CheckWinLimit( void )
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
-bool CTeamplayRoundBasedRules::CheckMaxRounds()
+bool CTeamplayRoundBasedRules::CheckMaxRounds( bool bAllowEnd /*= true*/ )
{
if ( mp_maxrounds.GetInt() > 0 && IsInPreMatch() == false )
{
if ( m_nRoundsPlayed >= mp_maxrounds.GetInt() )
{
- IGameEvent *event = gameeventmanager->CreateEvent( "teamplay_game_over" );
- if ( event )
+ if ( bAllowEnd )
{
- event->SetString( "reason", "Reached Round Limit" );
- gameeventmanager->FireEvent( event );
- }
+ IGameEvent *event = gameeventmanager->CreateEvent( "teamplay_game_over" );
+ if ( event )
+ {
+ event->SetString( "reason", "Reached Round Limit" );
+ gameeventmanager->FireEvent( event );
+ }
- GoToIntermission();
+ GoToIntermission();
+ }
return true;
}
}
@@ -1435,17 +1468,17 @@ void CTeamplayRoundBasedRules::State_Enter_PREROUND( void )
m_flStateTransitionTime = gpGlobals->curtime + tf_arena_preround_time.GetInt();
}
#if defined(TF_CLIENT_DLL) || defined(TF_DLL)
- else if ( TFGameRules() && TFGameRules()->IsMannVsMachineMode() )
- {
- State_Transition( GR_STATE_BETWEEN_RNDS );
- TFObjectiveResource()->SetMannVsMachineBetweenWaves( true );
- }
-#ifdef STAGING_ONLY
- else if ( TFGameRules() && TFGameRules()->IsRatedTournamentMode() )
+ // Only allow at the very beginning of the game, or between waves in mvm
+ else if ( TFGameRules() && TFGameRules()->UsePlayerReadyStatusMode() && m_bAllowBetweenRounds )
{
State_Transition( GR_STATE_BETWEEN_RNDS );
+ m_bAllowBetweenRounds = false;
+
+ if ( TFGameRules()->IsMannVsMachineMode() )
+ {
+ TFObjectiveResource()->SetMannVsMachineBetweenWaves( true );
+ }
}
-#endif // STAGING_ONLY
#endif // #if defined(TF_CLIENT_DLL) || defined(TF_DLL)
else
{
@@ -1527,28 +1560,33 @@ void CTeamplayRoundBasedRules::State_Enter_RND_RUNNING( void )
void CTeamplayRoundBasedRules::CheckReadyRestart( void )
{
// check round restart
- if( m_flRestartRoundTime > 0 && m_flRestartRoundTime <= gpGlobals->curtime && !g_pServerBenchmark->IsBenchmarkRunning() )
+ if ( m_flRestartRoundTime > 0 && m_flRestartRoundTime <= gpGlobals->curtime && !g_pServerBenchmark->IsBenchmarkRunning() )
{
m_flRestartRoundTime = -1;
#ifdef TF_DLL
if ( TFGameRules() )
{
- if ( TFGameRules()->IsMannVsMachineMode() && g_pPopulationManager )
+ if ( TFGameRules()->IsMannVsMachineMode() )
{
- if ( TFObjectiveResource()->GetMannVsMachineIsBetweenWaves() )
+ if ( g_pPopulationManager && TFObjectiveResource()->GetMannVsMachineIsBetweenWaves() )
{
g_pPopulationManager->StartCurrentWave();
+ m_bAllowBetweenRounds = true;
return;
}
}
-#ifdef STAGING_ONLY
- else if ( TFGameRules()->IsRatedTournamentMode() )
+ else if ( TFGameRules()->IsCompetitiveMode() )
+ {
+ TFGameRules()->StartCompetitiveMatch();
+ return;
+ }
+ else if ( mp_tournament.GetBool() )
{
- TFGameRules()->StartRatedTournamentMatch();
+ // Temp
+ TFGameRules()->StartCompetitiveMatch();
return;
}
-#endif // STAGING_ONLY
}
#endif // TF_DLL
@@ -1556,34 +1594,28 @@ void CTeamplayRoundBasedRules::CheckReadyRestart( void )
State_Transition( GR_STATE_RESTART );
}
- // check ready restart
- if( m_bAwaitingReadyRestart )
- {
- int nTime = 5;
- bool bTeamReady = false;
+ bool bProcessReadyRestart = m_bAwaitingReadyRestart;
#ifdef TF_DLL
- if ( TFGameRules() )
+ bProcessReadyRestart &= TFGameRules() && !TFGameRules()->UsePlayerReadyStatusMode();
+#endif // TF_DLL
+
+ // check ready restart
+ if ( bProcessReadyRestart )
+ {
+ bool bTeamNotReady = false;
+ for ( int i = LAST_SHARED_TEAM + 1; i < GetNumberOfTeams(); i++ )
{
- if ( TFGameRules()->IsMannVsMachineMode() )
+ if ( !m_bTeamReady[i] )
{
- bTeamReady = AreDefendingPlayersReady();
- if ( bTeamReady )
- {
- nTime = 10;
- }
- }
- else
- {
- bTeamReady = m_bTeamReady[TF_TEAM_BLUE] && m_bTeamReady[TF_TEAM_RED];
+ bTeamNotReady = true;
+ break;
}
}
-#endif // TF_DLL
- if ( bTeamReady )
+ if ( !bTeamNotReady )
{
- //State_Transition( GR_STATE_RESTART );
- mp_restartgame.SetValue( nTime );
+ mp_restartgame.SetValue( 5 );
m_bAwaitingReadyRestart = false;
ShouldResetScores( true, true );
@@ -1596,31 +1628,31 @@ void CTeamplayRoundBasedRules::CheckReadyRestart( void )
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
-bool CTeamplayRoundBasedRules::AreDefendingPlayersReady()
+bool CTeamplayRoundBasedRules::AreLobbyPlayersOnTeamReady( int iTeam )
{
- // Get list of defenders
- CUtlVector<LobbyPlayerInfo_t> vecMvMDefenders;
- GetMvMPotentialDefendersLobbyPlayerInfo( vecMvMDefenders );
+ if ( !TFGameRules() )
+ return false;
+
+ if ( TFGameRules()->IsMannVsMachineMode() && iTeam == TF_TEAM_PVE_INVADERS )
+ return true;
- // Scan all the players, and bail as soon as we find one person
- // worth waiting for
bool bAtLeastOnePersonReady = false;
- for ( int i = 0; i < vecMvMDefenders.Count(); i++ )
- {
+
+ CUtlVector<LobbyPlayerInfo_t> vecLobbyPlayers;
+ GetPotentialPlayersLobbyPlayerInfo( vecLobbyPlayers );
- // Are they on the red team?
- const LobbyPlayerInfo_t &p = vecMvMDefenders[i];
- if ( !p.m_bConnected || p.m_iTeam == TEAM_UNASSIGNED || p.m_nEntNum <= 0 || p.m_nEntNum >= MAX_PLAYERS )
+ for ( int i = 0; i < vecLobbyPlayers.Count(); i++ )
+ {
+ const LobbyPlayerInfo_t &p = vecLobbyPlayers[i];
+
+ // Make sure all lobby players are connected
+ if ( !AreLobbyPlayersConnected() )
{
- // They're still getting set up. We'll wait for them,
- // but only if they are in the lobby
- if ( p.m_bInLobby )
- return false;
+ return false;
}
- else if ( p.m_iTeam == TF_TEAM_PVE_DEFENDERS )
+ // All are connected, make sure their team is ready
+ else if ( p.m_iTeam == iTeam )
{
-
- // If he isn't ready, then we aren't ready
if ( !m_bPlayerReady[ p.m_nEntNum ] )
return false;
@@ -1629,8 +1661,12 @@ bool CTeamplayRoundBasedRules::AreDefendingPlayersReady()
}
else
{
- // And you may ask yourself, "How did I get here?"
- Assert( p.m_iTeam == TF_TEAM_PVE_DEFENDERS );
+ // In MvM, only the red team should pass through here
+ if ( TFGameRules()->IsMannVsMachineMode() )
+ {
+ // And you may ask yourself, "How did I get here?"
+ Assert( p.m_iTeam == iTeam );
+ }
}
}
@@ -1639,6 +1675,32 @@ bool CTeamplayRoundBasedRules::AreDefendingPlayersReady()
return bAtLeastOnePersonReady;
}
+//-----------------------------------------------------------------------------
+// Purpose: Is everyone in the lobby connected to the server?
+//-----------------------------------------------------------------------------
+bool CTeamplayRoundBasedRules::AreLobbyPlayersConnected( void )
+{
+ CUtlVector<LobbyPlayerInfo_t> vecLobbyPlayers;
+ GetPotentialPlayersLobbyPlayerInfo( vecLobbyPlayers );
+
+ // If you're calling this, you should have lobby members
+ Assert( vecLobbyPlayers.Count() );
+
+ for ( int i = 0; i < vecLobbyPlayers.Count(); i++ )
+ {
+ const LobbyPlayerInfo_t &pLobbyPlayer = vecLobbyPlayers[i];
+ if ( !pLobbyPlayer.m_bConnected ||
+ pLobbyPlayer.m_nEntNum <= 0 ||
+ pLobbyPlayer.m_nEntNum >= MAX_PLAYERS ||
+ ( TFGameRules() && TFGameRules()->IsMannVsMachineMode() && pLobbyPlayer.m_iTeam == TEAM_UNASSIGNED ) )
+ {
+ if ( pLobbyPlayer.m_bInLobby )
+ return false;
+ }
+ }
+
+ return true;
+}
#endif // #if defined(TF_CLIENT_DLL) || defined(TF_DLL)
//-----------------------------------------------------------------------------
@@ -1657,6 +1719,15 @@ void CTeamplayRoundBasedRules::State_Think_RND_RUNNING( void )
}
#endif
+#ifdef TF_DLL
+ // Mass time-out? Clean everything up.
+ if ( TFGameRules() && TFGameRules()->IsCompetitiveMode() )
+ {
+ TFGameRules()->EndCompetitiveMatch();
+ return;
+ }
+#endif // TF_DLL
+
State_Transition( GR_STATE_PREGAME );
return;
}
@@ -1672,9 +1743,8 @@ void CTeamplayRoundBasedRules::State_Think_RND_RUNNING( void )
// check round restart
CheckReadyRestart();
-
// See if we're coming up to the server timelimit, in which case force a stalemate immediately.
- if ( State_Get() == GR_STATE_RND_RUNNING && mp_timelimit.GetInt() > 0 && IsInPreMatch() == false && GetTimeLeft() <= 0 )
+ if ( mp_timelimit.GetInt() > 0 && IsInPreMatch() == false && GetTimeLeft() <= 0 )
{
if ( m_bAllowStalemateAtTimelimit || ( mp_match_end_at_timelimit.GetBool() && !IsValveMap() ) )
{
@@ -1730,9 +1800,7 @@ void CTeamplayRoundBasedRules::State_Think_RND_RUNNING( void )
//-----------------------------------------------------------------------------
void CTeamplayRoundBasedRules::State_Enter_TEAM_WIN( void )
{
- float flTime = GetBonusRoundTime();
-
- m_flStateTransitionTime = gpGlobals->curtime + flTime;
+ m_flStateTransitionTime = gpGlobals->curtime + GetBonusRoundTime();
// if we're forcing the map to reset it must be the end of a "full" round not a mini-round
if ( m_bForceMapReset )
@@ -1744,18 +1812,14 @@ void CTeamplayRoundBasedRules::State_Enter_TEAM_WIN( void )
SendWinPanelInfo();
-#ifdef STAGING_ONLY
#ifdef TF_DLL
- if ( TFGameRules() && TFGameRules()->IsRatedTournamentMode() )
+ // Do this now, so players don't leave before the usual CheckWinLimit() call happens
+ bool bDone = ( CheckTimeLimit( false ) || CheckWinLimit( false ) || CheckMaxRounds( false ) || CheckNextLevelCvar( false ) );
+ if ( TFGameRules() && TFGameRules()->IsCompetitiveMode() && bDone )
{
- // Do this now, so players don't leave before the usual CheckWinLimit() call happens
- if ( CheckWinLimit() )
- {
- TFGameRules()->SkillRating_CalculateAdjustmentForTeams( m_iWinningTeam );
- }
+ TFGameRules()->StopCompetitiveMatch( CMsgGC_Match_Result_Status_MATCH_SUCCEEDED );
}
#endif // TF_DLL
-#endif // STAGING_ONLY
}
//-----------------------------------------------------------------------------
@@ -1773,10 +1837,10 @@ void CTeamplayRoundBasedRules::State_Think_TEAM_WIN( void )
}
#endif // TF_DLL
- bool bDone = !(!CheckTimeLimit() && !CheckWinLimit() && !CheckMaxRounds() && !CheckNextLevelCvar());
+ bool bDone = ( CheckTimeLimit() || CheckWinLimit() || CheckMaxRounds() || CheckNextLevelCvar() );
// check the win limit, max rounds, time limit and nextlevel cvar before starting the next round
- if ( bDone == false )
+ if ( !bDone )
{
PreviousRoundEnd();
@@ -1797,7 +1861,7 @@ void CTeamplayRoundBasedRules::State_Think_TEAM_WIN( void )
State_Transition( GR_STATE_PREROUND );
}
}
- else if ( IsInTournamentMode() == true )
+ else if ( IsInTournamentMode() )
{
for ( int i = 1; i <= MAX_PLAYERS; i++ )
{
@@ -1811,7 +1875,7 @@ void CTeamplayRoundBasedRules::State_Think_TEAM_WIN( void )
RestartTournament();
- if ( IsInArenaMode() == true )
+ if ( IsInArenaMode() )
{
#if defined( REPLAY_ENABLED )
if ( g_pReplay )
@@ -1823,33 +1887,43 @@ void CTeamplayRoundBasedRules::State_Think_TEAM_WIN( void )
State_Transition( GR_STATE_PREROUND );
}
- else
- {
#ifdef TF_DLL
- if ( TFGameRules() && TFGameRules()->IsMannVsMachineMode() )
+ else if ( TFGameRules() && TFGameRules()->IsMannVsMachineMode() && g_pPopulationManager )
+ {
+ // one of the convars mp_timelimit, mp_winlimit, mp_maxrounds, or nextlevel has been triggered
+ for ( int i = 1; i <= MAX_PLAYERS; i++ )
{
- // one of the convars mp_timelimit, mp_winlimit, mp_maxrounds, or nextlevel has been triggered
- if ( g_pPopulationManager )
- {
- for ( int i = 1; i <= MAX_PLAYERS; i++ )
- {
- CBasePlayer *pPlayer = UTIL_PlayerByIndex( i );
+ CBasePlayer *pPlayer = UTIL_PlayerByIndex( i );
+ if ( !pPlayer )
+ continue;
- if ( !pPlayer )
- continue;
+ pPlayer->AddFlag( FL_FROZEN );
+ }
- pPlayer->AddFlag( FL_FROZEN );
- pPlayer->ShowViewPortPanel( PANEL_SCOREBOARD );
- }
+ g_fGameOver = true;
+ g_pPopulationManager->SetMapRestartTime( gpGlobals->curtime + 10.0f );
+ State_Enter( GR_STATE_GAME_OVER );
+ return;
+ }
+ else if ( TFGameRules() && TFGameRules()->UsePlayerReadyStatusMode() )
+ {
+ for ( int i = 1; i <= MAX_PLAYERS; i++ )
+ {
+ CBasePlayer *pPlayer = UTIL_PlayerByIndex( i );
+ if ( !pPlayer )
+ continue;
- g_fGameOver = true;
- g_pPopulationManager->SetMapRestartTime( gpGlobals->curtime + 10.0f );
- State_Enter( GR_STATE_GAME_OVER );
- return;
- }
+ pPlayer->AddFlag( FL_FROZEN );
}
+ g_fGameOver = true;
+ State_Enter( GR_STATE_GAME_OVER );
+ m_flStateTransitionTime = gpGlobals->curtime + GetBonusRoundTime( true );
+ return;
+ }
#endif // TF_DLL
+ else
+ {
State_Transition( GR_STATE_RND_RUNNING );
}
}
@@ -2180,7 +2254,7 @@ int TeamScoreSort( CTeam* const *pTeam1, CTeam* const *pTeam2 )
//-----------------------------------------------------------------------------
// Purpose: Input for other entities to declare a round winner.
//-----------------------------------------------------------------------------
-void CTeamplayRoundBasedRules::SetWinningTeam( int team, int iWinReason, bool bForceMapReset /* = true */, bool bSwitchTeams /* = false*/, bool bDontAddScore /* = false*/ )
+void CTeamplayRoundBasedRules::SetWinningTeam( int team, int iWinReason, bool bForceMapReset /* = true */, bool bSwitchTeams /* = false*/, bool bDontAddScore /* = false*/, bool bFinal /*= false*/ )
{
// Commentary doesn't let anyone win
if ( IsInCommentaryMode() )
@@ -2224,6 +2298,8 @@ void CTeamplayRoundBasedRules::SetWinningTeam( int team, int iWinReason, bool bF
State_Transition( GR_STATE_TEAM_WIN );
+ m_flLastTeamWin = gpGlobals->curtime;
+
IGameEvent *event = gameeventmanager->CreateEvent( "teamplay_round_win" );
if ( event )
{
@@ -2438,6 +2514,10 @@ void CTeamplayRoundBasedRules::RestartTournament( void )
m_flStopWatchTotalTime = -1.0f;
m_bStopWatch = false;
+ // we might have had a stalemate during the last round
+ // so reset this bool each time we restart the tournament
+ m_bChangelevelAfterStalemate = false;
+
for ( int i = 0; i < MAX_TEAMS; i++ )
{
m_bTeamReady.Set( i, false );
@@ -2582,6 +2662,30 @@ void CTeamplayRoundBasedRules::HandleTimeLimitChange( void )
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
+void CTeamplayRoundBasedRules::ResetPlayerAndTeamReadyState( void )
+{
+ for ( int i = 0; i < MAX_TEAMS; i++ )
+ {
+ m_bTeamReady.Set( i, false );
+ }
+
+ for ( int i = 0; i < MAX_PLAYERS; i++ )
+ {
+ m_bPlayerReady.Set( i, false );
+ }
+
+#ifdef GAME_DLL
+ // Note <= MAX_PLAYERS vs < MAX_PLAYERS above
+ for ( int i = 0; i <= MAX_PLAYERS; i++ )
+ {
+ m_bPlayerReadyBefore[i] = false;
+ }
+#endif // GAME_DLL
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
bool CTeamplayRoundBasedRules::MapHasActiveTimer( void )
{
#ifndef CSTRIKE_DLL
@@ -2606,6 +2710,12 @@ void CTeamplayRoundBasedRules::CreateTimeLimitTimer( void )
if ( IsInArenaMode () == true || IsInKothMode() == true )
return;
+ // this is the same check we use in State_Think_RND_RUNNING()
+ // don't show the timelimit timer if we're not going to end the map when it runs out
+ bool bAllowStalemate = ( m_bAllowStalemateAtTimelimit || ( mp_match_end_at_timelimit.GetBool() && !IsValveMap() ) );
+ if ( !bAllowStalemate )
+ return;
+
#ifndef CSTRIKE_DLL
if ( !m_hTimeLimitTimer )
{
@@ -2886,6 +2996,11 @@ void CTeamplayRoundBasedRules::BalanceTeams( bool bRequireSwitcheesToBeDead )
return;
}
+#if defined( _DEBUG ) || defined( STAGING_ONLY )
+ if ( mp_developer.GetBool() )
+ return;
+#endif // _DEBUG || STAGING_ONLY
+
if ( IsInTraining() || IsInItemTestingMode() )
{
return;
@@ -3314,9 +3429,12 @@ bool CTeamplayRoundBasedRules::IsInHighlanderMode( void )
#endif
}
-int CTeamplayRoundBasedRules::GetBonusRoundTime( void )
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+int CTeamplayRoundBasedRules::GetBonusRoundTime( bool bFinal /*= false*/ )
{
- return MAX( 5, mp_bonusroundtime.GetFloat() );
+ return bFinal ? mp_bonusroundtime_final.GetInt() : Max( 5, mp_bonusroundtime.GetInt() );
}
//-----------------------------------------------------------------------------
@@ -3330,6 +3448,11 @@ bool CTeamplayRoundBasedRules::ShouldBalanceTeams( void )
if ( IsInTraining() == true || IsInItemTestingMode() )
return false;
+#if defined( _DEBUG ) || defined( STAGING_ONLY )
+ if ( mp_developer.GetBool() )
+ return false;
+#endif // _DEBUG || STAGING_ONLY
+
if ( mp_teams_unbalance_limit.GetInt() <= 0 )
return false;
@@ -3349,6 +3472,11 @@ bool CTeamplayRoundBasedRules::WouldChangeUnbalanceTeams( int iNewTeam, int iCur
if ( ShouldBalanceTeams() == false )
return false;
+#if defined( _DEBUG ) || defined( STAGING_ONLY )
+ if ( mp_developer.GetBool() )
+ return false;
+#endif // _DEBUG || STAGING_ONLY
+
// if they are joining a non-playing team, allow
if ( iNewTeam < FIRST_GAME_TEAM )
return false;
@@ -3524,25 +3652,30 @@ void CTeamplayRoundBasedRules::ResetTeamsRoundWinTracking( void )
//-----------------------------------------------------------------------------
// Purpose: Are you now, or are you ever going to be, a member of the defending party?
//-----------------------------------------------------------------------------
-void CTeamplayRoundBasedRules::GetMvMPotentialDefendersLobbyPlayerInfo( CUtlVector<LobbyPlayerInfo_t> &vecMvMDefenders, bool bIncludeBots /*= false*/ )
+void CTeamplayRoundBasedRules::GetPotentialPlayersLobbyPlayerInfo( CUtlVector<LobbyPlayerInfo_t> &vecLobbyPlayers, bool bIncludeBots /*= false*/ )
{
- GetAllPlayersLobbyInfo( vecMvMDefenders, bIncludeBots );
+ GetAllPlayersLobbyInfo( vecLobbyPlayers, bIncludeBots );
// Now scan through and remove the spectators
- for (int i = vecMvMDefenders.Count() - 1 ; i >= 0 ; --i )
+ for ( int i = vecLobbyPlayers.Count() - 1; i >= 0; --i )
{
- switch ( vecMvMDefenders[i].m_iTeam )
+ switch ( vecLobbyPlayers[i].m_iTeam )
{
case TEAM_UNASSIGNED:
- case TF_TEAM_PVE_DEFENDERS:
+ case TF_TEAM_RED:
+ break;
+
+ case TF_TEAM_BLUE:
+ if ( TFGameRules() && TFGameRules()->IsMannVsMachineMode() )
+ vecLobbyPlayers.FastRemove( i );
break;
- default:
- AssertMsg1( false, "Bogus team %d", vecMvMDefenders[i].m_iTeam );
- case TF_TEAM_PVE_INVADERS:
case TEAM_SPECTATOR:
- vecMvMDefenders.FastRemove( i );
+ vecLobbyPlayers.FastRemove( i );
break;
+
+ default:
+ AssertMsg1( false, "Bogus team %d", vecLobbyPlayers[i].m_iTeam );
}
}
}
diff --git a/mp/src/game/shared/teamplayroundbased_gamerules.h b/mp/src/game/shared/teamplayroundbased_gamerules.h
index ddf6e791..95060d3d 100644
--- a/mp/src/game/shared/teamplayroundbased_gamerules.h
+++ b/mp/src/game/shared/teamplayroundbased_gamerules.h
@@ -12,6 +12,7 @@
#include "teamplay_gamerules.h"
#include "teamplay_round_timer.h"
+#include "GameEventListener.h"
#ifdef GAME_DLL
#include "team_control_point.h"
@@ -162,7 +163,7 @@ public:
//-----------------------------------------------------------------------------
// Purpose: Teamplay game rules that manage a round based structure for you
//-----------------------------------------------------------------------------
-class CTeamplayRoundBasedRules : public CTeamplayRules
+class CTeamplayRoundBasedRules : public CTeamplayRules, public CGameEventListener
{
DECLARE_CLASS( CTeamplayRoundBasedRules, CTeamplayRules );
public:
@@ -248,7 +249,7 @@ public:
void SetMultipleTrains( bool bMultipleTrains ){ m_bMultipleTrains = bMultipleTrains; }
bool HasMultipleTrains( void ){ return m_bMultipleTrains; }
- virtual int GetBonusRoundTime( void );
+ virtual int GetBonusRoundTime( bool bFinal = false );
#if defined(TF_CLIENT_DLL) || defined(TF_DLL)
@@ -258,10 +259,15 @@ public:
// Get list of players who are on the defending team now, or are likely
// to end up on the defending team (not yet connected or assigned a team)
- void GetMvMPotentialDefendersLobbyPlayerInfo( CUtlVector<LobbyPlayerInfo_t> &vecMvmDefenders, bool bIncludeBots = false );
+ void GetPotentialPlayersLobbyPlayerInfo( CUtlVector<LobbyPlayerInfo_t> &vecLobbyPlayers, bool bIncludeBots = false );
#endif
+ void SetAllowBetweenRounds( bool bValue ) { m_bAllowBetweenRounds = bValue; }
+
+public: // IGameEventListener Interface
+ virtual void FireGameEvent( IGameEvent * event );
+
//----------------------------------------------------------------------------------
// Server specific
#ifdef GAME_DLL
@@ -309,7 +315,7 @@ public:
virtual bool ShouldScorePerRound( void ){ return true; }
- bool CheckNextLevelCvar( void );
+ bool CheckNextLevelCvar( bool bAllowEnd = true );
virtual bool TimerMayExpire( void );
@@ -332,7 +338,7 @@ public:
bool IsPreviouslyPlayedRound ( string_t strName );
string_t GetLastPlayedRound( void );
- virtual void SetWinningTeam( int team, int iWinReason, bool bForceMapReset = true, bool bSwitchTeams = false, bool bDontAddScore = false );
+ virtual void SetWinningTeam( int team, int iWinReason, bool bForceMapReset = true, bool bSwitchTeams = false, bool bDontAddScore = false, bool bFinal = false ) OVERRIDE;
virtual void SetStalemate( int iReason, bool bForceMapReset = true, bool bSwitchTeams = false );
virtual void SetRoundOverlayDetails( void ){ return; }
@@ -365,10 +371,11 @@ public:
{
m_bPlayerReady.Set( iIndex, bState );
}
+ void ResetPlayerAndTeamReadyState( void );
virtual void PlayTrainCaptureAlert( CTeamControlPoint *pPoint, bool bFinalPointInMap ){ return; }
- virtual void PlaySpecialCapSounds( int iCappingTeam ){ return; }
+ virtual void PlaySpecialCapSounds( int iCappingTeam, CTeamControlPoint *pPoint ){ return; }
bool PlayThrottledAlert( int iTeam, const char *sound, float fDelayBeforeNext );
@@ -393,14 +400,15 @@ protected:
void CheckWaitingForPlayers( void );
virtual bool AllowWaitingForPlayers( void ) { return true; }
void CheckRestartRound( void );
- bool CheckTimeLimit( void );
+ bool CheckTimeLimit( bool bAllowEnd = true );
int GetTimeLeft( void );
- virtual bool CheckWinLimit( void );
- bool CheckMaxRounds( void );
+ virtual bool CheckWinLimit( bool bAllowEnd = true );
+ bool CheckMaxRounds( bool bAllowEnd = true );
void CheckReadyRestart( void );
#if defined(TF_CLIENT_DLL) || defined(TF_DLL)
- bool AreDefendingPlayersReady();
+ bool AreLobbyPlayersOnTeamReady( int iTeam );
+ bool AreLobbyPlayersConnected( void );
#endif
virtual bool CanChangelevelBecauseOfTimeLimit( void ) { return true; }
@@ -479,6 +487,8 @@ protected:
bool MapHasActiveTimer( void );
void CreateTimeLimitTimer( void );
+ virtual float GetLastMajorEventTime( void ) OVERRIDE { return m_flLastTeamWin; }
+
protected:
CGameRulesRoundStateInfo *m_pCurStateInfo; // Per-state data
float m_flStateTransitionTime; // Timer for round states
@@ -521,10 +531,13 @@ protected:
gamerules_roundstate_t m_prevState;
+ bool m_bPlayerReadyBefore[MAX_PLAYERS+1]; // Test to see if a player has hit ready before
+
+ float m_flLastTeamWin;
+
private:
CUtlMap < int, int > m_GameTeams; // Team index, Score
-
#endif
// End server specific
//----------------------------------------------------------------------------------
@@ -582,6 +595,9 @@ private:
int m_nAutoBalanceQueuePlayerIndex;
int m_nAutoBalanceQueuePlayerScore;
+protected:
+ bool m_bAllowBetweenRounds;
+
public:
float m_flStopWatchTotalTime;
diff --git a/mp/src/game/shared/triggers_shared.h b/mp/src/game/shared/triggers_shared.h
new file mode 100644
index 00000000..1467ae93
--- /dev/null
+++ b/mp/src/game/shared/triggers_shared.h
@@ -0,0 +1,33 @@
+//====== Copyright � 1996-2005, Valve Corporation, All rights reserved. =======
+//
+// Purpose:
+//
+//=============================================================================
+
+#ifndef TRIGGERS_SHARED_H
+#define TRIGGERS_SHARED_H
+#ifdef _WIN32
+#pragma once
+#endif
+
+//
+// Spawnflags
+//
+enum
+{
+ SF_TRIGGER_ALLOW_CLIENTS = 0x01, // Players can fire this trigger
+ SF_TRIGGER_ALLOW_NPCS = 0x02, // NPCS can fire this trigger
+ SF_TRIGGER_ALLOW_PUSHABLES = 0x04, // Pushables can fire this trigger
+ SF_TRIGGER_ALLOW_PHYSICS = 0x08, // Physics objects can fire this trigger
+ SF_TRIGGER_ONLY_PLAYER_ALLY_NPCS = 0x10, // *if* NPCs can fire this trigger, this flag means only player allies do so
+ SF_TRIGGER_ONLY_CLIENTS_IN_VEHICLES = 0x20, // *if* Players can fire this trigger, this flag means only players inside vehicles can
+ SF_TRIGGER_ALLOW_ALL = 0x40, // Everything can fire this trigger EXCEPT DEBRIS!
+ SF_TRIGGER_ONLY_CLIENTS_OUT_OF_VEHICLES = 0x200, // *if* Players can fire this trigger, this flag means only players outside vehicles can
+ SF_TRIG_PUSH_ONCE = 0x80, // trigger_push removes itself after firing once
+ SF_TRIG_PUSH_AFFECT_PLAYER_ON_LADDER = 0x100, // if pushed object is player on a ladder, then this disengages them from the ladder (HL2only)
+ SF_TRIG_TOUCH_DEBRIS = 0x400, // Will touch physics debris objects
+ SF_TRIGGER_ONLY_NPCS_IN_VEHICLES = 0X800, // *if* NPCs can fire this trigger, only NPCs in vehicles do so (respects player ally flag too)
+ SF_TRIGGER_DISALLOW_BOTS = 0x1000, // Bots are not allowed to fire this trigger
+};
+
+#endif // TRIGGERS_SHARED_H
diff --git a/mp/src/game/shared/usercmd.h b/mp/src/game/shared/usercmd.h
index 20b40345..0005bde9 100644
--- a/mp/src/game/shared/usercmd.h
+++ b/mp/src/game/shared/usercmd.h
@@ -51,6 +51,9 @@ public:
weaponselect = 0;
weaponsubtype = 0;
random_seed = 0;
+#ifdef GAME_DLL
+ server_random_seed = 0;
+#endif
mousedx = 0;
mousedy = 0;
@@ -76,6 +79,9 @@ public:
weaponselect = src.weaponselect;
weaponsubtype = src.weaponsubtype;
random_seed = src.random_seed;
+#ifdef GAME_DLL
+ server_random_seed = src.server_random_seed;
+#endif
mousedx = src.mousedx;
mousedy = src.mousedy;
@@ -151,6 +157,9 @@ public:
int weaponsubtype;
int random_seed; // For shared random functions
+#ifdef GAME_DLL
+ int server_random_seed; // Only the server populates this seed
+#endif
short mousedx; // mouse accum in x from create move
short mousedy; // mouse accum in y from create move
diff --git a/mp/src/game/shared/util_shared.h b/mp/src/game/shared/util_shared.h
index 18f066c3..83793418 100644
--- a/mp/src/game/shared/util_shared.h
+++ b/mp/src/game/shared/util_shared.h
@@ -441,8 +441,8 @@ inline float DistanceToRay( const Vector &pos, const Vector &rayStart, const Vec
public: \
interfaceName( bool bAutoAdd = true ); \
virtual ~interfaceName(); \
- static void Add( interfaceName *pElement ) { m_##interfaceName##AutoList.AddToTail( pElement ); } \
- static void Remove( interfaceName *pElement ) { m_##interfaceName##AutoList.FindAndFastRemove( pElement ); } \
+ static void AddToAutoList( interfaceName *pElement ) { m_##interfaceName##AutoList.AddToTail( pElement ); } \
+ static void RemoveFromAutoList( interfaceName *pElement ) { m_##interfaceName##AutoList.FindAndFastRemove( pElement ); } \
static const CUtlVector< interfaceName* >& AutoList( void ) { return m_##interfaceName##AutoList; } \
private: \
static CUtlVector< interfaceName* > m_##interfaceName##AutoList; \
@@ -456,14 +456,28 @@ inline float DistanceToRay( const Vector &pos, const Vector &rayStart, const Vec
{ \
if ( bAutoAdd ) \
{ \
- Add( this ); \
+ AddToAutoList( this ); \
} \
} \
interfaceName::~interfaceName() \
{ \
- Remove( this ); \
+ RemoveFromAutoList( this ); \
}
+//--------------------------------------------------------------------------------------------------------------
+// This would do the same thing without requiring casts all over the place. Yes, it's a template, but
+// DECLARE_AUTO_LIST requires a CUtlVector<T> anyway. TODO ask about replacing the macros with this.
+//template<class T>
+//class AutoList {
+//public:
+// typedef CUtlVector<T*> AutoListType;
+// static AutoListType& All() { return m_autolist; }
+//protected:
+// AutoList() { m_autolist.AddToTail(static_cast<T*>(this)); }
+// virtual ~AutoList() { m_autolist.FindAndFastRemove(static_cast<T*>(this)); }
+//private:
+// static AutoListType m_autolist;
+//};
//--------------------------------------------------------------------------------------------------------------
/**
@@ -579,7 +593,15 @@ public:
private:
float m_duration;
float m_timestamp;
- float Now( void ) const; // work-around since client header doesn't like inlined gpGlobals->curtime
+ virtual float Now( void ) const; // work-around since client header doesn't like inlined gpGlobals->curtime
+};
+
+class RealTimeCountdownTimer : public CountdownTimer
+{
+ virtual float Now( void ) const OVERRIDE
+ {
+ return Plat_FloatTime();
+ }
};
char* ReadAndAllocStringValue( KeyValues *pSub, const char *pName, const char *pFilename = NULL );
diff --git a/mp/src/game/shared/voice_gamemgr.cpp b/mp/src/game/shared/voice_gamemgr.cpp
index 15523859..79933896 100644
--- a/mp/src/game/shared/voice_gamemgr.cpp
+++ b/mp/src/game/shared/voice_gamemgr.cpp
@@ -37,7 +37,7 @@ ConVar voice_serverdebug( "voice_serverdebug", "0" );
// Set game rules to allow all clients to talk to each other.
// Muted players still can't talk to each other.
-ConVar sv_alltalk( "sv_alltalk", "0", FCVAR_NOTIFY, "Players can hear all other players, no team restrictions" );
+ConVar sv_alltalk( "sv_alltalk", "0", FCVAR_NOTIFY | FCVAR_REPLICATED, "Players can hear all other players, no team restrictions" );
CVoiceGameMgr g_VoiceGameMgr;
@@ -289,4 +289,4 @@ bool CVoiceGameMgr::CheckProximity( int iDistance )
return true;
return false;
-} \ No newline at end of file
+}
diff --git a/mp/src/game/shared/weapon_parse.cpp b/mp/src/game/shared/weapon_parse.cpp
index 514da202..c42ad7f1 100644
--- a/mp/src/game/shared/weapon_parse.cpp
+++ b/mp/src/game/shared/weapon_parse.cpp
@@ -70,7 +70,7 @@ itemFlags_t g_ItemFlags[8] =
{ "ITEM_FLAG_NOITEMPICKUP", ITEM_FLAG_NOITEMPICKUP }
};
#else
-extern itemFlags_t g_ItemFlags[7];
+extern itemFlags_t g_ItemFlags[8];
#endif
@@ -78,7 +78,7 @@ static CUtlDict< FileWeaponInfo_t*, unsigned short > m_WeaponInfoDatabase;
#ifdef _DEBUG
// used to track whether or not two weapons have been mistakenly assigned the wrong slot
-bool g_bUsedWeaponSlots[MAX_WEAPON_SLOTS][MAX_WEAPON_POSITIONS] = { 0 };
+bool g_bUsedWeaponSlots[MAX_WEAPON_SLOTS][MAX_WEAPON_POSITIONS] = { { false } };
#endif