You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1077 lines
32 KiB
1077 lines
32 KiB
//========= Copyright Valve Corporation, All rights reserved. ============// |
|
// |
|
// Purpose: |
|
// |
|
//===========================================================================// |
|
|
|
#include "cbase.h" |
|
#include "team_control_point.h" |
|
#include "player.h" |
|
#include "teamplay_gamerules.h" |
|
#include "teamplayroundbased_gamerules.h" |
|
#include "team.h" |
|
#include "team_control_point_master.h" |
|
#include "mp_shareddefs.h" |
|
#include "engine/IEngineSound.h" |
|
#include "soundenvelope.h" |
|
|
|
#ifdef TF_DLL |
|
#include "tf_shareddefs.h" |
|
#endif |
|
|
|
#define CONTROL_POINT_UNLOCK_THINK "UnlockThink" |
|
|
|
BEGIN_DATADESC(CTeamControlPoint) |
|
DEFINE_KEYFIELD( m_iszPrintName, FIELD_STRING, "point_printname" ), |
|
DEFINE_KEYFIELD( m_iCPGroup, FIELD_INTEGER, "point_group" ), |
|
DEFINE_KEYFIELD( m_iDefaultOwner, FIELD_INTEGER, "point_default_owner" ), |
|
DEFINE_KEYFIELD( m_iPointIndex, FIELD_INTEGER, "point_index" ), |
|
DEFINE_KEYFIELD( m_iWarnOnCap, FIELD_INTEGER, "point_warn_on_cap" ), |
|
DEFINE_KEYFIELD( m_iszWarnSound, FIELD_STRING, "point_warn_sound" ), |
|
|
|
DEFINE_KEYFIELD( m_iszCaptureStartSound, FIELD_STRING, "point_capture_start_sound" ), |
|
DEFINE_KEYFIELD( m_iszCaptureEndSound, FIELD_STRING, "point_capture_end_sound" ), |
|
DEFINE_KEYFIELD( m_iszCaptureInProgress, FIELD_STRING, "point_capture_progress_sound" ), |
|
DEFINE_KEYFIELD( m_iszCaptureInterrupted, FIELD_STRING, "point_capture_interrupted_sound" ), |
|
DEFINE_KEYFIELD( m_bRandomOwnerOnRestart, FIELD_BOOLEAN, "random_owner_on_restart" ), |
|
DEFINE_KEYFIELD( m_bLocked, FIELD_BOOLEAN, "point_start_locked" ), |
|
|
|
DEFINE_FUNCTION( UnlockThink ), |
|
|
|
// DEFINE_FIELD( m_iTeam, FIELD_INTEGER ), |
|
// DEFINE_FIELD( m_iIndex, FIELD_INTEGER ), |
|
// DEFINE_FIELD( m_TeamData, CUtlVector < perteamdata_t > ), |
|
// DEFINE_FIELD( m_bPointVisible, FIELD_INTEGER ), |
|
// DEFINE_FIELD( m_bActive, FIELD_BOOLEAN ), |
|
// DEFINE_FIELD( m_iszName, FIELD_STRING ), |
|
// DEFINE_FIELD( m_bStartDisabled, FIELD_BOOLEAN ), |
|
// DEFINE_FIELD( m_flLastContestedAt, FIELD_FLOAT ), |
|
// DEFINE_FIELD( m_pCaptureInProgressSound, CSoundPatch ), |
|
|
|
DEFINE_INPUTFUNC( FIELD_INTEGER, "SetOwner", InputSetOwner ), |
|
DEFINE_INPUTFUNC( FIELD_VOID, "ShowModel", InputShowModel ), |
|
DEFINE_INPUTFUNC( FIELD_VOID, "HideModel", InputHideModel ), |
|
DEFINE_INPUTFUNC( FIELD_VOID, "RoundActivate", InputRoundActivate ), |
|
DEFINE_INPUTFUNC( FIELD_INTEGER, "SetLocked", InputSetLocked ), |
|
DEFINE_INPUTFUNC( FIELD_INTEGER, "SetUnlockTime", InputSetUnlockTime ), |
|
|
|
DEFINE_OUTPUT( m_OnCapTeam1, "OnCapTeam1" ), // these are fired whenever the point changes modes |
|
DEFINE_OUTPUT( m_OnCapTeam2, "OnCapTeam2" ), |
|
DEFINE_OUTPUT( m_OnCapReset, "OnCapReset" ), |
|
|
|
DEFINE_OUTPUT( m_OnOwnerChangedToTeam1, "OnOwnerChangedToTeam1" ), // these are fired when a team does the work to change the owner |
|
DEFINE_OUTPUT( m_OnOwnerChangedToTeam2, "OnOwnerChangedToTeam2" ), |
|
|
|
DEFINE_OUTPUT( m_OnRoundStartOwnedByTeam1, "OnRoundStartOwnedByTeam1" ), // these are fired when a round is starting |
|
DEFINE_OUTPUT( m_OnRoundStartOwnedByTeam2, "OnRoundStartOwnedByTeam2" ), |
|
|
|
DEFINE_OUTPUT( m_OnUnlocked, "OnUnlocked" ), |
|
|
|
DEFINE_THINKFUNC( AnimThink ), |
|
END_DATADESC(); |
|
|
|
LINK_ENTITY_TO_CLASS( team_control_point, CTeamControlPoint ); |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
CTeamControlPoint::CTeamControlPoint() |
|
{ |
|
m_TeamData.SetSize( GetNumberOfTeams() ); |
|
m_pCaptureInProgressSound = NULL; |
|
|
|
m_bLocked = false; |
|
m_flUnlockTime = -1; |
|
|
|
#ifdef TF_DLL |
|
UseClientSideAnimation(); |
|
#endif |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
void CTeamControlPoint::Spawn( void ) |
|
{ |
|
// Validate our default team |
|
if ( m_iDefaultOwner < 0 || m_iDefaultOwner >= GetNumberOfTeams() ) |
|
{ |
|
Warning( "team_control_point '%s' has bad point_default_owner.\n", GetDebugName() ); |
|
m_iDefaultOwner = TEAM_UNASSIGNED; |
|
} |
|
|
|
#ifdef TF_DLL |
|
if ( m_iszCaptureStartSound == NULL_STRING ) |
|
{ |
|
m_iszCaptureStartSound = AllocPooledString( "Hologram.Start" ); |
|
} |
|
if ( m_iszCaptureEndSound == NULL_STRING ) |
|
{ |
|
m_iszCaptureEndSound = AllocPooledString( "Hologram.Stop" ); |
|
} |
|
if ( m_iszCaptureInProgress == NULL_STRING ) |
|
{ |
|
m_iszCaptureInProgress = AllocPooledString( "Hologram.Move" ); |
|
} |
|
if ( m_iszCaptureInterrupted == NULL_STRING ) |
|
{ |
|
m_iszCaptureInterrupted = AllocPooledString( "Hologram.Interrupted" ); |
|
} |
|
#endif |
|
|
|
Precache(); |
|
|
|
InternalSetOwner( m_iDefaultOwner, false ); //init the owner of this point |
|
TeamplayRoundBasedRules()->RecalculateControlPointState(); |
|
|
|
SetActive( !m_bStartDisabled ); |
|
|
|
BaseClass::Spawn(); |
|
|
|
SetPlaybackRate( 1.0 ); |
|
SetThink( &CTeamControlPoint::AnimThink ); |
|
SetNextThink( gpGlobals->curtime + 0.1f ); |
|
|
|
if ( FBitSet( m_spawnflags, SF_CAP_POINT_HIDE_MODEL ) ) |
|
{ |
|
AddEffects( EF_NODRAW ); |
|
} |
|
|
|
if ( FBitSet( m_spawnflags, SF_CAP_POINT_HIDE_SHADOW ) ) |
|
{ |
|
AddEffects( EF_NOSHADOW ); |
|
} |
|
|
|
m_flLastContestedAt = -1; |
|
|
|
m_pCaptureInProgressSound = NULL; |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
bool CTeamControlPoint::KeyValue( const char *szKeyName, const char *szValue ) |
|
{ |
|
if ( !Q_strncmp( szKeyName, "team_capsound_", 14 ) ) |
|
{ |
|
int iTeam = atoi(szKeyName+14); |
|
Assert( iTeam >= 0 && iTeam < m_TeamData.Count() ); |
|
|
|
m_TeamData[iTeam].iszCapSound = AllocPooledString(szValue); |
|
} |
|
else if ( !Q_strncmp( szKeyName, "team_model_", 11 ) ) |
|
{ |
|
int iTeam = atoi(szKeyName+11); |
|
Assert( iTeam >= 0 && iTeam < m_TeamData.Count() ); |
|
|
|
m_TeamData[iTeam].iszModel = AllocPooledString(szValue); |
|
} |
|
else if ( !Q_strncmp( szKeyName, "team_timedpoints_", 17 ) ) |
|
{ |
|
int iTeam = atoi(szKeyName+17); |
|
Assert( iTeam >= 0 && iTeam < m_TeamData.Count() ); |
|
|
|
m_TeamData[iTeam].iTimedPoints = atoi(szValue); |
|
} |
|
else if ( !Q_strncmp( szKeyName, "team_bodygroup_", 15 ) ) |
|
{ |
|
int iTeam = atoi(szKeyName+15); |
|
Assert( iTeam >= 0 && iTeam < m_TeamData.Count() ); |
|
|
|
m_TeamData[iTeam].iModelBodygroup = atoi(szValue); |
|
} |
|
else if ( !Q_strncmp( szKeyName, "team_icon_", 10 ) ) |
|
{ |
|
int iTeam = atoi(szKeyName+10); |
|
Assert( iTeam >= 0 && iTeam < m_TeamData.Count() ); |
|
|
|
m_TeamData[iTeam].iszIcon = AllocPooledString(szValue); |
|
} |
|
else if ( !Q_strncmp( szKeyName, "team_overlay_", 13 ) ) |
|
{ |
|
int iTeam = atoi(szKeyName+13); |
|
Assert( iTeam >= 0 && iTeam < m_TeamData.Count() ); |
|
|
|
m_TeamData[iTeam].iszOverlay = AllocPooledString(szValue); |
|
} |
|
else if ( !Q_strncmp( szKeyName, "team_previouspoint_", 19 ) ) |
|
{ |
|
int iTeam; |
|
int iPoint = 0; |
|
sscanf( szKeyName+19, "%d_%d", &iTeam, &iPoint ); |
|
Assert( iTeam >= 0 && iTeam < m_TeamData.Count() ); |
|
Assert( iPoint >= 0 && iPoint < MAX_PREVIOUS_POINTS ); |
|
m_TeamData[iTeam].iszPreviousPoint[iPoint] = AllocPooledString(szValue); |
|
} |
|
else |
|
{ |
|
return BaseClass::KeyValue( szKeyName, szValue ); |
|
} |
|
|
|
return true; |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
void CTeamControlPoint::Precache( void ) |
|
{ |
|
for ( int i = 0; i < m_TeamData.Count(); i++ ) |
|
{ |
|
// Skip over spectator |
|
if ( i == TEAM_SPECTATOR ) |
|
continue; |
|
|
|
if ( m_TeamData[i].iszCapSound != NULL_STRING ) |
|
{ |
|
PrecacheScriptSound( STRING(m_TeamData[i].iszCapSound) ); |
|
} |
|
|
|
if ( m_TeamData[i].iszModel != NULL_STRING ) |
|
{ |
|
PrecacheModel( STRING(m_TeamData[i].iszModel) ); |
|
} |
|
|
|
if ( m_TeamData[i].iszIcon != NULL_STRING ) |
|
{ |
|
PrecacheMaterial( STRING( m_TeamData[i].iszIcon ) ); |
|
m_TeamData[i].iIcon = GetMaterialIndex( STRING( m_TeamData[i].iszIcon ) ); |
|
Assert( m_TeamData[i].iIcon != 0 ); |
|
} |
|
|
|
if ( !m_TeamData[i].iIcon ) |
|
{ |
|
Warning( "Invalid hud icon material for team %d in control point '%s' ( point index %d )\n", i, GetDebugName(), GetPointIndex() ); |
|
} |
|
|
|
if ( m_TeamData[i].iszOverlay != NULL_STRING ) |
|
{ |
|
PrecacheMaterial( STRING( m_TeamData[i].iszOverlay ) ); |
|
m_TeamData[i].iOverlay = GetMaterialIndex( STRING( m_TeamData[i].iszOverlay ) ); |
|
Assert( m_TeamData[i].iOverlay != 0 ); |
|
|
|
if ( !m_TeamData[i].iOverlay ) |
|
{ |
|
Warning( "Invalid hud overlay material for team %d in control point '%s' ( point index %d )\n", i, GetDebugName(), GetPointIndex() ); |
|
} |
|
} |
|
} |
|
|
|
PrecacheScriptSound( STRING( m_iszCaptureStartSound ) ); |
|
PrecacheScriptSound( STRING( m_iszCaptureEndSound ) ); |
|
PrecacheScriptSound( STRING( m_iszCaptureInProgress ) ); |
|
PrecacheScriptSound( STRING( m_iszCaptureInterrupted ) ); |
|
|
|
if ( m_iszWarnSound != NULL_STRING ) |
|
{ |
|
PrecacheScriptSound( STRING( m_iszWarnSound ) ); |
|
} |
|
|
|
#ifdef TF_DLL |
|
PrecacheScriptSound( "Announcer.ControlPointContested" ); |
|
#endif |
|
} |
|
|
|
//------------------------------------------------------------------------------ |
|
// Purpose: |
|
//------------------------------------------------------------------------------ |
|
void CTeamControlPoint::AnimThink( void ) |
|
{ |
|
StudioFrameAdvance(); |
|
DispatchAnimEvents(this); |
|
SetNextThink( gpGlobals->curtime + 0.1f ); |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: Used by ControlMaster to this point to its default owner |
|
//----------------------------------------------------------------------------- |
|
void CTeamControlPoint::InputReset( inputdata_t &input ) |
|
{ |
|
m_flLastContestedAt = -1; |
|
InternalSetOwner( m_iDefaultOwner, false ); |
|
ObjectiveResource()->SetOwningTeam( GetPointIndex(), m_iTeam ); |
|
TeamplayRoundBasedRules()->RecalculateControlPointState(); |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
void CTeamControlPoint::HandleScoring( int iTeam ) |
|
{ |
|
if ( TeamplayRoundBasedRules() && !TeamplayRoundBasedRules()->ShouldScorePerRound() ) |
|
{ |
|
GetGlobalTeam( iTeam )->AddScore( 1 ); |
|
TeamplayRoundBasedRules()->HandleTeamScoreModify( iTeam, 1 ); |
|
|
|
CTeamControlPointMaster *pMaster = g_hControlPointMasters.Count() ? g_hControlPointMasters[0] : NULL; |
|
if ( pMaster && !pMaster->WouldNewCPOwnerWinGame( this, iTeam ) ) |
|
{ |
|
#ifdef TF_DLL |
|
if ( TeamplayRoundBasedRules()->GetGameType() == TF_GAMETYPE_ESCORT ) |
|
{ |
|
CBroadcastRecipientFilter filter; |
|
EmitSound( filter, entindex(), "Hud.EndRoundScored" ); |
|
} |
|
else |
|
#endif |
|
{ |
|
CTeamRecipientFilter filter( iTeam ); |
|
EmitSound( filter, entindex(), "Hud.EndRoundScored" ); |
|
} |
|
} |
|
} |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: Used by Area caps to set the owner |
|
//----------------------------------------------------------------------------- |
|
void CTeamControlPoint::InputSetOwner( inputdata_t &input ) |
|
{ |
|
int iCapTeam = input.value.Int(); |
|
|
|
Assert( iCapTeam >= 0 && iCapTeam < GetNumberOfTeams() ); |
|
|
|
Assert( input.pCaller ); |
|
|
|
if ( !input.pCaller ) |
|
return; |
|
|
|
if ( GetOwner() == iCapTeam ) |
|
return; |
|
|
|
if ( TeamplayGameRules()->PointsMayBeCaptured() ) |
|
{ |
|
// must be done before setting the owner |
|
HandleScoring( iCapTeam ); |
|
|
|
if ( input.pCaller->IsPlayer() ) |
|
{ |
|
int iCappingPlayer = input.pCaller->entindex(); |
|
InternalSetOwner( iCapTeam, true, 1, &iCappingPlayer ); |
|
} |
|
else |
|
{ |
|
InternalSetOwner( iCapTeam, false ); |
|
} |
|
|
|
ObjectiveResource()->SetOwningTeam( GetPointIndex(), m_iTeam ); |
|
TeamplayRoundBasedRules()->RecalculateControlPointState(); |
|
} |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
void CTeamControlPoint::InputShowModel( inputdata_t &input ) |
|
{ |
|
RemoveEffects( EF_NODRAW ); |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
void CTeamControlPoint::InputHideModel( inputdata_t &input ) |
|
{ |
|
AddEffects( EF_NODRAW ); |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
int CTeamControlPoint::GetCurrentHudIconIndex( void ) |
|
{ |
|
return m_TeamData[GetOwner()].iIcon; |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
int CTeamControlPoint::GetHudIconIndexForTeam( int iGameTeam ) |
|
{ |
|
return m_TeamData[iGameTeam].iIcon; |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
int CTeamControlPoint::GetHudOverlayIndexForTeam( int iGameTeam ) |
|
{ |
|
return m_TeamData[iGameTeam].iOverlay; |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
int CTeamControlPoint::GetPreviousPointForTeam( int iGameTeam, int iPrevPoint ) |
|
{ |
|
Assert( iPrevPoint >= 0 && iPrevPoint < MAX_PREVIOUS_POINTS ); |
|
|
|
int iRetVal = -1; |
|
CBaseEntity *pEntity = gEntList.FindEntityByName( NULL, STRING(m_TeamData[iGameTeam].iszPreviousPoint[iPrevPoint]) ); |
|
|
|
if ( pEntity ) |
|
{ |
|
CTeamControlPoint *pPoint = dynamic_cast<CTeamControlPoint*>( pEntity ); |
|
|
|
if ( pPoint ) |
|
{ |
|
iRetVal = pPoint->GetPointIndex(); |
|
} |
|
} |
|
|
|
return iRetVal; |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
void CTeamControlPoint::ForceOwner( int iTeam ) |
|
{ |
|
InternalSetOwner( iTeam, false, 0, 0 ); |
|
ObjectiveResource()->SetOwningTeam( GetPointIndex(), m_iTeam ); |
|
TeamplayRoundBasedRules()->RecalculateControlPointState(); |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
void CTeamControlPoint::SetOwner( int iCapTeam, bool bMakeSound, int iNumCappers, int *pCappingPlayers ) |
|
{ |
|
if ( TeamplayGameRules()->PointsMayBeCaptured() ) |
|
{ |
|
// must be done before setting the owner |
|
HandleScoring( iCapTeam ); |
|
|
|
InternalSetOwner( iCapTeam, bMakeSound, iNumCappers, pCappingPlayers ); |
|
ObjectiveResource()->SetOwningTeam( GetPointIndex(), m_iTeam ); |
|
TeamplayRoundBasedRules()->RecalculateControlPointState(); |
|
} |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
void CTeamControlPoint::CaptureStart( int iCapTeam, int iNumCappingPlayers, int *pCappingPlayers ) |
|
{ |
|
int iNumCappers = iNumCappingPlayers; |
|
|
|
float flLastOwnershipChangeTime = -1.f; |
|
CBaseEntity *pEnt = gEntList.FindEntityByClassname( NULL, GetControlPointMasterName() ); |
|
while( pEnt ) |
|
{ |
|
CTeamControlPointMaster *pMaster = dynamic_cast<CTeamControlPointMaster *>( pEnt ); |
|
if ( pMaster && pMaster->IsActive() ) |
|
{ |
|
flLastOwnershipChangeTime = pMaster->GetLastOwnershipChangeTime(); |
|
} |
|
pEnt = gEntList.FindEntityByClassname( pEnt, GetControlPointMasterName() ); |
|
} |
|
|
|
IGameEvent *event = gameeventmanager->CreateEvent( "teamplay_point_startcapture" ); |
|
if ( event ) |
|
{ |
|
event->SetInt( "cp", m_iPointIndex ); |
|
event->SetString( "cpname", STRING( m_iszPrintName ) ); |
|
event->SetInt( "team", m_iTeam ); |
|
event->SetInt( "capteam", iCapTeam ); |
|
event->SetFloat( "captime", gpGlobals->curtime - flLastOwnershipChangeTime ); |
|
|
|
// safety check |
|
if ( iNumCappers > 8 ) |
|
{ |
|
iNumCappers = 8; |
|
} |
|
|
|
char cappers[9]; // pCappingPlayers should be max length 8 |
|
int i; |
|
for( i = 0 ; i < iNumCappers ; i++ ) |
|
{ |
|
cappers[i] = (char)pCappingPlayers[i]; |
|
} |
|
|
|
cappers[i] = '\0'; |
|
|
|
// pCappingPlayers is a null terminated list of player indices |
|
event->SetString( "cappers", cappers ); |
|
event->SetInt( "priority", 7 ); |
|
|
|
gameeventmanager->FireEvent( event ); |
|
} |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
void CTeamControlPoint::CaptureEnd( void ) |
|
{ |
|
StopLoopingSounds(); |
|
|
|
if ( !FBitSet( m_spawnflags, SF_CAP_POINT_NO_CAP_SOUNDS ) ) |
|
{ |
|
EmitSound( STRING( m_iszCaptureEndSound ) ); |
|
} |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
void CTeamControlPoint::CaptureInterrupted( bool bBlocked ) |
|
{ |
|
StopLoopingSounds(); |
|
|
|
if ( FBitSet( m_spawnflags, SF_CAP_POINT_NO_CAP_SOUNDS ) ) |
|
{ |
|
return; |
|
} |
|
|
|
const char *pSoundName = NULL; |
|
|
|
if ( bBlocked == true ) |
|
{ |
|
pSoundName = STRING( m_iszCaptureInterrupted ); |
|
} |
|
else |
|
{ |
|
pSoundName = STRING( m_iszCaptureInProgress ); |
|
EmitSound( STRING( m_iszCaptureStartSound ) ); |
|
} |
|
|
|
if ( m_pCaptureInProgressSound == NULL && pSoundName != NULL ) |
|
{ |
|
CPASFilter filter( GetAbsOrigin() ); |
|
|
|
CSoundEnvelopeController &controller = CSoundEnvelopeController::GetController(); |
|
m_pCaptureInProgressSound = controller.SoundCreate( filter, entindex(), pSoundName ); |
|
|
|
controller.Play( m_pCaptureInProgressSound, 1.0, 100 ); |
|
} |
|
|
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
void CTeamControlPoint::StopLoopingSounds( void ) |
|
{ |
|
CSoundEnvelopeController &controller = CSoundEnvelopeController::GetController(); |
|
|
|
if ( m_pCaptureInProgressSound ) |
|
{ |
|
controller.SoundDestroy( m_pCaptureInProgressSound ); |
|
m_pCaptureInProgressSound = NULL; |
|
} |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: Sets the new owner of the point, plays the appropriate sound and shows the right model |
|
//----------------------------------------------------------------------------- |
|
void CTeamControlPoint::InternalSetOwner( int iCapTeam, bool bMakeSound, int iNumCappers, int *pCappingPlayers ) |
|
{ |
|
Assert( iCapTeam >= 0 && iCapTeam < GetNumberOfTeams() ); |
|
|
|
int iOldTeam = m_iTeam; |
|
|
|
m_iTeam = iCapTeam; |
|
ChangeTeam( iCapTeam ); |
|
|
|
if ( bMakeSound ) |
|
{ |
|
CBroadcastRecipientFilter filter; |
|
EmitSound( filter, entindex(), STRING( m_TeamData[m_iTeam].iszCapSound ) ); |
|
} |
|
|
|
// Update visuals |
|
SetModel( STRING(m_TeamData[m_iTeam].iszModel) ); |
|
SetBodygroup( 0, m_iTeam ); |
|
m_nSkin = ( m_iTeam == TEAM_UNASSIGNED ) ? 2 : (m_iTeam - 2); |
|
ResetSequence( LookupSequence("idle") ); |
|
|
|
// We add 1 to the index because we consider the default "no points capped" as 0. |
|
TeamplayGameRules()->SetLastCapPointChanged( m_iPointIndex+1 ); |
|
|
|
// Determine the pose parameters for each team |
|
for ( int i = 0; i < m_TeamData.Count(); i++ ) |
|
{ |
|
// Skip spectator |
|
if ( i == TEAM_SPECTATOR ) |
|
continue; |
|
|
|
if ( GetModelPtr() && GetModelPtr()->SequencesAvailable() ) |
|
{ |
|
m_TeamData[i].iTeamPoseParam = LookupPoseParameter( UTIL_VarArgs( "cappoint_%d_percentage", i ) ); |
|
} |
|
else |
|
{ |
|
m_TeamData[i].iTeamPoseParam = -1; |
|
} |
|
} |
|
UpdateCapPercentage(); |
|
|
|
if ( m_iTeam == TEAM_UNASSIGNED ) |
|
{ |
|
m_OnCapReset.FireOutput( this, this ); |
|
} |
|
else |
|
{ |
|
// Remap team to get first game team = 1 |
|
switch ( m_iTeam - FIRST_GAME_TEAM+1 ) |
|
{ |
|
case 1: |
|
m_OnCapTeam1.FireOutput( this, this ); |
|
break; |
|
case 2: |
|
m_OnCapTeam2.FireOutput( this, this ); |
|
break; |
|
default: |
|
Assert(0); |
|
break; |
|
} |
|
} |
|
|
|
// If we're playing a sound, this is a true cap by players. |
|
if ( bMakeSound ) |
|
{ |
|
if ( iOldTeam > LAST_SHARED_TEAM && iOldTeam != m_iTeam ) |
|
{ |
|
// Make the members of our old team say something |
|
for ( int i = 1; i <= gpGlobals->maxClients; i++ ) |
|
{ |
|
CBaseMultiplayerPlayer *pPlayer = ToBaseMultiplayerPlayer( UTIL_PlayerByIndex( i ) ); |
|
if ( !pPlayer ) |
|
continue; |
|
if ( pPlayer->GetTeamNumber() == iOldTeam ) |
|
{ |
|
pPlayer->SpeakConceptIfAllowed( MP_CONCEPT_LOST_CONTROL_POINT ); |
|
} |
|
} |
|
} |
|
|
|
for( int i = 0; i < iNumCappers; i++ ) |
|
{ |
|
int playerIndex = pCappingPlayers[i]; |
|
|
|
Assert( playerIndex > 0 && playerIndex <= gpGlobals->maxClients ); |
|
|
|
PlayerCapped( ToBaseMultiplayerPlayer(UTIL_PlayerByIndex( playerIndex )) ); |
|
} |
|
|
|
// Remap team to get first game team = 1 |
|
switch ( m_iTeam - FIRST_GAME_TEAM+1 ) |
|
{ |
|
case 1: |
|
m_OnOwnerChangedToTeam1.FireOutput( this, this ); |
|
break; |
|
case 2: |
|
m_OnOwnerChangedToTeam2.FireOutput( this, this ); |
|
break; |
|
} |
|
|
|
if ( m_iTeam != TEAM_UNASSIGNED && iNumCappers ) |
|
{ |
|
SendCapString( m_iTeam, iNumCappers, pCappingPlayers ); |
|
} |
|
} |
|
|
|
// Have control point master check the win conditions now! |
|
CBaseEntity *pEnt = gEntList.FindEntityByClassname( NULL, GetControlPointMasterName() ); |
|
|
|
while( pEnt ) |
|
{ |
|
CTeamControlPointMaster *pMaster = dynamic_cast<CTeamControlPointMaster *>( pEnt ); |
|
|
|
if ( pMaster->IsActive() ) |
|
{ |
|
pMaster->CheckWinConditions(); |
|
pMaster->SetLastOwnershipChangeTime( gpGlobals->curtime ); |
|
} |
|
|
|
pEnt = gEntList.FindEntityByClassname( pEnt, GetControlPointMasterName() ); |
|
} |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
void CTeamControlPoint::SendCapString( int iCapTeam, int iNumCappingPlayers, int *pCappingPlayers ) |
|
{ |
|
if ( strlen( STRING(m_iszPrintName) ) <= 0 ) |
|
return; |
|
|
|
int iNumCappers = iNumCappingPlayers; |
|
|
|
IGameEvent *event = gameeventmanager->CreateEvent( "teamplay_point_captured" ); |
|
if ( event ) |
|
{ |
|
event->SetInt( "cp", m_iPointIndex ); |
|
event->SetString( "cpname", STRING( m_iszPrintName ) ); |
|
event->SetInt( "team", iCapTeam ); |
|
|
|
// safety check |
|
if ( iNumCappers > 8 ) |
|
{ |
|
iNumCappers = 8; |
|
} |
|
|
|
char cappers[9]; // pCappingPlayers should be max length 8 |
|
int i; |
|
for( i = 0 ; i < iNumCappers ; i++ ) |
|
{ |
|
cappers[i] = (char)pCappingPlayers[i]; |
|
} |
|
|
|
cappers[i] = '\0'; |
|
|
|
// pCappingPlayers is a null terminated list of player indices |
|
event->SetString( "cappers", cappers ); |
|
event->SetInt( "priority", 9 ); |
|
|
|
gameeventmanager->FireEvent( event ); |
|
} |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
void CTeamControlPoint::CaptureBlocked( CBaseMultiplayerPlayer *pPlayer ) |
|
{ |
|
if( strlen( STRING(m_iszPrintName) ) <= 0 ) |
|
return; |
|
|
|
IGameEvent *event = gameeventmanager->CreateEvent( "teamplay_capture_blocked" ); |
|
|
|
if ( event ) |
|
{ |
|
event->SetInt( "cp", m_iPointIndex ); |
|
event->SetString( "cpname", STRING(m_iszPrintName) ); |
|
event->SetInt( "blocker", pPlayer->entindex() ); |
|
event->SetInt( "priority", 9 ); |
|
|
|
gameeventmanager->FireEvent( event ); |
|
} |
|
|
|
PlayerBlocked( pPlayer ); |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
int CTeamControlPoint::GetOwner( void ) const |
|
{ |
|
return m_iTeam; |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
int CTeamControlPoint::GetDefaultOwner( void ) const |
|
{ |
|
return m_iDefaultOwner; |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
int CTeamControlPoint::GetCPGroup( void ) |
|
{ |
|
return m_iCPGroup; |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: Returns the time-based point value of this control point |
|
//----------------------------------------------------------------------------- |
|
int CTeamControlPoint::PointValue( void ) |
|
{ |
|
if ( GetOwner() != m_iDefaultOwner ) |
|
return m_TeamData[ GetOwner() ].iTimedPoints; |
|
|
|
return 0; |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
void CTeamControlPoint::SetActive( bool active ) |
|
{ |
|
m_bActive = active; |
|
|
|
if( active ) |
|
{ |
|
RemoveEffects( EF_NODRAW ); |
|
} |
|
else |
|
{ |
|
AddEffects( EF_NODRAW ); |
|
} |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
void CTeamControlPoint::SetCappersRequiredForTeam( int iGameTeam, int iCappers ) |
|
{ |
|
m_TeamData[iGameTeam].iPlayersRequired = iCappers; |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: Return true if this point has ever been contested, false if the enemy has never contested this point yet |
|
//----------------------------------------------------------------------------- |
|
bool CTeamControlPoint::HasBeenContested( void ) const |
|
{ |
|
return m_flLastContestedAt > 0.0f; |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
float CTeamControlPoint::LastContestedAt( void ) |
|
{ |
|
return m_flLastContestedAt; |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
void CTeamControlPoint::SetLastContestedAt( float flTime ) |
|
{ |
|
m_flLastContestedAt = flTime; |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
void CTeamControlPoint::UpdateCapPercentage( void ) |
|
{ |
|
for ( int i = LAST_SHARED_TEAM+1; i < m_TeamData.Count(); i++ ) |
|
{ |
|
// Skip spectator |
|
if ( i == TEAM_SPECTATOR ) |
|
continue; |
|
|
|
float flPerc = GetTeamCapPercentage(i); |
|
|
|
if ( m_TeamData[i].iTeamPoseParam != -1 ) |
|
{ |
|
SetPoseParameter( m_TeamData[i].iTeamPoseParam, flPerc ); |
|
} |
|
} |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
float CTeamControlPoint::GetTeamCapPercentage( int iTeam ) |
|
{ |
|
int iCappingTeam = ObjectiveResource()->GetCappingTeam( GetPointIndex() ); |
|
if ( iCappingTeam == TEAM_UNASSIGNED ) |
|
{ |
|
// No-one's capping this point. |
|
if ( iTeam == m_iTeam ) |
|
return 1.0; |
|
|
|
return 0.0; |
|
} |
|
|
|
float flCapPerc = ObjectiveResource()->GetCPCapPercentage( GetPointIndex() ); |
|
if ( iTeam == iCappingTeam ) |
|
return (1.0 - flCapPerc); |
|
if ( iTeam == m_iTeam ) |
|
return flCapPerc; |
|
|
|
return 0.0; |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
int CTeamControlPoint::DrawDebugTextOverlays( void ) |
|
{ |
|
int text_offset = BaseClass::DrawDebugTextOverlays(); |
|
|
|
if (m_debugOverlays & OVERLAY_TEXT_BIT) |
|
{ |
|
char tempstr[1024]; |
|
Q_snprintf(tempstr, sizeof(tempstr), "INDEX: (%d)", GetPointIndex() ); |
|
EntityText(text_offset,tempstr,0); |
|
text_offset++; |
|
|
|
Q_snprintf( tempstr, sizeof(tempstr), "Red Previous Points: "); |
|
for ( int i = 0; i < MAX_PREVIOUS_POINTS; i++ ) |
|
{ |
|
if ( m_TeamData[2].iszPreviousPoint[i] != NULL_STRING ) |
|
{ |
|
Q_strncat( tempstr, STRING(m_TeamData[2].iszPreviousPoint[i]), 1024, COPY_ALL_CHARACTERS ); |
|
Q_strncat( tempstr, ", ", 1024, COPY_ALL_CHARACTERS ); |
|
} |
|
} |
|
EntityText(text_offset,tempstr,0); |
|
text_offset++; |
|
|
|
Q_snprintf( tempstr, sizeof(tempstr), "Blue Previous Points: " ); |
|
for ( int i = 0; i < MAX_PREVIOUS_POINTS; i++ ) |
|
{ |
|
if ( m_TeamData[3].iszPreviousPoint[i] != NULL_STRING ) |
|
{ |
|
Q_strncat( tempstr, STRING(m_TeamData[3].iszPreviousPoint[i]), 1024, COPY_ALL_CHARACTERS ); |
|
Q_strncat( tempstr, ", ", 1024, COPY_ALL_CHARACTERS ); |
|
} |
|
} |
|
EntityText(text_offset,tempstr,0); |
|
text_offset++; |
|
|
|
for ( int i = 0; i < MAX_CONTROL_POINT_TEAMS; i++ ) |
|
{ |
|
if ( ObjectiveResource()->GetBaseControlPointForTeam(i) == GetPointIndex() ) |
|
{ |
|
Q_snprintf(tempstr, sizeof(tempstr), "Base Control Point for Team %d", i ); |
|
EntityText(text_offset,tempstr,0); |
|
text_offset++; |
|
} |
|
} |
|
} |
|
|
|
return text_offset; |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: The specified player took part in capping this point. |
|
//----------------------------------------------------------------------------- |
|
void CTeamControlPoint::PlayerCapped( CBaseMultiplayerPlayer *pPlayer ) |
|
{ |
|
if ( pPlayer ) |
|
{ |
|
pPlayer->SpeakConceptIfAllowed( MP_CONCEPT_CAPTURED_POINT ); |
|
} |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: The specified player blocked the enemy team from capping this point. |
|
//----------------------------------------------------------------------------- |
|
void CTeamControlPoint::PlayerBlocked( CBaseMultiplayerPlayer *pPlayer ) |
|
{ |
|
if ( pPlayer ) |
|
{ |
|
pPlayer->SpeakConceptIfAllowed( MP_CONCEPT_CAPTURE_BLOCKED ); |
|
} |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
void CTeamControlPoint::InputRoundActivate( inputdata_t &inputdata ) |
|
{ |
|
switch ( m_iTeam - FIRST_GAME_TEAM+1 ) |
|
{ |
|
case 1: |
|
m_OnRoundStartOwnedByTeam1.FireOutput( this, this ); |
|
break; |
|
case 2: |
|
m_OnRoundStartOwnedByTeam2.FireOutput( this, this ); |
|
break; |
|
} |
|
|
|
InternalSetLocked( m_bLocked ); |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
void CTeamControlPoint::InputSetLocked( inputdata_t &inputdata ) |
|
{ |
|
// never lock/unlock the point if we're in waiting for players |
|
if ( TeamplayRoundBasedRules() && TeamplayRoundBasedRules()->IsInWaitingForPlayers() ) |
|
return; |
|
|
|
bool bLocked = inputdata.value.Int() > 0; |
|
InternalSetLocked( bLocked ); |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
void CTeamControlPoint::InternalSetLocked( bool bLocked ) |
|
{ |
|
if ( !bLocked && m_bLocked ) |
|
{ |
|
// unlocked this point |
|
IGameEvent *event = gameeventmanager->CreateEvent( "teamplay_point_unlocked" ); |
|
if ( event ) |
|
{ |
|
event->SetInt( "cp", m_iPointIndex ); |
|
event->SetString( "cpname", STRING( m_iszPrintName ) ); |
|
event->SetInt( "team", m_iTeam ); |
|
gameeventmanager->FireEvent( event ); |
|
} |
|
} |
|
else if ( bLocked && !m_bLocked ) |
|
{ |
|
// locked this point |
|
IGameEvent *event = gameeventmanager->CreateEvent( "teamplay_point_locked" ); |
|
if ( event ) |
|
{ |
|
event->SetInt( "cp", m_iPointIndex ); |
|
event->SetString( "cpname", STRING( m_iszPrintName ) ); |
|
event->SetInt( "team", m_iTeam ); |
|
gameeventmanager->FireEvent( event ); |
|
} |
|
} |
|
|
|
m_bLocked = bLocked; |
|
|
|
if ( ObjectiveResource() && GetPointIndex() < ObjectiveResource()->GetNumControlPoints() ) |
|
{ |
|
ObjectiveResource()->SetCPLocked( GetPointIndex(), m_bLocked ); |
|
ObjectiveResource()->SetCPUnlockTime( GetPointIndex(), 0.0f ); |
|
} |
|
|
|
if ( !m_bLocked ) |
|
{ |
|
m_flUnlockTime = -1; |
|
m_OnUnlocked.FireOutput( this, this ); |
|
SetContextThink( NULL, 0, CONTROL_POINT_UNLOCK_THINK ); |
|
} |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
void CTeamControlPoint::InputSetUnlockTime( inputdata_t &inputdata ) |
|
{ |
|
// never lock/unlock the point if we're in waiting for players |
|
if ( TeamplayRoundBasedRules() && TeamplayRoundBasedRules()->IsInWaitingForPlayers() ) |
|
return; |
|
|
|
int nTime = inputdata.value.Int(); |
|
|
|
if ( nTime <= 0 ) |
|
{ |
|
InternalSetLocked( false ); |
|
return; |
|
} |
|
|
|
m_flUnlockTime = gpGlobals->curtime + nTime; |
|
|
|
if ( ObjectiveResource() ) |
|
{ |
|
ObjectiveResource()->SetCPUnlockTime( GetPointIndex(), m_flUnlockTime ); |
|
} |
|
|
|
SetContextThink( &CTeamControlPoint::UnlockThink, gpGlobals->curtime + 0.1, CONTROL_POINT_UNLOCK_THINK ); |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
void CTeamControlPoint::UnlockThink( void ) |
|
{ |
|
if ( m_flUnlockTime > 0 && |
|
m_flUnlockTime < gpGlobals->curtime && |
|
( TeamplayRoundBasedRules() && TeamplayRoundBasedRules()->State_Get() == GR_STATE_RND_RUNNING ) ) |
|
{ |
|
InternalSetLocked( false ); |
|
return; |
|
} |
|
|
|
SetContextThink( &CTeamControlPoint::UnlockThink, gpGlobals->curtime + 0.1, CONTROL_POINT_UNLOCK_THINK ); |
|
}
|
|
|