From 0d8dceea4310fde5706b3ce1c70609d72a38efdf Mon Sep 17 00:00:00 2001 From: John Schoenick Date: Wed, 9 Sep 2015 18:35:41 -0700 Subject: Updated the SDK with the latest code from the TF and HL2 branches. --- mp/src/game/shared/GameStats.cpp | 47 ++- mp/src/game/shared/ModelSoundsCache.cpp | 2 +- .../shared/Multiplayer/multiplayer_animstate.cpp | 12 + .../shared/Multiplayer/multiplayer_animstate.h | 8 + mp/src/game/shared/SceneCache.cpp | 2 +- mp/src/game/shared/SoundEmitterSystem.cpp | 14 +- mp/src/game/shared/SpriteTrail.h | 9 +- mp/src/game/shared/activitylist.cpp | 47 +++ mp/src/game/shared/ai_activity.h | 50 +++ mp/src/game/shared/animation.cpp | 83 +++- mp/src/game/shared/base_playeranimstate.cpp | 9 +- mp/src/game/shared/base_playeranimstate.h | 1 + mp/src/game/shared/basecombatcharacter_shared.cpp | 17 +- mp/src/game/shared/basecombatweapon_shared.cpp | 67 ++- mp/src/game/shared/basecombatweapon_shared.h | 48 ++- mp/src/game/shared/baseentity_shared.cpp | 9 +- mp/src/game/shared/baseentity_shared.h | 6 +- mp/src/game/shared/baseplayer_shared.cpp | 5 +- mp/src/game/shared/baseprojectile.cpp | 5 + mp/src/game/shared/baseprojectile.h | 9 +- mp/src/game/shared/cam_thirdperson.cpp | 16 +- mp/src/game/shared/cam_thirdperson.h | 16 +- mp/src/game/shared/effect_dispatch_data.cpp | 2 +- mp/src/game/shared/eventlist.cpp | 3 + mp/src/game/shared/eventlist.h | 3 + mp/src/game/shared/expressionsample.h | 1 + mp/src/game/shared/gamemovement.cpp | 2 +- mp/src/game/shared/gamerules.h | 2 + mp/src/game/shared/mp_shareddefs.cpp | 4 + mp/src/game/shared/mp_shareddefs.h | 3 + mp/src/game/shared/multiplay_gamerules.cpp | 98 +++-- mp/src/game/shared/multiplay_gamerules.h | 10 +- mp/src/game/shared/particle_parse.cpp | 35 +- mp/src/game/shared/particle_property.cpp | 6 +- mp/src/game/shared/ragdoll_shared.cpp | 8 +- mp/src/game/shared/shareddefs.h | 6 + mp/src/game/shared/takedamageinfo.cpp | 1 + mp/src/game/shared/takedamageinfo.h | 14 + mp/src/game/shared/teamplay_gamerules.h | 2 +- mp/src/game/shared/teamplay_round_timer.cpp | 71 +++- mp/src/game/shared/teamplay_round_timer.h | 2 +- .../game/shared/teamplayroundbased_gamerules.cpp | 467 +++++++++++++-------- mp/src/game/shared/teamplayroundbased_gamerules.h | 38 +- mp/src/game/shared/triggers_shared.h | 33 ++ mp/src/game/shared/usercmd.h | 9 + mp/src/game/shared/util_shared.h | 32 +- mp/src/game/shared/voice_gamemgr.cpp | 4 +- mp/src/game/shared/weapon_parse.cpp | 4 +- 48 files changed, 1036 insertions(+), 306 deletions(-) create mode 100644 mp/src/game/shared/triggers_shared.h (limited to 'mp/src/game/shared') 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 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; iLookupPoseParameter( 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 &mapList ) + void CMultiplayRules::LoadMapCycleFileIntoVector( const char *pszMapCycleFile, CUtlVector &mapList ) + { + CMultiplayRules::RawLoadMapCycleFileIntoVector( pszMapCycleFile, mapList ); + } + + void CMultiplayRules::RawLoadMapCycleFileIntoVector( const char *pszMapCycleFile, CUtlVector &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 &mapList ); + virtual void LoadMapCycleFileIntoVector ( const char *pszMapCycleFile, CUtlVector &mapList ); static void FreeMapCycleFileVector ( CUtlVector &mapList ); + // LoadMapCycleFileIntoVector without the fixups inherited versions of gamerules may provide + static void RawLoadMapCycleFileIntoVector ( const char *pszMapCycleFile, CUtlVector &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 "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 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 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 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 ); @@ -2579,6 +2659,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: //----------------------------------------------------------------------------- @@ -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 &vecMvMDefenders, bool bIncludeBots /*= false*/ ) +void CTeamplayRoundBasedRules::GetPotentialPlayersLobbyPlayerInfo( CUtlVector &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 &vecMvmDefenders, bool bIncludeBots = false ); + void GetPotentialPlayersLobbyPlayerInfo( CUtlVector &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 anyway. TODO ask about replacing the macros with this. +//template +//class AutoList { +//public: +// typedef CUtlVector AutoListType; +// static AutoListType& All() { return m_autolist; } +//protected: +// AutoList() { m_autolist.AddToTail(static_cast(this)); } +// virtual ~AutoList() { m_autolist.FindAndFastRemove(static_cast(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 -- cgit v1.2.3