diff options
Diffstat (limited to 'game/server/dod/dod_control_point.cpp')
| -rw-r--r-- | game/server/dod/dod_control_point.cpp | 738 |
1 files changed, 738 insertions, 0 deletions
diff --git a/game/server/dod/dod_control_point.cpp b/game/server/dod/dod_control_point.cpp new file mode 100644 index 0000000..5b74f8e --- /dev/null +++ b/game/server/dod/dod_control_point.cpp @@ -0,0 +1,738 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//=============================================================================// + +#include "cbase.h" +#include "dod_shareddefs.h" +#include "dod_control_point.h" +#include "dod_player.h" +#include "dod_gamerules.h" +#include "dod_team.h" +#include "dod_objective_resource.h" +#include "dod_control_point_master.h" + +LINK_ENTITY_TO_CLASS( dod_control_point, CControlPoint ); + +#define OBJ_ICON_NEUTRAL_FLAG 0 +#define OBJ_ICON_ALLIES_FLAG 1 +#define OBJ_ICON_AXIS_FLAG 2 + +BEGIN_DATADESC(CControlPoint) + + DEFINE_KEYFIELD( m_iszPrintName, FIELD_STRING, "point_printname" ), + + DEFINE_KEYFIELD( m_iszAlliesCapSound, FIELD_STRING, "point_allies_capsound" ), + DEFINE_KEYFIELD( m_iszAxisCapSound, FIELD_STRING, "point_axis_capsound" ), + DEFINE_KEYFIELD( m_iszResetSound, FIELD_STRING, "point_resetsound" ), + + DEFINE_KEYFIELD( m_iszAlliesModel, FIELD_STRING, "point_allies_model" ), + DEFINE_KEYFIELD( m_iszAxisModel, FIELD_STRING, "point_axis_model" ), + DEFINE_KEYFIELD( m_iszResetModel, FIELD_STRING, "point_reset_model" ), + + DEFINE_KEYFIELD( m_iCPGroup, FIELD_INTEGER, "point_group" ), + + DEFINE_KEYFIELD( m_iTimedPointsAllies, FIELD_INTEGER, "point_timedpoints_allies" ), + DEFINE_KEYFIELD( m_iTimedPointsAxis, FIELD_INTEGER, "point_timedpoints_axis" ), + + DEFINE_KEYFIELD( m_iBombsRequired, FIELD_INTEGER, "point_num_bombs" ), + + DEFINE_INPUTFUNC( FIELD_INTEGER, "SetOwner", InputSetOwner ), + + DEFINE_INPUTFUNC( FIELD_VOID, "ShowModel", InputShowModel ), + DEFINE_INPUTFUNC( FIELD_VOID, "HideModel", InputHideModel ), + + DEFINE_OUTPUT( m_AlliesCapOutput, "OnAlliesCap" ), // these are fired whenever the point changes modes + DEFINE_OUTPUT( m_AxisCapOutput, "OnAxisCap" ), + DEFINE_OUTPUT( m_PointResetOutput, "OnCapReset" ), + + DEFINE_OUTPUT( m_OwnerChangedToAllies, "AlliesCapturePoint" ), // these are fired when a team does the work to change the owner + DEFINE_OUTPUT( m_OwnerChangedToAxis, "AxisCapturePoint" ), + +END_DATADESC(); + + +CControlPoint::CControlPoint( ) +{ + m_iPointIndex = -1; + m_bPointVisible = false; + + m_iAlliesIcon = 0; + m_iAxisIcon = 0; + m_iNeutralIcon = 0; + m_iNeutralIcon = 0; + + //default group is 0 for backwards compatibility + m_iAlliesModelBodygroup = 0; + m_iAxisModelBodygroup = 0; + m_iResetModelBodygroup = 0; + + m_bBombPlanted = false; +} + +void CControlPoint::Spawn( void ) +{ + Precache(); + + SetTouch( NULL ); + + InternalSetOwner( m_iDefaultOwner, false ); //init the owner of this point + + SetActive( !m_bStartDisabled ); + + BaseClass::Spawn(); + + UseClientSideAnimation(); + + SetPlaybackRate( 1.0 ); + + SetCycle( random->RandomFloat( 0, 1.0 ) ); + + m_iAlliesRequired = 0; + m_iAxisRequired = 0; + + if ( FBitSet( m_spawnflags, CAP_POINT_HIDE_MODEL ) ) + { + AddEffects( EF_NODRAW ); + } + + m_iBombsRemaining = m_iBombsRequired; +} + +void CControlPoint::SetNumCappersRequired( int alliesRequired, int axisRequired ) +{ + m_iAlliesRequired = alliesRequired; + m_iAxisRequired = axisRequired; +} + +//================================ +// InputReset +// Used by ControlMaster to this point to its default owner +//================================ +void CControlPoint::InputReset( inputdata_t &input ) +{ + InternalSetOwner( m_iDefaultOwner, false ); + g_pObjectiveResource->SetOwningTeam( GetPointIndex(), m_iTeam ); +} + +//================================ +// InputReset +// Used by Area caps to set the owner +//================================ +void CControlPoint::InputSetOwner( inputdata_t &input ) +{ + int team = input.value.Int(); + + Assert( team == TEAM_UNASSIGNED || team == TEAM_ALLIES || team == TEAM_AXIS ); + + Assert( input.pCaller ); + Assert( input.pCaller->IsPlayer() ); + + CDODPlayer *pPlayer = ToDODPlayer( input.pCaller ); + + int iCappingPlayer = pPlayer->entindex(); + + // Only allow cp caps when round is running ( but not when in warmup ) + if( DODGameRules()->State_Get() == STATE_RND_RUNNING && + !DODGameRules()->IsInWarmup() ) + { + InternalSetOwner( team, true, 1, &iCappingPlayer ); + g_pObjectiveResource->SetOwningTeam( GetPointIndex(), m_iTeam ); + } +} + +void CControlPoint::SetOwner( int owner, bool bMakeSound, int iNumCappers, int *pCappingPlayers ) +{ + // Only allow cp caps when round is running ( but not when in warmup ) + if( DODGameRules()->State_Get() == STATE_RND_RUNNING && + !DODGameRules()->IsInWarmup() ) + { + InternalSetOwner( owner, bMakeSound, iNumCappers, pCappingPlayers ); + g_pObjectiveResource->SetOwningTeam( GetPointIndex(), m_iTeam ); + } +} + +void CControlPoint::InputShowModel( inputdata_t &input ) +{ + RemoveEffects( EF_NODRAW ); +} + +void CControlPoint::InputHideModel( inputdata_t &input ) +{ + AddEffects( EF_NODRAW ); +} + +int CControlPoint::GetCurrentHudIconIndex( void ) +{ + return GetHudIconIndexForTeam( GetOwner() ); +} + +int CControlPoint::GetHudIconIndexForTeam( int team ) +{ + int icon = m_iNeutralIcon; + + switch( team ) + { + case TEAM_ALLIES: + icon = m_iAlliesIcon; + break; + case TEAM_AXIS: + icon = m_iAxisIcon; + break; + case TEAM_UNASSIGNED: + icon = m_iNeutralIcon; + break; + default: + Assert( !"Bad team in GetHudIconIndexForTeam()" ); + break; + } + + return icon; +} + +int CControlPoint::GetTimerCapHudIcon( void ) +{ + return m_iTimerCapIcon; +} + +int CControlPoint::GetBombedHudIcon( void ) +{ + return m_iBombedIcon; +} + +// SetOwner +// ======== +// Sets the new owner of the point +// plays the appropriate sound +// and shows the right model + +void CControlPoint::InternalSetOwner( int owner, bool bMakeSound, int iNumCappers, int *pCappingPlayers ) +{ + m_iTeam = owner; + + switch ( m_iTeam ) + { + case TEAM_UNASSIGNED: + { + if( bMakeSound ) + { + CBroadcastRecipientFilter filter; + EmitSound( filter, entindex(), STRING(m_iszResetSound) ); + } + + SetModel( STRING(m_iszResetModel) ); + SetBodygroup( 0, m_iResetModelBodygroup ); + + m_PointResetOutput.FireOutput( this, this ); + } + break; + case TEAM_ALLIES: + { + if( bMakeSound ) + { + CBroadcastRecipientFilter filter; + EmitSound( filter, entindex(), STRING(m_iszAlliesCapSound) ); + } + + SetModel( STRING(m_iszAlliesModel) ); + SetBodygroup( 0, m_iAlliesModelBodygroup ); + + m_AlliesCapOutput.FireOutput( this, this ); + } + break; + case TEAM_AXIS: + { + if( bMakeSound ) + { + CBroadcastRecipientFilter filter; + EmitSound( filter, entindex(), STRING(m_iszAxisCapSound) ); + } + + SetModel( STRING(m_iszAxisModel) ); + SetBodygroup( 0, m_iAxisModelBodygroup ); + + m_AxisCapOutput.FireOutput( this, this ); + } + break; + default: + Assert(0); + break; + } + + if( bMakeSound ) //make sure this is a real cap and not a reset + { + for( int i=0;i<iNumCappers;i++ ) + { + int playerIndex = pCappingPlayers[i]; + + Assert( playerIndex > 0 && playerIndex <= gpGlobals->maxClients ); + + CDODPlayer *pPlayer = ToDODPlayer( UTIL_PlayerByIndex( playerIndex ) ); + + Assert( pPlayer ); + + if ( pPlayer ) + { + pPlayer->AddScore( PLAYER_POINTS_FOR_CAP ); + pPlayer->Stats_AreaCaptured(); + DODGameRules()->Stats_PlayerCap( pPlayer->GetTeamNumber(), pPlayer->m_Shared.DesiredPlayerClass() ); + + // count bomb plants as point capture + //if ( !m_bSetOwnerIsBombPlant ) + { + pPlayer->StatEvent_PointCaptured(); + } + } + } + + if ( m_iTeam == TEAM_ALLIES ) + { + m_OwnerChangedToAllies.FireOutput( this, this ); + } + else if ( m_iTeam == TEAM_AXIS ) + { + m_OwnerChangedToAxis.FireOutput( this, this ); + } + } + + if( bMakeSound && m_iTeam != TEAM_UNASSIGNED && iNumCappers > 0 ) //dont print message if its a reset + SendCapString( m_iTeam, iNumCappers, pCappingPlayers ); + + // have control point master check the win conditions now! + CBaseEntity *pEnt = gEntList.FindEntityByClassname( NULL, "dod_control_point_master" ); + + while( pEnt ) + { + CControlPointMaster *pMaster = dynamic_cast<CControlPointMaster *>( pEnt ); + + if ( pMaster->IsActive() ) + { + pMaster->CheckWinConditions(); + } + + pEnt = gEntList.FindEntityByClassname( pEnt, "dod_control_point_master" ); + } + + // Capping the last flag achievement + if ( ( DODGameRules()->State_Get() == STATE_ALLIES_WIN && m_iTeam == TEAM_ALLIES ) || + ( DODGameRules()->State_Get() == STATE_AXIS_WIN && m_iTeam == TEAM_AXIS ) ) + { + // limit to flag cap maps + if ( m_iBombsRequired == 0 ) + { + for ( int i=0;i<iNumCappers;i++ ) + { + CDODPlayer *pDODPlayer = ToDODPlayer( UTIL_PlayerByIndex( pCappingPlayers[i] ) ); + + if ( pDODPlayer ) + { + pDODPlayer->AwardAchievement( ACHIEVEMENT_DOD_CAP_LAST_FLAG ); + } + } + } + } +} + +void CControlPoint::SendCapString( int team, int iNumCappers, int *pCappingPlayers ) +{ + if( strlen( STRING(m_iszPrintName) ) <= 0 ) + return; + + IGameEvent * event = gameeventmanager->CreateEvent( "dod_point_captured" ); + + if ( event ) + { + event->SetInt( "cp", m_iPointIndex ); + event->SetString( "cpname", STRING(m_iszPrintName) ); + + char cappers[9]; // pCappingPlayers is 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 indeces + event->SetString( "cappers", cappers ); + event->SetInt( "priority", 9 ); + + event->SetBool( "bomb", m_bSetOwnerIsBombPlant ); + + gameeventmanager->FireEvent( event ); + } +} + +void CControlPoint::CaptureBlocked( CDODPlayer *pPlayer ) +{ + if( strlen( STRING(m_iszPrintName) ) <= 0 ) + return; + + IGameEvent *event = gameeventmanager->CreateEvent( "dod_capture_blocked" ); + + if ( event ) + { + event->SetInt( "cp", m_iPointIndex ); + event->SetString( "cpname", STRING(m_iszPrintName) ); + event->SetInt( "blocker", pPlayer->entindex() ); + event->SetInt( "priority", 9 ); + event->SetBool( "bomb", GetBombsRemaining() > 0 ); + + gameeventmanager->FireEvent( event ); + } + + pPlayer->AddScore( PLAYER_POINTS_FOR_BLOCK ); + + if ( GetBombsRemaining() <= 0 ) // no bomb blocks ( kills planter or defuser ) + { + pPlayer->StatEvent_CaptureBlocked(); + } + + pPlayer->Stats_AreaDefended(); + DODGameRules()->Stats_PlayerDefended( pPlayer->GetTeamNumber(), pPlayer->m_Shared.DesiredPlayerClass() ); +} + +// GetOwner +// ======== +// returns the current owner +// 2 for allies +// 3 for axis +// 0 if noone owns it + +int CControlPoint::GetOwner( void ) const +{ + return m_iTeam; +} + +int CControlPoint::GetDefaultOwner( void ) const +{ + return m_iDefaultOwner; +} + +int CControlPoint::GetCPGroup( void ) +{ + return m_iCPGroup; +} + +// PointValue +// ========== +// returns the time-based point value of this control point +int CControlPoint::PointValue( void ) +{ + // teams earn 0 points for a flag they start with + // after that its 1 additional point for each flag closer to the spawn. + + int value = 0; + + if ( FBitSet( m_spawnflags, CAP_POINT_TICK_FOR_BOMBS_REMAINING ) ) + { + value = m_iBombsRemaining; + } + else if ( GetOwner() == m_iDefaultOwner ) + { + value = 0; + } + else + { + if ( GetOwner() == TEAM_ALLIES ) + { + value = m_iTimedPointsAllies; + } + else if ( GetOwner() == TEAM_AXIS ) + { + value = m_iTimedPointsAxis; + } + } + + return value; +} + +//precache the necessary models and sounds +void CControlPoint::Precache( void ) +{ + if ( m_iszAlliesCapSound != NULL_STRING ) + { + PrecacheScriptSound( STRING(m_iszAlliesCapSound) ); + } + if ( m_iszAxisCapSound != NULL_STRING ) + { + PrecacheScriptSound( STRING(m_iszAxisCapSound) ); + } + if ( m_iszResetSound != NULL_STRING ) + { + PrecacheScriptSound( STRING(m_iszResetSound) ); + } + + PrecacheModel( STRING( m_iszAlliesModel ) ); + PrecacheModel( STRING( m_iszAxisModel ) ); + PrecacheModel( STRING( m_iszResetModel ) ); + + PrecacheMaterial( STRING( m_iszAlliesIcon ) ); + m_iAlliesIcon = GetMaterialIndex( STRING( m_iszAlliesIcon ) ); + Assert( m_iAlliesIcon != 0 ); + + PrecacheMaterial( STRING( m_iszAxisIcon ) ); + m_iAxisIcon = GetMaterialIndex( STRING( m_iszAxisIcon ) ); + Assert( m_iAxisIcon != 0 ); + + PrecacheMaterial( STRING( m_iszNeutralIcon ) ); + m_iNeutralIcon = GetMaterialIndex( STRING( m_iszNeutralIcon ) ); + Assert( m_iNeutralIcon != 0 ); + + if ( strlen( STRING( m_iszTimerCapIcon ) ) > 0 ) + { + PrecacheMaterial( STRING( m_iszTimerCapIcon ) ); + m_iTimerCapIcon = GetMaterialIndex( STRING( m_iszTimerCapIcon ) ); + } + + if ( strlen( STRING( m_iszBombedIcon ) ) > 0 ) + { + PrecacheMaterial( STRING( m_iszBombedIcon ) ); + m_iBombedIcon = GetMaterialIndex( STRING( m_iszBombedIcon ) ); + } + + if( !m_iNeutralIcon || !m_iAxisIcon || !m_iAlliesIcon ) + { + Warning( "Invalid hud icon material in control point ( point index %d )\n", GetPointIndex() ); + } +} + +// Keyvalue +// ======== +// this function interfaces with the keyvalues set by the mapper +// +// Values: +// point_name - the name of the point displayed in the capture string ( and ControlStatus command ) +// point_reset_time - time after which the point spontaneously resets - currently not used +// point_default_owner - the owner of this point at the start and after resets + +// point_allies_capsound | +// point_axis_capsound | the sounds that are made when the points are capped by each team +// point_resetsound | +// +// point_allies_model | +// point_axis_model | the models that the ent is set to after each team caps it +// point_reset_model | + +//point_team_points - number of team points to give to the capper's team for capping + +bool CControlPoint::KeyValue( const char *szKeyName, const char *szValue ) +{ + if (FStrEq(szKeyName, "point_default_owner")) + { + m_iDefaultOwner = atoi(szValue); + + Assert( m_iDefaultOwner == TEAM_ALLIES || + m_iDefaultOwner == TEAM_AXIS || + m_iDefaultOwner == TEAM_UNASSIGNED ); + + if( m_iDefaultOwner != TEAM_ALLIES && + m_iDefaultOwner != TEAM_AXIS && + m_iDefaultOwner != TEAM_UNASSIGNED ) + { + Warning( "dod_control_point with bad point_default_owner - probably '1'\n" ); + m_iDefaultOwner = TEAM_UNASSIGNED; + } + } + else if (FStrEq(szKeyName, "point_allies_model_bodygroup")) + { + m_iAlliesModelBodygroup = atoi(szValue); + } + else if (FStrEq(szKeyName, "point_axis_model_bodygroup")) + { + m_iAxisModelBodygroup = atoi(szValue); + } + else if (FStrEq(szKeyName, "point_reset_model_bodygroup")) + { + m_iResetModelBodygroup = atoi(szValue); + } + else if (FStrEq(szKeyName, "point_index")) + { + m_iPointIndex = atoi(szValue); + } + else if (FStrEq(szKeyName, "point_hud_icon_allies")) + { + m_iszAlliesIcon = AllocPooledString(szValue); + } + else if (FStrEq(szKeyName, "point_hud_icon_axis")) + { + m_iszAxisIcon = AllocPooledString(szValue); + } + else if (FStrEq(szKeyName, "point_hud_icon_neutral")) + { + m_iszNeutralIcon = AllocPooledString(szValue); + } + else if (FStrEq(szKeyName, "point_hud_icon_timercap")) + { + m_iszTimerCapIcon = AllocPooledString(szValue); + } + else if (FStrEq(szKeyName, "point_hud_icon_bombed")) + { + m_iszBombedIcon = AllocPooledString(szValue); + } + else + return CBaseEntity::KeyValue( szKeyName, szValue ); + + return true; +} + +void CControlPoint::SetActive( bool active ) +{ + m_bActive = active; + + if( active ) + { + RemoveEffects( EF_NODRAW ); + } + else + { + AddEffects( EF_NODRAW ); + } +} + +void CControlPoint::BombPlanted( float flTimerLength, CDODPlayer *pPlantingPlayer ) +{ + if ( m_bBombPlanted == true ) + { + Warning( "ERROR - dod_control_point only supports one bomb being planted at once\n" ); + return; + } + + //send it to everyone + IGameEvent *event = gameeventmanager->CreateEvent( "dod_bomb_planted" ); + if ( event ) + { + int iOppositeTeam = ( pPlantingPlayer->GetTeamNumber() == TEAM_ALLIES ) ? TEAM_AXIS : TEAM_ALLIES; + + event->SetInt( "team", iOppositeTeam ); + + event->SetInt( "cp", m_iPointIndex ); + event->SetString( "cpname", STRING(m_iszPrintName) ); + event->SetInt( "userid", pPlantingPlayer->GetUserID() ); + + gameeventmanager->FireEvent( event ); + } + + m_bBombPlanted = true; + m_flBombExplodeTime = gpGlobals->curtime + flTimerLength; + + // give the planter a point + pPlantingPlayer->AddScore( PLAYER_POINTS_FOR_BOMB_PLANT ); + + pPlantingPlayer->StatEvent_BombPlanted(); + + // set hud display + // this triggers the countdown ( using a shared, constant bomb timer ) + g_pObjectiveResource->SetBombPlanted( GetPointIndex(), true ); +} + +void CControlPoint::BombExploded( CDODPlayer *pPlantingPlayer /* = NULL */, int iPlantingTeam /* = TEAM_UNASSIGNED */ ) +{ + m_bBombPlanted = false; + + m_iBombsRemaining -= 1; + g_pObjectiveResource->SetBombsRemaining( GetPointIndex(), m_iBombsRemaining ); + + if ( pPlantingPlayer ) + { + IGameEvent *event = gameeventmanager->CreateEvent( "dod_bomb_exploded" ); + if ( event ) + { + event->SetInt( "cp", m_iPointIndex ); + event->SetString( "cpname", STRING(m_iszPrintName) ); + event->SetInt( "userid", pPlantingPlayer->GetUserID() ); + + gameeventmanager->FireEvent( event ); + } + + pPlantingPlayer->Stats_BombDetonated(); + + int iCappingPlayer = pPlantingPlayer->entindex(); + + DODGameRules()->CapEvent( CAP_EVENT_BOMB, iPlantingTeam ); + + if ( m_iBombsRemaining <= 0 ) + { + m_bSetOwnerIsBombPlant = true; + + InternalSetOwner( iPlantingTeam, true, 1, &iCappingPlayer ); + g_pObjectiveResource->SetOwningTeam( GetPointIndex(), GetOwner() ); + + m_bSetOwnerIsBombPlant = false; + + // top up points so it equals PLAYER_POINTS_FOR_BOMB_EXPLODED + pPlantingPlayer->AddScore( PLAYER_POINTS_FOR_BOMB_EXPLODED - PLAYER_POINTS_FOR_CAP ); + } + else + { + // give that bomber a point! + pPlantingPlayer->AddScore( PLAYER_POINTS_FOR_BOMB_EXPLODED ); + + pPlantingPlayer->Stats_AreaCaptured(); + + pPlantingPlayer->StatEvent_PointCaptured(); + + // send something to death notices to show that something was accomplished + + IGameEvent * event = gameeventmanager->CreateEvent( "dod_point_captured" ); + + if ( event ) + { + event->SetInt( "cp", m_iPointIndex ); + event->SetString( "cpname", STRING(m_iszPrintName) ); + + char cappers[3]; + cappers[0] = iCappingPlayer; + cappers[1] = '\0'; + + // pCappingPlayers is a null terminated list of player indeces + event->SetString( "cappers", cappers ); + event->SetInt( "priority", 9 ); + + event->SetBool( "bomb", true ); + + gameeventmanager->FireEvent( event ); + } + } + } + else + { + if ( m_iBombsRemaining <= 0 ) + { + // get the opposite team + int team = ( GetOwner() == TEAM_ALLIES ) ? TEAM_AXIS : TEAM_ALLIES; + + InternalSetOwner( team, true ); + g_pObjectiveResource->SetOwningTeam( GetPointIndex(), GetOwner() ); + } + } + + g_pObjectiveResource->SetBombPlanted( GetPointIndex(), false ); +} + +void CControlPoint::BombDisarmed( CDODPlayer *pDisarmingPlayer ) +{ + CancelBombPlanted(); + + CaptureBlocked( pDisarmingPlayer ); + + IGameEvent *event = gameeventmanager->CreateEvent( "dod_bomb_defused" ); + if ( event ) + { + event->SetInt( "cp", m_iPointIndex ); + event->SetString( "cpname", STRING(m_iszPrintName) ); + event->SetInt( "userid", pDisarmingPlayer->GetUserID() ); + event->SetInt( "team", pDisarmingPlayer->GetTeamNumber() ); + gameeventmanager->FireEvent( event ); + } +} + +void CControlPoint::CancelBombPlanted( void ) +{ + m_bBombPlanted = false; + + // reset hud display + g_pObjectiveResource->SetBombPlanted( GetPointIndex(), false ); +}
\ No newline at end of file |