//========= 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 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( 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;iAwardAchievement( 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;iSetString( "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 ); }