1
0
mirror of https://github.com/alliedmodders/hl2sdk.git synced 2025-09-19 20:16:10 +08:00

Sync with upstream (Issue #30).

Recompiled tier1 and mathlib  for all platforms will come in next commit.
This commit is contained in:
Nicholas Hastings
2016-11-30 10:01:15 -05:00
parent 98fe5b5a34
commit 3957adff10
491 changed files with 29846 additions and 10698 deletions

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -342,6 +342,77 @@ int CStudioHdr::CActivityToSequenceMapping::SelectWeightedSequence( CStudioHdr *
}
int CStudioHdr::CActivityToSequenceMapping::SelectWeightedSequenceFromModifiers( CStudioHdr *pstudiohdr, int activity, CUtlSymbol *pActivityModifiers, int iModifierCount )
{
if ( !pstudiohdr->SequencesAvailable() )
{
return ACTIVITY_NOT_AVAILABLE;
}
VerifySequenceIndex( pstudiohdr );
if ( pstudiohdr->GetNumSeq() == 1 )
{
return ( ::GetSequenceActivity( pstudiohdr, 0, NULL ) == activity ) ? 0 : ACTIVITY_NOT_AVAILABLE;
}
if (!ValidateAgainst(pstudiohdr))
{
AssertMsg1(false, "CStudioHdr %s has changed its vmodel pointer without reinitializing its activity mapping! Now performing emergency reinitialization.", pstudiohdr->pszName());
ExecuteOnce(DebuggerBreakIfDebugging());
Reinitialize(pstudiohdr);
}
// a null m_pSequenceTuples just means that this studio header has no activities.
if (!m_pSequenceTuples)
return ACTIVITY_NOT_AVAILABLE;
// get the data for the given activity
HashValueType dummy( activity, 0, 0, 0 );
UtlHashHandle_t handle = m_ActToSeqHash.Find(dummy);
if (!m_ActToSeqHash.IsValidHandle(handle))
{
return ACTIVITY_NOT_AVAILABLE;
}
const HashValueType * __restrict actData = &m_ActToSeqHash[handle];
// go through each sequence and give it a score
int top_score = -1;
CUtlVector<int> topScoring( actData->count, actData->count );
for ( int i = 0; i < actData->count; i++ )
{
SequenceTuple * __restrict sequenceInfo = m_pSequenceTuples + actData->startingIdx + i;
int score = 0;
// count matching activity modifiers
for ( int m = 0; m < iModifierCount; m++ )
{
int num_modifiers = sequenceInfo->iNumActivityModifiers;
for ( int k = 0; k < num_modifiers; k++ )
{
if ( sequenceInfo->pActivityModifiers[ k ] == pActivityModifiers[ m ] )
{
score++;
break;
}
}
}
if ( score > top_score )
{
topScoring.RemoveAll();
topScoring.AddToTail( sequenceInfo->seqnum );
top_score = score;
}
}
// randomly pick between the highest scoring sequences ( NOTE: this method of selecting a sequence ignores activity weights )
if ( IsInPrediction() )
{
return topScoring[ SharedRandomInt( "SelectWeightedSequence", 0, topScoring.Count() - 1 ) ];
}
return topScoring[ RandomInt( 0, topScoring.Count() - 1 ) ];
}
#endif
@ -449,9 +520,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;
}
@ -463,11 +534,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;
@ -852,7 +919,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;

View File

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

View File

@ -234,6 +234,7 @@ private:
void EstimateYaw();
virtual bool ShouldResetMainSequence( int iCurrentSequence, int iNewSequence );
void ComputeMainSequence();
void ComputeAimSequence();

View File

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

View File

@ -1149,7 +1149,7 @@ float CBaseCombatWeapon::GetViewModelSequenceDuration()
return vm->SequenceDuration();
}
bool CBaseCombatWeapon::IsViewModelSequenceFinished( void )
bool CBaseCombatWeapon::IsViewModelSequenceFinished( void ) const
{
// These are not valid activities and always complete immediately
if ( GetActivity() == ACT_RESET || GetActivity() == ACT_INVALID )
@ -1452,7 +1452,12 @@ selects and deploys each weapon as you pass it. (sjb)
bool CBaseCombatWeapon::Deploy( )
{
MDLCACHE_CRITICAL_SECTION();
return DefaultDeploy( (char*)GetViewModel(), (char*)GetWorldModel(), GetDrawActivity(), (char*)GetAnimPrefix() );
bool bResult = DefaultDeploy( (char*)GetViewModel(), (char*)GetWorldModel(), GetDrawActivity(), (char*)GetAnimPrefix() );
// override pose parameters
PoseParameterOverride( false );
return bResult;
}
Activity CBaseCombatWeapon::GetDrawActivity( void )
@ -1511,6 +1516,9 @@ bool CBaseCombatWeapon::Holster( CBaseCombatWeapon *pSwitchingTo )
RescindReloadHudHint();
}
// reset pose parameters
PoseParameterOverride( true );
return true;
}
@ -1775,8 +1783,8 @@ void CBaseCombatWeapon::ItemPostFrame( void )
// -----------------------
// Reload pressed / Clip Empty
// -----------------------
if ( ( pOwner->m_nButtons & IN_RELOAD ) && UsesClipsForAmmo1() && !m_bInReload )
// Can only start the Reload Cycle after the firing cycle
if ( ( pOwner->m_nButtons & IN_RELOAD ) && m_flNextPrimaryAttack <= gpGlobals->curtime && UsesClipsForAmmo1() && !m_bInReload )
{
// reload when reload is pressed, or if no buttons are down and weapon is empty.
Reload();
@ -2440,23 +2448,53 @@ bool CBaseCombatWeapon::IsLocked( CBaseEntity *pAsker )
//-----------------------------------------------------------------------------
Activity CBaseCombatWeapon::ActivityOverride( Activity baseAct, bool *pRequired )
{
acttable_t *pTable = ActivityList();
int actCount = ActivityListCount();
int actCount = 0;
acttable_t *pTable = ActivityList( actCount );
for ( int i = 0; i < actCount; i++, pTable++ )
for ( int i = 0; i < actCount; i++ )
{
if ( baseAct == pTable->baseAct )
const acttable_t& act = pTable[i];
if ( baseAct == act.baseAct )
{
if (pRequired)
{
*pRequired = pTable->required;
*pRequired = act.required;
}
return (Activity)pTable->weaponAct;
return (Activity)act.weaponAct;
}
}
return baseAct;
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CBaseCombatWeapon::PoseParameterOverride( bool bReset )
{
CBaseCombatCharacter *pOwner = GetOwner();
if ( !pOwner )
return;
CStudioHdr *pStudioHdr = pOwner->GetModelPtr();
if ( !pStudioHdr )
return;
int iCount = 0;
poseparamtable_t *pPoseParamList = PoseParamList( iCount );
if ( pPoseParamList )
{
for ( int i=0; i<iCount; ++i )
{
int iPoseParam = pOwner->LookupPoseParameter( pStudioHdr, pPoseParamList[i].pszName );
if ( iPoseParam != -1 )
pOwner->SetPoseParameter( iPoseParam, bReset ? 0 : pPoseParamList[i].flValue );
}
}
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
@ -2745,6 +2783,13 @@ void* SendProxy_SendNonLocalWeaponDataTable( const SendProp *pProp, const void *
}
REGISTER_SEND_PROXY_NON_MODIFIED_POINTER( SendProxy_SendNonLocalWeaponDataTable );
#else
void CBaseCombatWeapon::RecvProxy_WeaponState( const CRecvProxyData *pData, void *pStruct, void *pOut )
{
CBaseCombatWeapon *pWeapon = (CBaseCombatWeapon*)pStruct;
pWeapon->m_iState = pData->m_Value.m_Int;
pWeapon->UpdateVisibility();
}
#endif
#if PREDICTION_ERROR_CHECK_LEVEL > 1
@ -2818,7 +2863,7 @@ BEGIN_NETWORK_TABLE(CBaseCombatWeapon, DT_BaseCombatWeapon)
RecvPropDataTable("LocalActiveWeaponData", 0, 0, &REFERENCE_RECV_TABLE(DT_LocalActiveWeaponData)),
RecvPropInt( RECVINFO(m_iViewModelIndex)),
RecvPropInt( RECVINFO(m_iWorldModelIndex)),
RecvPropInt( RECVINFO(m_iState )),
RecvPropInt( RECVINFO(m_iState), 0, &CBaseCombatWeapon::RecvProxy_WeaponState ),
RecvPropEHandle( RECVINFO(m_hOwner ) ),
#endif
END_NETWORK_TABLE()

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -87,6 +87,9 @@ typedef enum
AE_RD_ROBOT_POP_PANELS_OFF,
AE_TAUNT_ENABLE_MOVE,
AE_TAUNT_DISABLE_MOVE,
LAST_SHARED_ANIMEVENT,
} Animevent;

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -85,7 +85,8 @@ ConVar mp_show_voice_icons( "mp_show_voice_icons", "1", FCVAR_REPLICATED, "Show
#ifdef GAME_DLL
ConVar tv_delaymapchange( "tv_delaymapchange", "0", 0, "Delays map change until broadcast is complete" );
ConVar tv_delaymapchange( "tv_delaymapchange", "0", FCVAR_NONE, "Delays map change until broadcast is complete" );
ConVar tv_delaymapchange_protect( "tv_delaymapchange_protect", "1", FCVAR_NONE, "Protect against doing a manual map change if HLTV is broadcasting and has not caught up with a major game event such as round_end" );
ConVar mp_restartgame( "mp_restartgame", "0", FCVAR_GAMEDLL, "If non-zero, game will restart in the specified number of seconds" );
ConVar mp_restartgame_immediate( "mp_restartgame_immediate", "0", FCVAR_GAMEDLL, "If non-zero, game will restart immediately" );
@ -278,7 +279,7 @@ CMultiplayRules::CMultiplayRules()
if ( cfgfile && cfgfile[0] )
{
char szCommand[256];
char szCommand[MAX_PATH];
Log( "Executing dedicated server config file %s\n", cfgfile );
Q_snprintf( szCommand,sizeof(szCommand), "exec %s\n", cfgfile );
@ -292,7 +293,7 @@ CMultiplayRules::CMultiplayRules()
if ( cfgfile && cfgfile[0] )
{
char szCommand[256];
char szCommand[MAX_PATH];
Log( "Executing listen server config file %s\n", cfgfile );
Q_snprintf( szCommand,sizeof(szCommand), "exec %s\n", cfgfile );
@ -1164,7 +1165,7 @@ ConVarRef suitcharger( "sk_suitcharger" );
void CMultiplayRules::GetNextLevelName( char *pszNextMap, int bufsize, bool bRandom /* = false */ )
{
char mapcfile[256];
char mapcfile[MAX_PATH];
DetermineMapCycleFilename( mapcfile, sizeof(mapcfile), false );
// Check the time of the mapcycle file and re-populate the list of level names if the file has been modified
@ -1182,10 +1183,7 @@ ConVarRef suitcharger( "sk_suitcharger" );
// If map cycle file has changed or this is the first time through ...
if ( m_nMapCycleTimeStamp != nMapCycleTimeStamp )
{
// Reset map index and map cycle timestamp
m_nMapCycleTimeStamp = nMapCycleTimeStamp;
m_nMapCycleindex = 0;
// Reload
LoadMapCycleFile();
}
}
@ -1209,7 +1207,7 @@ ConVarRef suitcharger( "sk_suitcharger" );
void CMultiplayRules::DetermineMapCycleFilename( char *pszResult, int nSizeResult, bool bForceSpew )
{
static char szLastResult[ 256];
static char szLastResult[ MAX_PATH ];
const char *pszVar = mapcyclefile.GetString();
if ( *pszVar == '\0' )
@ -1223,7 +1221,7 @@ ConVarRef suitcharger( "sk_suitcharger" );
return;
}
char szRecommendedName[ 256 ];
char szRecommendedName[ MAX_PATH ];
V_sprintf_safe( szRecommendedName, "cfg/%s", pszVar );
// First, look for a mapcycle file in the cfg directory, which is preferred
@ -1274,7 +1272,12 @@ ConVarRef suitcharger( "sk_suitcharger" );
}
}
void CMultiplayRules::LoapMapCycleFileIntoVector( const char *pszMapCycleFile, CUtlVector<char *> &mapList )
void CMultiplayRules::LoadMapCycleFileIntoVector( const char *pszMapCycleFile, CUtlVector<char *> &mapList )
{
CMultiplayRules::RawLoadMapCycleFileIntoVector( pszMapCycleFile, mapList );
}
void CMultiplayRules::RawLoadMapCycleFileIntoVector( const char *pszMapCycleFile, CUtlVector<char *> &mapList )
{
CUtlBuffer buf;
if ( !filesystem->ReadFile( pszMapCycleFile, "GAME", buf ) )
@ -1293,13 +1296,6 @@ ConVarRef suitcharger( "sk_suitcharger" );
{
bIgnore = true;
}
else if ( !engine->IsMapValid( mapList[i] ) )
{
bIgnore = true;
// If the engine doesn't consider it a valid map remove it from the lists
Warning( "Invalid map '%s' included in map cycle file. Ignored.\n", mapList[i] );
}
if ( bIgnore )
{
@ -1321,6 +1317,27 @@ ConVarRef suitcharger( "sk_suitcharger" );
mapList.RemoveAll();
}
bool CMultiplayRules::IsManualMapChangeOkay( const char **pszReason )
{
if ( HLTVDirector()->IsActive() && ( HLTVDirector()->GetDelay() >= HLTV_MIN_DIRECTOR_DELAY ) )
{
if ( tv_delaymapchange.GetBool() && tv_delaymapchange_protect.GetBool() )
{
float flLastEvent = GetLastMajorEventTime();
if ( flLastEvent > -1 )
{
if ( flLastEvent > ( gpGlobals->curtime - ( HLTVDirector()->GetDelay() + 3 ) ) ) // +3 second delay to prevent instant change after a major event
{
*pszReason = "\n***WARNING*** Map change blocked. HLTV is broadcasting and has not caught up to the last major game event yet.\nYou can disable this check by setting the value of the server convar \"tv_delaymapchange_protect\" to 0.\n";
return false;
}
}
}
}
return true;
}
bool CMultiplayRules::IsMapInMapCycle( const char *pszName )
{
for ( int i = 0; i < m_MapList.Count(); i++ )
@ -1338,7 +1355,7 @@ ConVarRef suitcharger( "sk_suitcharger" );
{
char szNextMap[MAX_MAP_NAME];
if ( nextlevel.GetString() && *nextlevel.GetString() && engine->IsMapValid( nextlevel.GetString() ) )
if ( nextlevel.GetString() && *nextlevel.GetString() )
{
Q_strncpy( szNextMap, nextlevel.GetString(), sizeof( szNextMap ) );
}
@ -1353,13 +1370,19 @@ ConVarRef suitcharger( "sk_suitcharger" );
void CMultiplayRules::LoadMapCycleFile( void )
{
char mapcfile[256];
int nOldCycleIndex = m_nMapCycleindex;
m_nMapCycleindex = 0;
char mapcfile[MAX_PATH];
DetermineMapCycleFilename( mapcfile, sizeof(mapcfile), false );
FreeMapCycleFileVector( m_MapList );
const int nMapCycleTimeStamp = filesystem->GetPathTime( mapcfile, "GAME" );
m_nMapCycleTimeStamp = nMapCycleTimeStamp;
// Repopulate map list from mapcycle file
LoapMapCycleFileIntoVector( mapcfile, m_MapList );
LoadMapCycleFileIntoVector( mapcfile, m_MapList );
// Load server's mapcycle into network string table for client-side voting
if ( g_pStringTableServerMapCycle )
@ -1466,16 +1489,29 @@ ConVarRef suitcharger( "sk_suitcharger" );
}
#endif
// If the current map selection is in the list, set m_nMapCycleindex to the map that follows it.
for ( int i = 0; i < m_MapList.Count(); i++ )
// If the current map is in the same location in the new map cycle, keep that index. This gives better behavior
// when reloading a map cycle that has the current map in it multiple times.
int nOldPreviousMap = ( nOldCycleIndex == 0 ) ? ( m_MapList.Count() - 1 ) : ( nOldCycleIndex - 1 );
if ( nOldCycleIndex >= 0 && nOldCycleIndex < m_MapList.Count() &&
nOldPreviousMap >= 0 && nOldPreviousMap < m_MapList.Count() &&
V_strcmp( STRING( gpGlobals->mapname ), m_MapList[ nOldPreviousMap ] ) == 0 )
{
if ( V_strcmp( STRING( gpGlobals->mapname ), m_MapList[i] ) == 0 )
// The old index is still valid, and falls after our current map in the new cycle, use it
m_nMapCycleindex = nOldCycleIndex;
}
else
{
// Otherwise, if the current map selection is in the list, set m_nMapCycleindex to the map that follows it.
for ( int i = 0; i < m_MapList.Count(); i++ )
{
m_nMapCycleindex = i;
IncrementMapCycleIndex();
break;
if ( V_strcmp( STRING( gpGlobals->mapname ), m_MapList[i] ) == 0 )
{
m_nMapCycleindex = i;
IncrementMapCycleIndex();
break;
}
}
}
}
}
void CMultiplayRules::ChangeLevelToMap( const char *pszMap )
@ -1556,7 +1592,7 @@ ConVarRef suitcharger( "sk_suitcharger" );
Msg( "Skipping: %s\tNext map: %s\n", szSkippedMap, szNextMap );
if ( nextlevel.GetString() && *nextlevel.GetString() && engine->IsMapValid( nextlevel.GetString() ) )
if ( nextlevel.GetString() && *nextlevel.GetString() )
{
Msg( "Warning! \"nextlevel\" is set to \"%s\" and will override the next map to be played.\n", nextlevel.GetString() );
}
@ -1624,10 +1660,6 @@ ConVarRef suitcharger( "sk_suitcharger" );
pPlayer->OnAchievementEarned( nAchievementID );
}
}
else if ( FStrEq( pszCommand, "SendServerMapCycle" ) )
{
LoadMapCycleFile();
}
}
}

View File

@ -239,20 +239,26 @@ public:
virtual void GetNextLevelName( char *szNextMap, int bufsize, bool bRandom = false );
static void DetermineMapCycleFilename( char *pszResult, int nSizeResult, bool bForceSpew );
static void LoapMapCycleFileIntoVector ( const char *pszMapCycleFile, CUtlVector<char *> &mapList );
virtual void LoadMapCycleFileIntoVector ( const char *pszMapCycleFile, CUtlVector<char *> &mapList );
static void FreeMapCycleFileVector ( CUtlVector<char *> &mapList );
// LoadMapCycleFileIntoVector without the fixups inherited versions of gamerules may provide
static void RawLoadMapCycleFileIntoVector ( const char *pszMapCycleFile, CUtlVector<char *> &mapList );
bool IsMapInMapCycle( const char *pszName );
virtual bool IsManualMapChangeOkay( const char **pszReason ) OVERRIDE;
protected:
virtual bool UseSuicidePenalty() { return true; } // apply point penalty for suicide?
virtual float GetLastMajorEventTime( void ){ return -1.0f; }
public:
virtual void ChangeLevel( void );
protected:
virtual void GoToIntermission( void );
void LoadMapCycleFile( void );
virtual void LoadMapCycleFile( void );
void ChangeLevelToMap( const char *pszMap );
float m_flIntermissionEndTime;

View File

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

View File

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

View File

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

View File

@ -151,6 +151,8 @@ typedef enum
VOTE_FAILED_MAP_NOT_VALID,
VOTE_FAILED_CANNOT_KICK_FOR_TIME,
VOTE_FAILED_CANNOT_KICK_DURING_ROUND,
VOTE_FAILED_VOTE_IN_PROGRESS,
VOTE_FAILED_KICK_LIMIT_REACHED,
// TF-specific?
VOTE_FAILED_MODIFICATION_ALREADY_ACTIVE,
@ -455,6 +457,7 @@ enum {
OBS_MODE_FIXED, // view from a fixed camera position
OBS_MODE_IN_EYE, // follow a player in first person view
OBS_MODE_CHASE, // follow a player in third person view
OBS_MODE_POI, // PASSTIME point of interest - game objective, big fight, anything interesting; added in the middle of the enum due to tons of hard-coded "<ROAMING" enum compares
OBS_MODE_ROAMING, // free roaming
NUM_OBSERVER_MODES,
@ -688,6 +691,7 @@ struct FireBulletsInfo_t
m_vecDirShooting.Init( VEC_T_NAN, VEC_T_NAN, VEC_T_NAN );
#endif
m_bPrimaryAttack = true;
m_bUseServerRandomSeed = false;
}
FireBulletsInfo_t( int nShots, const Vector &vecSrc, const Vector &vecDir, const Vector &vecSpread, float flDistance, int nAmmoType, bool bPrimaryAttack = true )
@ -706,6 +710,7 @@ struct FireBulletsInfo_t
m_pAdditionalIgnoreEnt = NULL;
m_flDamageForceScale = 1.0f;
m_bPrimaryAttack = bPrimaryAttack;
m_bUseServerRandomSeed = false;
}
int m_iShots;
@ -722,6 +727,7 @@ struct FireBulletsInfo_t
CBaseEntity *m_pAttacker;
CBaseEntity *m_pAdditionalIgnoreEnt;
bool m_bPrimaryAttack;
bool m_bUseServerRandomSeed;
};
//-----------------------------------------------------------------------------

View File

@ -61,6 +61,7 @@ void CTakeDamageInfo::Init( CBaseEntity *pInflictor, CBaseEntity *pAttacker, CBa
m_iPlayerPenetrationCount = 0;
m_flDamageBonus = 0.f;
m_bForceFriendlyFire = false;
m_flDamageForForce = 0.f;
}
CTakeDamageInfo::CTakeDamageInfo()

View File

@ -64,6 +64,8 @@ public:
Vector GetDamageForce() const;
void SetDamageForce( const Vector &damageForce );
void ScaleDamageForce( float flScaleAmount );
float GetDamageForForceCalc() const;
void SetDamageForForceCalc( const float flScaleAmount );
Vector GetDamagePosition() const;
void SetDamagePosition( const Vector &damagePosition );
@ -129,6 +131,9 @@ protected:
EHANDLE m_hDamageBonusProvider; // Who gave us the ability to do extra damage?
bool m_bForceFriendlyFire; // Ideally this would be a dmg type, but we can't add more
// AlliedModders - This member only exists after the 2015 SDK update.
float m_flDamageForForce;
DECLARE_SIMPLE_DATADESC();
};
@ -289,6 +294,16 @@ inline void CTakeDamageInfo::ScaleDamageForce( float flScaleAmount )
m_vecDamageForce *= flScaleAmount;
}
inline float CTakeDamageInfo::GetDamageForForceCalc() const
{
return m_flDamageForForce;
}
inline void CTakeDamageInfo::SetDamageForForceCalc( float flDamage )
{
m_flDamageForForce = flDamage;
}
inline Vector CTakeDamageInfo::GetDamagePosition() const
{
return m_vecDamagePosition;

View File

@ -87,7 +87,7 @@ public:
virtual bool TimerMayExpire( void ) { return true; }
// A game has been won by the specified team
virtual void SetWinningTeam( int team, int iWinReason, bool bForceMapReset = true, bool bSwitchTeams = false, bool bDontAddScore = false ) { return; }
virtual void SetWinningTeam( int team, int iWinReason, bool bForceMapReset = true, bool bSwitchTeams = false, bool bDontAddScore = false, bool bFinal = false ) { return; }
virtual void SetStalemate( int iReason, bool bForceMapReset = true, bool bSwitchTeams = false ) { return; }
// Used to determine if all players should switch teams

View File

@ -44,6 +44,14 @@
#define ROUND_SETUP_2SECS "Announcer.RoundBegins2Seconds"
#define ROUND_SETUP_1SECS "Announcer.RoundBegins1Seconds"
#ifdef TF_CLIENT_DLL
#define MERASMUS_SETUP_5SECS "Merasmus.RoundBegins5Seconds"
#define MERASMUS_SETUP_4SECS "Merasmus.RoundBegins4Seconds"
#define MERASMUS_SETUP_3SECS "Merasmus.RoundBegins3Seconds"
#define MERASMUS_SETUP_2SECS "Merasmus.RoundBegins2Seconds"
#define MERASMUS_SETUP_1SECS "Merasmus.RoundBegins1Seconds"
#endif
#define ROUND_START_BELL "Ambient.Siren"
#define ROUND_TIMER_TIME_ADDED "Announcer.TimeAdded"
@ -283,6 +291,14 @@ void CTeamRoundTimer::Precache( void )
PrecacheScriptSound( ROUND_TIMER_TIME_ADDED_LOSER );
PrecacheScriptSound( ROUND_TIMER_TIME_ADDED_WINNER );
PrecacheScriptSound( ROUND_START_BELL );
#ifdef TF_CLIENT_DLL
PrecacheScriptSound( MERASMUS_SETUP_5SECS );
PrecacheScriptSound( MERASMUS_SETUP_4SECS );
PrecacheScriptSound( MERASMUS_SETUP_3SECS );
PrecacheScriptSound( MERASMUS_SETUP_2SECS );
PrecacheScriptSound( MERASMUS_SETUP_1SECS );
#endif // TF_CLIENT_DLL
#endif // TF_DLL || TF_CLIENT_DLL
}
@ -575,7 +591,16 @@ const char *CTeamRoundTimer::GetTimeWarningSound( int nWarning )
case RT_WARNING_5SECS:
if ( m_nState == RT_STATE_SETUP )
{
pszRetVal = ROUND_SETUP_5SECS;
#ifdef TF_CLIENT_DLL
if ( TFGameRules() && TFGameRules()->IsHalloweenScenario( CTFGameRules::HALLOWEEN_SCENARIO_DOOMSDAY ) )
{
pszRetVal = MERASMUS_SETUP_5SECS;
}
else
#endif
{
pszRetVal = ROUND_SETUP_5SECS;
}
}
else
{
@ -585,7 +610,16 @@ const char *CTeamRoundTimer::GetTimeWarningSound( int nWarning )
case RT_WARNING_4SECS:
if ( m_nState == RT_STATE_SETUP )
{
pszRetVal = ROUND_SETUP_4SECS;
#ifdef TF_CLIENT_DLL
if ( TFGameRules() && TFGameRules()->IsHalloweenScenario( CTFGameRules::HALLOWEEN_SCENARIO_DOOMSDAY ) )
{
pszRetVal = MERASMUS_SETUP_4SECS;
}
else
#endif
{
pszRetVal = ROUND_SETUP_4SECS;
}
}
else
{
@ -595,7 +629,16 @@ const char *CTeamRoundTimer::GetTimeWarningSound( int nWarning )
case RT_WARNING_3SECS:
if ( m_nState == RT_STATE_SETUP )
{
pszRetVal = ROUND_SETUP_3SECS;
#ifdef TF_CLIENT_DLL
if ( TFGameRules() && TFGameRules()->IsHalloweenScenario( CTFGameRules::HALLOWEEN_SCENARIO_DOOMSDAY ) )
{
pszRetVal = MERASMUS_SETUP_3SECS;
}
else
#endif
{
pszRetVal = ROUND_SETUP_3SECS;
}
}
else
{
@ -605,7 +648,16 @@ const char *CTeamRoundTimer::GetTimeWarningSound( int nWarning )
case RT_WARNING_2SECS:
if ( m_nState == RT_STATE_SETUP )
{
pszRetVal = ROUND_SETUP_2SECS;
#ifdef TF_CLIENT_DLL
if ( TFGameRules() && TFGameRules()->IsHalloweenScenario( CTFGameRules::HALLOWEEN_SCENARIO_DOOMSDAY ) )
{
pszRetVal = MERASMUS_SETUP_2SECS;
}
else
#endif
{
pszRetVal = ROUND_SETUP_2SECS;
}
}
else
{
@ -615,7 +667,16 @@ const char *CTeamRoundTimer::GetTimeWarningSound( int nWarning )
case RT_WARNING_1SECS:
if ( m_nState == RT_STATE_SETUP )
{
pszRetVal = ROUND_SETUP_1SECS;
#ifdef TF_CLIENT_DLL
if ( TFGameRules() && TFGameRules()->IsHalloweenScenario( CTFGameRules::HALLOWEEN_SCENARIO_DOOMSDAY ) )
{
pszRetVal = MERASMUS_SETUP_1SECS;
}
else
#endif
{
pszRetVal = ROUND_SETUP_1SECS;
}
}
else
{

View File

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

View File

@ -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();
GoToIntermission();
}
SendTeamScoresEvent();
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() )
// 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 );
TFObjectiveResource()->SetMannVsMachineBetweenWaves( true );
m_bAllowBetweenRounds = false;
if ( TFGameRules()->IsMannVsMachineMode() )
{
TFObjectiveResource()->SetMannVsMachineBetweenWaves( true );
}
}
#ifdef STAGING_ONLY
else if ( TFGameRules() && TFGameRules()->IsRatedTournamentMode() )
{
State_Transition( GR_STATE_BETWEEN_RNDS );
}
#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()->StartRatedTournamentMatch();
TFGameRules()->StartCompetitiveMatch();
return;
}
else if ( mp_tournament.GetBool() )
{
// 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() )
{
if ( TFGameRules()->IsMannVsMachineMode() )
{
bTeamReady = AreDefendingPlayersReady();
if ( bTeamReady )
{
nTime = 10;
}
}
else
{
bTeamReady = m_bTeamReady[TF_TEAM_BLUE] && m_bTeamReady[TF_TEAM_RED];
}
}
bProcessReadyRestart &= TFGameRules() && !TFGameRules()->UsePlayerReadyStatusMode();
#endif // TF_DLL
if ( bTeamReady )
// check ready restart
if ( bProcessReadyRestart )
{
bool bTeamNotReady = false;
for ( int i = LAST_SHARED_TEAM + 1; i < GetNumberOfTeams(); i++ )
{
//State_Transition( GR_STATE_RESTART );
mp_restartgame.SetValue( nTime );
if ( !m_bTeamReady[i] )
{
bTeamNotReady = true;
break;
}
}
if ( !bTeamNotReady )
{
mp_restartgame.SetValue( 5 );
m_bAwaitingReadyRestart = false;
ShouldResetScores( true, true );
@ -1596,31 +1628,31 @@ void CTeamplayRoundBasedRules::CheckReadyRestart( void )
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
bool CTeamplayRoundBasedRules::AreDefendingPlayersReady()
bool CTeamplayRoundBasedRules::AreLobbyPlayersOnTeamReady( int iTeam )
{
// Get list of defenders
CUtlVector<LobbyPlayerInfo_t> vecMvMDefenders;
GetMvMPotentialDefendersLobbyPlayerInfo( vecMvMDefenders );
if ( !TFGameRules() )
return false;
if ( TFGameRules()->IsMannVsMachineMode() && iTeam == TF_TEAM_PVE_INVADERS )
return true;
// Scan all the players, and bail as soon as we find one person
// worth waiting for
bool bAtLeastOnePersonReady = false;
for ( int i = 0; i < vecMvMDefenders.Count(); i++ )
CUtlVector<LobbyPlayerInfo_t> vecLobbyPlayers;
GetPotentialPlayersLobbyPlayerInfo( vecLobbyPlayers );
for ( int i = 0; i < vecLobbyPlayers.Count(); i++ )
{
// 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 )
const LobbyPlayerInfo_t &p = vecLobbyPlayers[i];
// Make sure all lobby players are connected
if ( !AreLobbyPlayersConnected() )
{
// They're still getting set up. We'll wait for them,
// but only if they are in the lobby
if ( p.m_bInLobby )
return false;
return false;
}
else if ( p.m_iTeam == TF_TEAM_PVE_DEFENDERS )
// All are connected, make sure their team is ready
else if ( p.m_iTeam == iTeam )
{
// If he isn't ready, then we aren't ready
if ( !m_bPlayerReady[ p.m_nEntNum ] )
return false;
@ -1629,8 +1661,12 @@ bool CTeamplayRoundBasedRules::AreDefendingPlayersReady()
}
else
{
// And you may ask yourself, "How did I get here?"
Assert( p.m_iTeam == TF_TEAM_PVE_DEFENDERS );
// In MvM, only the red team should pass through here
if ( TFGameRules()->IsMannVsMachineMode() )
{
// And you may ask yourself, "How did I get here?"
Assert( p.m_iTeam == iTeam );
}
}
}
@ -1639,6 +1675,32 @@ bool CTeamplayRoundBasedRules::AreDefendingPlayersReady()
return bAtLeastOnePersonReady;
}
//-----------------------------------------------------------------------------
// Purpose: Is everyone in the lobby connected to the server?
//-----------------------------------------------------------------------------
bool CTeamplayRoundBasedRules::AreLobbyPlayersConnected( void )
{
CUtlVector<LobbyPlayerInfo_t> vecLobbyPlayers;
GetPotentialPlayersLobbyPlayerInfo( vecLobbyPlayers );
// If you're calling this, you should have lobby members
Assert( vecLobbyPlayers.Count() );
for ( int i = 0; i < vecLobbyPlayers.Count(); i++ )
{
const LobbyPlayerInfo_t &pLobbyPlayer = vecLobbyPlayers[i];
if ( !pLobbyPlayer.m_bConnected ||
pLobbyPlayer.m_nEntNum <= 0 ||
pLobbyPlayer.m_nEntNum >= MAX_PLAYERS ||
( TFGameRules() && TFGameRules()->IsMannVsMachineMode() && pLobbyPlayer.m_iTeam == TEAM_UNASSIGNED ) )
{
if ( pLobbyPlayer.m_bInLobby )
return false;
}
}
return true;
}
#endif // #if defined(TF_CLIENT_DLL) || defined(TF_DLL)
//-----------------------------------------------------------------------------
@ -1657,6 +1719,15 @@ void CTeamplayRoundBasedRules::State_Think_RND_RUNNING( void )
}
#endif
#ifdef TF_DLL
// Mass time-out? Clean everything up.
if ( TFGameRules() && TFGameRules()->IsCompetitiveMode() )
{
TFGameRules()->EndCompetitiveMatch();
return;
}
#endif // TF_DLL
State_Transition( GR_STATE_PREGAME );
return;
}
@ -1672,9 +1743,8 @@ void CTeamplayRoundBasedRules::State_Think_RND_RUNNING( void )
// check round restart
CheckReadyRestart();
// See if we're coming up to the server timelimit, in which case force a stalemate immediately.
if ( State_Get() == GR_STATE_RND_RUNNING && mp_timelimit.GetInt() > 0 && IsInPreMatch() == false && GetTimeLeft() <= 0 )
if ( mp_timelimit.GetInt() > 0 && IsInPreMatch() == false && GetTimeLeft() <= 0 )
{
if ( m_bAllowStalemateAtTimelimit || ( mp_match_end_at_timelimit.GetBool() && !IsValveMap() ) )
{
@ -1730,9 +1800,7 @@ void CTeamplayRoundBasedRules::State_Think_RND_RUNNING( void )
//-----------------------------------------------------------------------------
void CTeamplayRoundBasedRules::State_Enter_TEAM_WIN( void )
{
float flTime = GetBonusRoundTime();
m_flStateTransitionTime = gpGlobals->curtime + flTime;
m_flStateTransitionTime = gpGlobals->curtime + GetBonusRoundTime();
// if we're forcing the map to reset it must be the end of a "full" round not a mini-round
if ( m_bForceMapReset )
@ -1744,18 +1812,14 @@ void CTeamplayRoundBasedRules::State_Enter_TEAM_WIN( void )
SendWinPanelInfo();
#ifdef STAGING_ONLY
#ifdef TF_DLL
if ( TFGameRules() && TFGameRules()->IsRatedTournamentMode() )
// Do this now, so players don't leave before the usual CheckWinLimit() call happens
bool bDone = ( CheckTimeLimit( false ) || CheckWinLimit( false ) || CheckMaxRounds( false ) || CheckNextLevelCvar( false ) );
if ( TFGameRules() && TFGameRules()->IsCompetitiveMode() && bDone )
{
// Do this now, so players don't leave before the usual CheckWinLimit() call happens
if ( CheckWinLimit() )
{
TFGameRules()->SkillRating_CalculateAdjustmentForTeams( m_iWinningTeam );
}
TFGameRules()->StopCompetitiveMatch( CMsgGC_Match_Result_Status_MATCH_SUCCEEDED );
}
#endif // TF_DLL
#endif // STAGING_ONLY
}
//-----------------------------------------------------------------------------
@ -1773,10 +1837,10 @@ void CTeamplayRoundBasedRules::State_Think_TEAM_WIN( void )
}
#endif // TF_DLL
bool bDone = !(!CheckTimeLimit() && !CheckWinLimit() && !CheckMaxRounds() && !CheckNextLevelCvar());
bool bDone = ( CheckTimeLimit() || CheckWinLimit() || CheckMaxRounds() || CheckNextLevelCvar() );
// check the win limit, max rounds, time limit and nextlevel cvar before starting the next round
if ( bDone == false )
if ( !bDone )
{
PreviousRoundEnd();
@ -1797,7 +1861,7 @@ void CTeamplayRoundBasedRules::State_Think_TEAM_WIN( void )
State_Transition( GR_STATE_PREROUND );
}
}
else if ( IsInTournamentMode() == true )
else if ( IsInTournamentMode() )
{
for ( int i = 1; i <= MAX_PLAYERS; i++ )
{
@ -1811,7 +1875,7 @@ void CTeamplayRoundBasedRules::State_Think_TEAM_WIN( void )
RestartTournament();
if ( IsInArenaMode() == true )
if ( IsInArenaMode() )
{
#if defined( REPLAY_ENABLED )
if ( g_pReplay )
@ -1823,33 +1887,43 @@ void CTeamplayRoundBasedRules::State_Think_TEAM_WIN( void )
State_Transition( GR_STATE_PREROUND );
}
else
{
#ifdef TF_DLL
if ( TFGameRules() && TFGameRules()->IsMannVsMachineMode() )
else if ( TFGameRules() && TFGameRules()->IsMannVsMachineMode() && g_pPopulationManager )
{
// one of the convars mp_timelimit, mp_winlimit, mp_maxrounds, or nextlevel has been triggered
for ( int i = 1; i <= MAX_PLAYERS; i++ )
{
// one of the convars mp_timelimit, mp_winlimit, mp_maxrounds, or nextlevel has been triggered
if ( g_pPopulationManager )
{
for ( int i = 1; i <= MAX_PLAYERS; i++ )
{
CBasePlayer *pPlayer = UTIL_PlayerByIndex( i );
CBasePlayer *pPlayer = UTIL_PlayerByIndex( i );
if ( !pPlayer )
continue;
if ( !pPlayer )
continue;
pPlayer->AddFlag( FL_FROZEN );
pPlayer->ShowViewPortPanel( PANEL_SCOREBOARD );
}
g_fGameOver = true;
g_pPopulationManager->SetMapRestartTime( gpGlobals->curtime + 10.0f );
State_Enter( GR_STATE_GAME_OVER );
return;
}
pPlayer->AddFlag( FL_FROZEN );
}
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;
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<LobbyPlayerInfo_t> &vecMvMDefenders, bool bIncludeBots /*= false*/ )
void CTeamplayRoundBasedRules::GetPotentialPlayersLobbyPlayerInfo( CUtlVector<LobbyPlayerInfo_t> &vecLobbyPlayers, bool bIncludeBots /*= false*/ )
{
GetAllPlayersLobbyInfo( vecMvMDefenders, bIncludeBots );
GetAllPlayersLobbyInfo( vecLobbyPlayers, bIncludeBots );
// Now scan through and remove the spectators
for (int i = vecMvMDefenders.Count() - 1 ; i >= 0 ; --i )
for ( int i = vecLobbyPlayers.Count() - 1; i >= 0; --i )
{
switch ( vecMvMDefenders[i].m_iTeam )
switch ( vecLobbyPlayers[i].m_iTeam )
{
case TEAM_UNASSIGNED:
case TF_TEAM_PVE_DEFENDERS:
case TF_TEAM_RED:
break;
case TF_TEAM_BLUE:
if ( TFGameRules() && TFGameRules()->IsMannVsMachineMode() )
vecLobbyPlayers.FastRemove( i );
break;
case TEAM_SPECTATOR:
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 );
break;
AssertMsg1( false, "Bogus team %d", vecLobbyPlayers[i].m_iTeam );
}
}
}

View File

@ -12,6 +12,7 @@
#include "teamplay_gamerules.h"
#include "teamplay_round_timer.h"
#include "GameEventListener.h"
#ifdef GAME_DLL
#include "team_control_point.h"
@ -162,7 +163,7 @@ public:
//-----------------------------------------------------------------------------
// Purpose: Teamplay game rules that manage a round based structure for you
//-----------------------------------------------------------------------------
class CTeamplayRoundBasedRules : public CTeamplayRules
class CTeamplayRoundBasedRules : public CTeamplayRules, public CGameEventListener
{
DECLARE_CLASS( CTeamplayRoundBasedRules, CTeamplayRules );
public:
@ -248,7 +249,7 @@ public:
void SetMultipleTrains( bool bMultipleTrains ){ m_bMultipleTrains = bMultipleTrains; }
bool HasMultipleTrains( void ){ return m_bMultipleTrains; }
virtual int GetBonusRoundTime( void );
virtual int GetBonusRoundTime( bool bFinal = false );
#if defined(TF_CLIENT_DLL) || defined(TF_DLL)
@ -258,10 +259,15 @@ public:
// Get list of players who are on the defending team now, or are likely
// to end up on the defending team (not yet connected or assigned a team)
void GetMvMPotentialDefendersLobbyPlayerInfo( CUtlVector<LobbyPlayerInfo_t> &vecMvmDefenders, bool bIncludeBots = false );
void GetPotentialPlayersLobbyPlayerInfo( CUtlVector<LobbyPlayerInfo_t> &vecLobbyPlayers, bool bIncludeBots = false );
#endif
void SetAllowBetweenRounds( bool bValue ) { m_bAllowBetweenRounds = bValue; }
public: // IGameEventListener Interface
virtual void FireGameEvent( IGameEvent * event );
//----------------------------------------------------------------------------------
// Server specific
#ifdef GAME_DLL
@ -309,7 +315,7 @@ public:
virtual bool ShouldScorePerRound( void ){ return true; }
bool CheckNextLevelCvar( void );
bool CheckNextLevelCvar( bool bAllowEnd = true );
virtual bool TimerMayExpire( void );
@ -332,7 +338,7 @@ public:
bool IsPreviouslyPlayedRound ( string_t strName );
string_t GetLastPlayedRound( void );
virtual void SetWinningTeam( int team, int iWinReason, bool bForceMapReset = true, bool bSwitchTeams = false, bool bDontAddScore = false );
virtual void SetWinningTeam( int team, int iWinReason, bool bForceMapReset = true, bool bSwitchTeams = false, bool bDontAddScore = false, bool bFinal = false ) OVERRIDE;
virtual void SetStalemate( int iReason, bool bForceMapReset = true, bool bSwitchTeams = false );
virtual void SetRoundOverlayDetails( void ){ return; }
@ -365,10 +371,11 @@ public:
{
m_bPlayerReady.Set( iIndex, bState );
}
void ResetPlayerAndTeamReadyState( void );
virtual void PlayTrainCaptureAlert( CTeamControlPoint *pPoint, bool bFinalPointInMap ){ return; }
virtual void PlaySpecialCapSounds( int iCappingTeam ){ return; }
virtual void PlaySpecialCapSounds( int iCappingTeam, CTeamControlPoint *pPoint ){ return; }
bool PlayThrottledAlert( int iTeam, const char *sound, float fDelayBeforeNext );
@ -393,14 +400,15 @@ protected:
void CheckWaitingForPlayers( void );
virtual bool AllowWaitingForPlayers( void ) { return true; }
void CheckRestartRound( void );
bool CheckTimeLimit( void );
bool CheckTimeLimit( bool bAllowEnd = true );
int GetTimeLeft( void );
virtual bool CheckWinLimit( void );
bool CheckMaxRounds( void );
virtual bool CheckWinLimit( bool bAllowEnd = true );
bool CheckMaxRounds( bool bAllowEnd = true );
void CheckReadyRestart( void );
#if defined(TF_CLIENT_DLL) || defined(TF_DLL)
bool AreDefendingPlayersReady();
bool AreLobbyPlayersOnTeamReady( int iTeam );
bool AreLobbyPlayersConnected( void );
#endif
virtual bool CanChangelevelBecauseOfTimeLimit( void ) { return true; }
@ -479,6 +487,8 @@ protected:
bool MapHasActiveTimer( void );
void CreateTimeLimitTimer( void );
virtual float GetLastMajorEventTime( void ) OVERRIDE { return m_flLastTeamWin; }
protected:
CGameRulesRoundStateInfo *m_pCurStateInfo; // Per-state data
float m_flStateTransitionTime; // Timer for round states
@ -521,10 +531,13 @@ protected:
gamerules_roundstate_t m_prevState;
bool m_bPlayerReadyBefore[MAX_PLAYERS+1]; // Test to see if a player has hit ready before
float m_flLastTeamWin;
private:
CUtlMap < int, int > m_GameTeams; // Team index, Score
#endif
// End server specific
//----------------------------------------------------------------------------------
@ -582,6 +595,9 @@ private:
int m_nAutoBalanceQueuePlayerIndex;
int m_nAutoBalanceQueuePlayerScore;
protected:
bool m_bAllowBetweenRounds;
public:
float m_flStopWatchTotalTime;

View File

@ -0,0 +1,33 @@
//====== Copyright <20> 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

View File

@ -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,10 @@ public:
int weaponsubtype;
int random_seed; // For shared random functions
#ifdef GAME_DLL
// AlliedModders - This member only exists after the 2015 SDK update.
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

View File

@ -441,8 +441,8 @@ inline float DistanceToRay( const Vector &pos, const Vector &rayStart, const Vec
public: \
interfaceName( bool bAutoAdd = true ); \
virtual ~interfaceName(); \
static void Add( interfaceName *pElement ) { m_##interfaceName##AutoList.AddToTail( pElement ); } \
static void Remove( interfaceName *pElement ) { m_##interfaceName##AutoList.FindAndFastRemove( pElement ); } \
static void AddToAutoList( interfaceName *pElement ) { m_##interfaceName##AutoList.AddToTail( pElement ); } \
static void RemoveFromAutoList( interfaceName *pElement ) { m_##interfaceName##AutoList.FindAndFastRemove( pElement ); } \
static const CUtlVector< interfaceName* >& AutoList( void ) { return m_##interfaceName##AutoList; } \
private: \
static CUtlVector< interfaceName* > m_##interfaceName##AutoList; \
@ -456,14 +456,28 @@ inline float DistanceToRay( const Vector &pos, const Vector &rayStart, const Vec
{ \
if ( bAutoAdd ) \
{ \
Add( this ); \
AddToAutoList( this ); \
} \
} \
interfaceName::~interfaceName() \
{ \
Remove( this ); \
RemoveFromAutoList( this ); \
}
//--------------------------------------------------------------------------------------------------------------
// This would do the same thing without requiring casts all over the place. Yes, it's a template, but
// DECLARE_AUTO_LIST requires a CUtlVector<T> anyway. TODO ask about replacing the macros with this.
//template<class T>
//class AutoList {
//public:
// typedef CUtlVector<T*> AutoListType;
// static AutoListType& All() { return m_autolist; }
//protected:
// AutoList() { m_autolist.AddToTail(static_cast<T*>(this)); }
// virtual ~AutoList() { m_autolist.FindAndFastRemove(static_cast<T*>(this)); }
//private:
// static AutoListType m_autolist;
//};
//--------------------------------------------------------------------------------------------------------------
/**
@ -579,7 +593,15 @@ public:
private:
float m_duration;
float m_timestamp;
float Now( void ) const; // work-around since client header doesn't like inlined gpGlobals->curtime
virtual float Now( void ) const; // work-around since client header doesn't like inlined gpGlobals->curtime
};
class RealTimeCountdownTimer : public CountdownTimer
{
virtual float Now( void ) const OVERRIDE
{
return Plat_FloatTime();
}
};
char* ReadAndAllocStringValue( KeyValues *pSub, const char *pName, const char *pFilename = NULL );

View File

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

View File

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