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.
590 lines
14 KiB
590 lines
14 KiB
//========= Copyright Valve Corporation, All rights reserved. ============// |
|
// |
|
// Purpose: |
|
// |
|
//=============================================================================// |
|
|
|
#include "cbase.h" |
|
#include "dod_area_capture.h" |
|
#include "dod_player.h" |
|
#include "dod_gamerules.h" |
|
#include "dod_control_point.h" |
|
#include "dod_team.h" |
|
#include "dod_objective_resource.h" |
|
|
|
|
|
//------------------------------------------------------------------- |
|
// CAreaCapture |
|
// An area entity that players must remain in in order to active another entity |
|
// Triggers are fired on start of capture, on end of capture and on broken capture |
|
// Can either be capped by both teams at once, or just by one |
|
// Time to capture and number of people required to capture are both passed by the mapper |
|
|
|
|
|
|
|
BEGIN_DATADESC(CAreaCapture) |
|
|
|
// Touch functions |
|
DEFINE_FUNCTION( AreaTouch ), |
|
|
|
// Think functions |
|
DEFINE_THINKFUNC( Think ), |
|
|
|
// Keyfields |
|
DEFINE_KEYFIELD( m_iszCapPointName, FIELD_STRING, "area_cap_point" ), |
|
|
|
DEFINE_KEYFIELD( m_nAlliesNumCap, FIELD_INTEGER, "area_allies_numcap" ), |
|
DEFINE_KEYFIELD( m_nAxisNumCap, FIELD_INTEGER, "area_axis_numcap" ), |
|
DEFINE_KEYFIELD( m_flCapTime, FIELD_FLOAT, "area_time_to_cap" ), |
|
|
|
DEFINE_KEYFIELD( m_bAlliesCanCap, FIELD_BOOLEAN, "area_allies_cancap" ), |
|
DEFINE_KEYFIELD( m_bAxisCanCap, FIELD_BOOLEAN, "area_axis_cancap" ), |
|
|
|
DEFINE_KEYFIELD( m_bDisabled, FIELD_BOOLEAN, "StartDisabled" ), |
|
|
|
// Inputs |
|
DEFINE_INPUTFUNC( FIELD_VOID, "Disable", InputDisable ), |
|
DEFINE_INPUTFUNC( FIELD_VOID, "Enable", InputEnable ), |
|
DEFINE_INPUTFUNC( FIELD_VOID, "RoundInit", InputRoundInit ), |
|
|
|
// Outputs |
|
DEFINE_OUTPUT( m_AlliesStartOutput, "OnAlliesStartCap" ), |
|
DEFINE_OUTPUT( m_AlliesBreakOutput, "OnAlliesBreakCap" ), |
|
DEFINE_OUTPUT( m_AlliesCapOutput, "OnAlliesEndCap" ), |
|
|
|
DEFINE_OUTPUT( m_AxisStartOutput, "OnAxisStartCap" ), |
|
DEFINE_OUTPUT( m_AxisBreakOutput, "OnAxisBreakCap" ), |
|
DEFINE_OUTPUT( m_AxisCapOutput, "OnAxisEndCap" ), |
|
|
|
DEFINE_OUTPUT( m_StartOutput, "OnStartCap" ), |
|
DEFINE_OUTPUT( m_BreakOutput, "OnBreakCap" ), |
|
DEFINE_OUTPUT( m_CapOutput, "OnEndCap" ), |
|
|
|
// DEFINE_OUTPUT( m_OnStartCap, "OnStartCap" ); |
|
// DEFINE_OUTPUT( m_OnBreakCap, |
|
|
|
// DEFINE_OUTPUT( m_OnEnterNoObj, "OnEnterNoObj" ); |
|
|
|
END_DATADESC(); |
|
|
|
LINK_ENTITY_TO_CLASS( dod_capture_area, CAreaCapture ); |
|
|
|
void CAreaCapture::Spawn( void ) |
|
{ |
|
BaseClass::Spawn(); |
|
|
|
InitTrigger(); |
|
|
|
Precache(); |
|
|
|
m_iAreaIndex = -1; |
|
|
|
SetTouch ( &CAreaCapture::AreaTouch ); |
|
|
|
m_bCapturing = false; |
|
m_nCapturingTeam = TEAM_UNASSIGNED; |
|
m_nOwningTeam = TEAM_UNASSIGNED; |
|
m_fTimeRemaining = 0.0f; |
|
|
|
SetNextThink( gpGlobals->curtime + AREA_THINK_TIME ); |
|
|
|
if( m_nAlliesNumCap < 1 ) |
|
m_nAlliesNumCap = 1; |
|
|
|
if( m_nAxisNumCap < 1 ) |
|
m_nAxisNumCap = 1; |
|
|
|
m_bDisabled = false; |
|
|
|
m_iCapAttemptNumber = 0; |
|
} |
|
|
|
void CAreaCapture::Precache( void ) |
|
{ |
|
} |
|
|
|
bool CAreaCapture::KeyValue( const char *szKeyName, const char *szValue ) |
|
{ |
|
return BaseClass::KeyValue( szKeyName, szValue ); |
|
} |
|
|
|
//sends to all players at the start of the round |
|
//needed? |
|
void CAreaCapture::area_SetIndex( int index ) |
|
{ |
|
m_iAreaIndex = index; |
|
} |
|
|
|
bool CAreaCapture::IsActive( void ) |
|
{ |
|
return !m_bDisabled; |
|
} |
|
|
|
void CAreaCapture::AreaTouch( CBaseEntity *pOther ) |
|
{ |
|
//if they are touching, set their SIGNAL flag on, and their m_iCapAreaNum to ours |
|
//then in think do all the scoring |
|
|
|
if( !IsActive() ) |
|
return; |
|
|
|
//Don't cap areas unless the round is running |
|
if( DODGameRules()->State_Get() != STATE_RND_RUNNING || DODGameRules()->IsInWarmup() ) |
|
return; |
|
|
|
Assert( m_iAreaIndex != -1 ); |
|
|
|
if( m_pPoint ) |
|
{ |
|
m_nOwningTeam = m_pPoint->GetOwner(); |
|
} |
|
|
|
//dont touch for non-alive or non-players |
|
if( !pOther->IsPlayer() ) |
|
return; |
|
|
|
if( !pOther->IsAlive() ) |
|
return; |
|
|
|
CDODPlayer *pPlayer = ToDODPlayer(pOther); |
|
|
|
ASSERT( pPlayer ); |
|
|
|
if ( pPlayer->GetTeamNumber() != m_nOwningTeam ) |
|
{ |
|
bool bAbleToCap = ( pPlayer->GetTeamNumber() == TEAM_ALLIES && m_bAlliesCanCap ) || |
|
( pPlayer->GetTeamNumber() == TEAM_AXIS && m_bAxisCanCap ); |
|
|
|
if ( bAbleToCap ) |
|
pPlayer->HintMessage( HINT_IN_AREA_CAP ); |
|
} |
|
|
|
pPlayer->m_signals.Signal( SIGNAL_CAPTUREAREA ); |
|
|
|
//add them to this area |
|
pPlayer->SetCapAreaIndex( m_iAreaIndex ); |
|
|
|
if ( m_pPoint ) |
|
{ |
|
pPlayer->SetCPIndex( m_pPoint->GetPointIndex() ); |
|
} |
|
} |
|
|
|
/* three ways to be capturing a cap area |
|
* 1) have the required number of people in the area |
|
* 2) have less than the required number on your team, new required num is everyone |
|
* 3) have less than the required number alive, new required is numAlive, but time is lengthened |
|
*/ |
|
|
|
ConVar dod_simulatemultiplecappers( "dod_simulatemultiplecappers", "1", FCVAR_CHEAT ); |
|
|
|
void CAreaCapture::Think( void ) |
|
{ |
|
SetNextThink( gpGlobals->curtime + AREA_THINK_TIME ); |
|
|
|
if( DODGameRules()->State_Get() != STATE_RND_RUNNING ) |
|
{ |
|
// If we were being capped, cancel it |
|
if( m_nNumAllies > 0 || m_nNumAxis > 0 ) |
|
{ |
|
m_nNumAllies = 0; |
|
m_nNumAxis = 0; |
|
SendNumPlayers(); |
|
|
|
if( m_pPoint ) |
|
{ |
|
g_pObjectiveResource->SetCappingTeam( m_pPoint->GetPointIndex(), TEAM_UNASSIGNED ); |
|
} |
|
} |
|
return; |
|
} |
|
|
|
// go through our list of players |
|
|
|
int iNumAllies = 0; |
|
int iNumAxis = 0; |
|
|
|
CDODPlayer *pFirstAlliedTouching = NULL; |
|
CDODPlayer *pFirstAxisTouching = NULL; |
|
|
|
for ( int i = 1; i <= gpGlobals->maxClients; i++ ) |
|
{ |
|
CBaseEntity *ent = UTIL_PlayerByIndex( i ); |
|
if ( ent ) |
|
{ |
|
CDODPlayer *pPlayer = ToDODPlayer(ent); |
|
|
|
//First check if the player is in fact in this area |
|
if ( ( pPlayer->m_signals.GetState() & SIGNAL_CAPTUREAREA ) && |
|
pPlayer->GetCapAreaIndex() == m_iAreaIndex && |
|
pPlayer->IsAlive() ) // alive check is kinda unnecessary, but there is some |
|
// case where non-present people are messing up this count |
|
{ |
|
if ( pPlayer->GetTeamNumber() == TEAM_ALLIES ) |
|
{ |
|
if ( iNumAllies == 0 ) |
|
pFirstAlliedTouching = pPlayer; |
|
|
|
iNumAllies++; |
|
} |
|
else if ( pPlayer->GetTeamNumber() == TEAM_AXIS ) |
|
{ |
|
if ( iNumAxis == 0 ) |
|
pFirstAxisTouching = pPlayer; |
|
|
|
iNumAxis++; |
|
} |
|
} |
|
} |
|
} |
|
|
|
iNumAllies *= dod_simulatemultiplecappers.GetInt(); |
|
iNumAxis *= dod_simulatemultiplecappers.GetInt(); |
|
|
|
if( iNumAllies != m_nNumAllies || iNumAxis != m_nNumAxis ) |
|
{ |
|
m_nNumAllies = iNumAllies; |
|
m_nNumAxis = iNumAxis; |
|
SendNumPlayers(); |
|
} |
|
|
|
// when a player blocks, tell them the cap index and attempt number |
|
// only give successive blocks to them if the attempt number is different |
|
|
|
if( m_bCapturing ) |
|
{ |
|
//its a regular cap |
|
//Subtract some time from the cap |
|
m_fTimeRemaining -= AREA_THINK_TIME; |
|
|
|
//if both teams are in the area |
|
if( iNumAllies > 0 && iNumAxis > 0 ) |
|
{ |
|
// See if anyone gets credit for the block |
|
float flPercentToGo = m_fTimeRemaining / m_flCapTime; |
|
if ( flPercentToGo <= 0.5 && m_pPoint ) |
|
{ |
|
// find the first player that is not on the capturing team |
|
// they have just broken a cap and should be rewarded |
|
// tell the player the capture attempt number, for checking later |
|
CDODPlayer *pBlockingPlayer = ( m_nCapturingTeam == TEAM_ALLIES ) ? pFirstAxisTouching : pFirstAlliedTouching; |
|
|
|
if ( pBlockingPlayer ) |
|
{ |
|
if ( pBlockingPlayer->GetCapAreaIndex() == m_iAreaIndex && |
|
pBlockingPlayer->GetLastBlockCapAttempt() == m_iCapAttemptNumber ) |
|
{ |
|
// this is a repeat block on the same cap, ignore it |
|
NULL; |
|
} |
|
else |
|
{ |
|
m_pPoint->CaptureBlocked( pBlockingPlayer ); |
|
pBlockingPlayer->StoreCaptureBlock( m_iAreaIndex, m_iCapAttemptNumber ); |
|
} |
|
} |
|
} |
|
|
|
BreakCapture( false ); |
|
return; |
|
} |
|
|
|
//if no-one is in the area |
|
if( iNumAllies == 0 && iNumAxis == 0 ) |
|
{ |
|
BreakCapture( true ); |
|
return; |
|
} |
|
|
|
if( m_nCapturingTeam == TEAM_ALLIES ) |
|
{ |
|
if( iNumAllies < m_nAlliesNumCap ) |
|
{ |
|
BreakCapture( true ); |
|
} |
|
} |
|
else if( m_nCapturingTeam == TEAM_AXIS ) |
|
{ |
|
if( iNumAxis < m_nAxisNumCap ) |
|
{ |
|
BreakCapture( true ); |
|
} |
|
} |
|
|
|
//if the cap is done |
|
if( m_fTimeRemaining <= 0 ) |
|
{ |
|
EndCapture( m_nCapturingTeam ); |
|
return; //we're done |
|
} |
|
} |
|
else //not capturing yet |
|
{ |
|
bool bStarted = false; |
|
|
|
if( iNumAllies > 0 && iNumAxis <= 0 && m_bAlliesCanCap && m_nOwningTeam != TEAM_ALLIES ) |
|
{ |
|
if( iNumAllies >= m_nAlliesNumCap ) |
|
{ |
|
m_iCappingRequired = m_nAlliesNumCap; |
|
m_iCappingPlayers = iNumAllies; |
|
StartCapture( TEAM_ALLIES, CAPTURE_NORMAL ); |
|
bStarted = true; |
|
} |
|
} |
|
else if( iNumAxis > 0 && iNumAllies <= 0 && m_bAxisCanCap && m_nOwningTeam != TEAM_AXIS ) |
|
{ |
|
if( iNumAxis >= m_nAxisNumCap ) |
|
{ |
|
m_iCappingRequired = m_nAxisNumCap; |
|
m_iCappingPlayers = iNumAxis; |
|
StartCapture( TEAM_AXIS, CAPTURE_NORMAL ); |
|
bStarted = true; |
|
} |
|
} |
|
} |
|
} |
|
|
|
void CAreaCapture::SetOwner( int team ) |
|
{ |
|
//break any current capturing |
|
BreakCapture( false ); |
|
|
|
//set the owner to the passed value |
|
m_nOwningTeam = team; |
|
g_pObjectiveResource->SetOwningTeam( m_pPoint->GetPointIndex(), m_nOwningTeam ); |
|
} |
|
|
|
void CAreaCapture::SendNumPlayers( CBasePlayer *pPlayer ) |
|
{ |
|
if( !m_pPoint ) |
|
return; |
|
|
|
int index = m_pPoint->GetPointIndex(); |
|
|
|
g_pObjectiveResource->SetNumPlayers( index, TEAM_ALLIES, m_nNumAllies ); |
|
g_pObjectiveResource->SetNumPlayers( index, TEAM_AXIS, m_nNumAxis ); |
|
} |
|
|
|
void CAreaCapture::StartCapture( int team, int capmode ) |
|
{ |
|
int iNumCappers = 0; |
|
|
|
//trigger start |
|
if( team == TEAM_ALLIES ) |
|
{ |
|
m_AlliesStartOutput.FireOutput(this,this); |
|
iNumCappers = m_nAlliesNumCap; |
|
} |
|
else if( team == TEAM_AXIS ) |
|
{ |
|
m_AxisStartOutput.FireOutput(this,this); |
|
iNumCappers = m_nAxisNumCap; |
|
} |
|
|
|
m_StartOutput.FireOutput(this,this); |
|
|
|
m_nCapturingTeam = team; |
|
m_fTimeRemaining = m_flCapTime; |
|
m_bCapturing = true; |
|
m_iCapMode = capmode; |
|
|
|
if( m_pPoint ) |
|
{ |
|
//send a message that we're starting to cap this area |
|
g_pObjectiveResource->SetCappingTeam( m_pPoint->GetPointIndex(), m_nCapturingTeam ); |
|
} |
|
} |
|
|
|
#define MAX_AREA_CAPPERS 9 |
|
|
|
void CAreaCapture::EndCapture( int team ) |
|
{ |
|
m_iCapAttemptNumber++; |
|
|
|
//do the triggering |
|
if( team == TEAM_ALLIES ) |
|
{ |
|
m_AlliesCapOutput.FireOutput(this,this); |
|
} |
|
else if( team == TEAM_AXIS ) |
|
{ |
|
m_AxisCapOutput.FireOutput(this,this); |
|
} |
|
|
|
m_CapOutput.FireOutput(this,this); |
|
|
|
m_iCappingRequired = 0; |
|
m_iCappingPlayers = 0; |
|
|
|
int numcappers = 0; |
|
int cappingplayers[MAX_AREA_CAPPERS]; |
|
|
|
CDODPlayer *pCappingPlayer = NULL; |
|
|
|
CDODTeam *pTeam = GetGlobalDODTeam(team); |
|
if ( pTeam ) |
|
{ |
|
int iCount = pTeam->GetNumPlayers(); |
|
|
|
for ( int i=0;i<iCount;i++ ) |
|
{ |
|
CDODPlayer *pPlayer = ToDODPlayer( pTeam->GetPlayer(i) ); |
|
if ( pPlayer ) |
|
{ |
|
if( ( pPlayer->m_signals.GetState() & SIGNAL_CAPTUREAREA ) && |
|
pPlayer->GetCapAreaIndex() == m_iAreaIndex && |
|
pPlayer->IsAlive() ) |
|
{ |
|
if( pCappingPlayer == NULL ) |
|
pCappingPlayer = pPlayer; |
|
|
|
if ( numcappers < MAX_AREA_CAPPERS-1 ) |
|
{ |
|
cappingplayers[numcappers] = pPlayer->entindex(); |
|
numcappers++; |
|
} |
|
} |
|
} |
|
} |
|
} |
|
|
|
if ( numcappers < MAX_AREA_CAPPERS ) |
|
{ |
|
cappingplayers[numcappers] = 0; //null terminate :) |
|
} |
|
|
|
m_nOwningTeam = team; |
|
m_bCapturing = false; |
|
m_fTimeRemaining = 0.0f; |
|
|
|
//there may have been more than one capper, but only report this one. |
|
//he hasnt gotten points yet, and his name will go in the cap string if its needed |
|
//first capper gets name sent and points given by flag. |
|
//other cappers get points manually above, no name in message |
|
|
|
//send the player in the cap string |
|
if( m_pPoint ) |
|
{ |
|
DODGameRules()->CapEvent( CAP_EVENT_FLAG, m_nOwningTeam ); |
|
|
|
g_pObjectiveResource->SetOwningTeam( m_pPoint->GetPointIndex(), m_nOwningTeam ); |
|
m_pPoint->SetOwner( m_nOwningTeam, true, numcappers, cappingplayers ); |
|
} |
|
} |
|
|
|
void CAreaCapture::BreakCapture( bool bNotEnoughPlayers ) |
|
{ |
|
if( m_bCapturing ) |
|
{ |
|
m_iCappingRequired = 0; |
|
m_iCappingPlayers = 0; |
|
|
|
if( m_nCapturingTeam == TEAM_ALLIES ) |
|
m_AlliesBreakOutput.FireOutput(this,this); |
|
|
|
else if( m_nCapturingTeam == TEAM_AXIS ) |
|
m_AxisBreakOutput.FireOutput(this,this); |
|
|
|
m_BreakOutput.FireOutput(this,this); |
|
|
|
m_bCapturing = false; |
|
|
|
if( m_pPoint ) |
|
{ |
|
g_pObjectiveResource->SetCappingTeam( m_pPoint->GetPointIndex(), TEAM_UNASSIGNED ); |
|
} |
|
|
|
if ( bNotEnoughPlayers ) |
|
{ |
|
m_iCapAttemptNumber++; |
|
} |
|
} |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
void CAreaCapture::InputDisable( inputdata_t &inputdata ) |
|
{ |
|
m_bDisabled = true; |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
void CAreaCapture::InputEnable( inputdata_t &inputdata ) |
|
{ |
|
m_bDisabled = false; |
|
} |
|
|
|
void CAreaCapture::InputRoundInit( inputdata_t &inputdata ) |
|
{ |
|
// find the flag we're linked to |
|
if( !m_pPoint ) |
|
{ |
|
m_pPoint = dynamic_cast<CControlPoint*>( gEntList.FindEntityByName(NULL, STRING(m_iszCapPointName) ) ); |
|
|
|
if ( m_pPoint ) |
|
{ |
|
m_pPoint->SetNumCappersRequired( m_nAlliesNumCap, m_nAxisNumCap ); |
|
g_pObjectiveResource->SetCPRequiredCappers( m_pPoint->GetPointIndex(), m_nAlliesNumCap, m_nAxisNumCap ); |
|
g_pObjectiveResource->SetCPCapTime( m_pPoint->GetPointIndex(), m_flCapTime, m_flCapTime ); |
|
} |
|
} |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: Check if this player's death causes a block |
|
// return FALSE if the player is not in this area |
|
// return TRUE otherwise ( eg player is in area, but his death does not cause break ) |
|
//----------------------------------------------------------------------------- |
|
bool CAreaCapture::CheckIfDeathCausesBlock( CDODPlayer *pVictim, CDODPlayer *pKiller ) |
|
{ |
|
// This shouldn't happen |
|
if ( !pVictim || !pKiller ) |
|
{ |
|
Assert( !"Why are null players getting here?" ); |
|
return false; |
|
} |
|
|
|
// make sure this player is in this area |
|
if ( pVictim->GetCapAreaIndex() != m_iAreaIndex ) |
|
return false; |
|
|
|
// Teamkills shouldn't give a block reward |
|
if ( pVictim->GetTeamNumber() == pKiller->GetTeamNumber() ) |
|
return true; |
|
|
|
// return if the area is not being capped |
|
if ( !m_bCapturing ) |
|
return true; |
|
|
|
int iTeam = pVictim->GetTeamNumber(); |
|
|
|
// return if this player's team is not capping the area |
|
if ( iTeam != m_nCapturingTeam ) |
|
return true; |
|
|
|
bool bBlocked = false; |
|
|
|
if ( m_nCapturingTeam == TEAM_ALLIES ) |
|
{ |
|
if ( m_nNumAllies-1 < m_nAlliesNumCap ) |
|
bBlocked = true; |
|
} |
|
else if ( m_nCapturingTeam == TEAM_AXIS ) |
|
{ |
|
if ( m_nNumAxis-1 < m_nAxisNumCap ) |
|
bBlocked = true; |
|
} |
|
|
|
// break early incase we kill multiple people in the same frame |
|
if ( bBlocked ) |
|
{ |
|
m_pPoint->CaptureBlocked( pKiller ); |
|
BreakCapture( false ); |
|
} |
|
|
|
return true; |
|
}
|
|
|