//----------------------------------------------------------------------------- // Purpose: Get a pointer to the specified team manager //----------------------------------------------------------------------------- CTeam *GetGlobalTeam( int iIndex ) { if ( iIndex < 0 || iIndex >= GetNumberOfTeams() ) return NULL; return g_Teams[ iIndex ]; }
//----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- CTeamControlPoint::CTeamControlPoint() { m_TeamData.SetSize( GetNumberOfTeams() ); m_pCaptureInProgressSound = NULL; }
//----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- void CTriggerAreaCapture::InputSetTeamCanCap( inputdata_t &inputdata ) { // Get the interaction name & target char parseString[255]; Q_strncpy(parseString, inputdata.value.String(), sizeof(parseString)); char *pszParam = strtok(parseString," "); if ( pszParam && pszParam[0] ) { int iTeam = atoi( pszParam ); pszParam = strtok(NULL," "); if ( pszParam && pszParam[0] ) { bool bCanCap = (atoi(pszParam) != 0); if ( iTeam >= 0 && iTeam < GetNumberOfTeams() ) { m_TeamData[iTeam].bCanCap = bCanCap; if ( m_hPoint ) { ObjectiveResource()->SetTeamCanCap( m_hPoint->GetPointIndex(), iTeam, m_TeamData[iTeam].bCanCap ); } return; } } } Warning("%s(%s) received SetTeamCanCap input with invalid format. Format should be: <team number> <can cap (0/1)>.\n", GetClassname(), GetDebugName() ); }
//----------------------------------------------------------------------------- // 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 ( 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 ); } }
//----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- void CTriggerAreaCapture::InputRoundSpawn( inputdata_t &inputdata ) { // find the flag we're linked to if( !m_hPoint ) { m_hPoint = dynamic_cast<CTeamControlPoint*>( gEntList.FindEntityByName(NULL, STRING(m_iszCapPointName) ) ); if ( m_hPoint ) { m_nOwningTeam = m_hPoint->GetOwner(); for ( int i = FIRST_GAME_TEAM; i < GetNumberOfTeams(); i++ ) { m_hPoint->SetCappersRequiredForTeam( i, m_TeamData[i].iNumRequiredToCap ); ObjectiveResource()->SetCPRequiredCappers( m_hPoint->GetPointIndex(), i, m_TeamData[i].iNumRequiredToCap ); ObjectiveResource()->SetTeamCanCap( m_hPoint->GetPointIndex(), i, m_TeamData[i].bCanCap ); if ( CaptureModeScalesWithPlayers() ) { ObjectiveResource()->SetCPCapTime( m_hPoint->GetPointIndex(), i, (m_flCapTime * 2) * m_TeamData[i].iNumRequiredToCap ); } else { ObjectiveResource()->SetCPCapTime( m_hPoint->GetPointIndex(), i, m_flCapTime ); } ObjectiveResource()->SetCPCapTimeScalesWithPlayers( m_hPoint->GetPointIndex(), CaptureModeScalesWithPlayers() ); } } } }
//----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- void CTeamplayRules::Precache( void ) { // Call the Team Manager's precaches for ( int i = 0; i < GetNumberOfTeams(); i++ ) { CTeam *pTeam = GetGlobalTeam( i ); pTeam->Precache(); } }
//----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- CTeamControlPoint::CTeamControlPoint() { m_TeamData.SetSize( GetNumberOfTeams() ); m_pCaptureInProgressSound = NULL; #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 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: //----------------------------------------------------------------------------- CTeamControlPoint::CTeamControlPoint() { m_TeamData.SetSize( GetNumberOfTeams() ); m_pCaptureInProgressSound = NULL; m_bLocked = false; m_flUnlockTime = -1; #if defined (TF_DLL) || defined (TF_CLASSIC) UseClientSideAnimation(); #endif }
//----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- void CBaseTeamObjectiveResource::Spawn( void ) { m_iNumControlPoints = 0; // If you hit this, you've got too many teams for the control point system to handle. Assert( GetNumberOfTeams() < MAX_CONTROL_POINT_TEAMS ); for ( int i=0; i < MAX_CONTROL_POINTS; i++ ) { // data variables m_vCPPositions.Set( i, vec3_origin ); m_bCPIsVisible.Set( i, true ); m_bBlocked.Set( i, false ); // state variables m_iOwner.Set( i, TEAM_UNASSIGNED ); m_iCappingTeam.Set( i, TEAM_UNASSIGNED ); m_iTeamInZone.Set( i, TEAM_UNASSIGNED ); m_bInMiniRound.Set( i, true ); m_bWarnOnCap.Set( i, false ); m_flLazyCapPerc.Set( i, 0.0 ); for ( int team = 0; team < MAX_CONTROL_POINT_TEAMS; team++ ) { int iTeamIndex = TEAM_ARRAY( i, team ); m_iTeamIcons.Set( iTeamIndex, 0 ); m_iTeamOverlays.Set( iTeamIndex, 0 ); m_iTeamReqCappers.Set( iTeamIndex, 0 ); m_flTeamCapTime.Set( iTeamIndex, 0.0f ); m_iNumTeamMembers.Set( TEAM_ARRAY( i, team ), 0 ); for ( int ipoint = 0; ipoint < MAX_PREVIOUS_POINTS; ipoint++ ) { int iIntIndex = ipoint + (i * MAX_PREVIOUS_POINTS) + (team * MAX_CONTROL_POINTS * MAX_PREVIOUS_POINTS); m_iPreviousPoints.Set( iIntIndex, -1 ); } m_bTeamCanCap.Set( iTeamIndex, false ); } } for ( int i = 0; i < MAX_TEAMS; i++ ) { m_iBaseControlPoints.Set( i, -1 ); } SetThink( &CBaseTeamObjectiveResource::ObjectiveThink ); SetNextThink( gpGlobals->curtime + LAZY_UPDATE_TIME ); }
//----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- bool CTeamControlPointRound::MakePlayable( void ) { CTeamControlPointMaster *pMaster = g_hControlPointMasters.Count() ? g_hControlPointMasters[0] : NULL; if ( pMaster ) { if ( !IsPlayable() ) { // we need to try switching the owners of the teams to make this round playable for ( int i = FIRST_GAME_TEAM ; i < GetNumberOfTeams() ; i++ ) { for ( int j = 0 ; j < m_ControlPoints.Count() ; j++ ) { if ( ( !pMaster->IsBaseControlPoint( m_ControlPoints[j]->GetPointIndex() ) ) && // this is NOT the base point for one of the teams (we don't want to assign the base to the wrong team) ( !WouldNewCPOwnerWinGame( m_ControlPoints[j], i ) ) ) // making this change would make this round playable { // need to find the trigger area associated with this point CBaseEntity *pEnt = gEntList.FindEntityByClassname( NULL, pMaster->GetTriggerAreaCaptureName() ); while( pEnt ) { CTriggerAreaCapture *pArea = assert_cast<CTriggerAreaCapture*>( pEnt ); if ( pArea ) { if ( pArea->TeamCanCap( i ) ) { CHandle<CTeamControlPoint> hPoint = pArea->GetControlPoint(); if ( hPoint == m_ControlPoints[j] ) { // found! pArea->ForceOwner( i ); // this updates the trigger_area *and* the control_point return true; } } } pEnt = gEntList.FindEntityByClassname( pEnt, pMaster->GetTriggerAreaCaptureName() ); } } } } } } return false; }
//----------------------------------------------------------------------------- // Purpose: Lock cap points when neither team can cap them for map-specific reasons //----------------------------------------------------------------------------- bool CControlPointIcon::IsPointLocked( void ) { bool bAnyTeamCanCap = false; for ( int gameteam = FIRST_GAME_TEAM; gameteam < GetNumberOfTeams(); gameteam++ ) { // Ignore teams that already own the point if ( ObjectiveResource()->GetOwningTeam(m_iCPIndex) != gameteam ) { if ( (ObjectiveResource()->TeamCanCapPoint( m_iCPIndex, gameteam)) ) { if ( TeamplayGameRules()->TeamMayCapturePoint( gameteam, m_iCPIndex ) ) { bAnyTeamCanCap = true; } } } } return ( !bAnyTeamCanCap ); }
//----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- bool CTeamControlPointRound::MakePlayable( void ) { CTeamControlPointMaster *pMaster = g_hControlPointMasters.Count() ? g_hControlPointMasters[0] : NULL; if ( pMaster ) { if ( !IsPlayable() ) { // we need to try switching the owners of the teams to make this round playable for ( int iTeam = FIRST_GAME_TEAM ; iTeam < GetNumberOfTeams() ; iTeam++ ) { for ( int iControlPoint = 0 ; iControlPoint < m_ControlPoints.Count() ; iControlPoint++ ) { if ( ( !pMaster->IsBaseControlPoint( m_ControlPoints[iControlPoint]->GetPointIndex() ) ) && // this is NOT the base point for one of the teams (we don't want to assign the base to the wrong team) ( !WouldNewCPOwnerWinGame( m_ControlPoints[iControlPoint], iTeam ) ) ) // making this change would make this round playable { // need to find the trigger area associated with this point for ( int iObj=0; iObj<ITriggerAreaCaptureAutoList::AutoList().Count(); ++iObj ) { CTriggerAreaCapture *pArea = static_cast< CTriggerAreaCapture * >( ITriggerAreaCaptureAutoList::AutoList()[iObj] ); if ( pArea->TeamCanCap( iTeam ) ) { CHandle<CTeamControlPoint> hPoint = pArea->GetControlPoint(); if ( hPoint == m_ControlPoints[iControlPoint] ) { // found! pArea->ForceOwner( iTeam ); // this updates the trigger_area *and* the control_point return true; } } } } } } } } return false; }
//----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- CTriggerAreaCapture::CTriggerAreaCapture() { m_TeamData.SetSize( GetNumberOfTeams() ); m_bStartTouch = false; m_hTrainWatcher = NULL; }
//----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- void CTriggerAreaCapture::CaptureThink( void ) { SetNextThink( gpGlobals->curtime + AREA_THINK_TIME ); // make sure this point is in the round being played (if we're playing one) CTeamControlPointMaster *pMaster = g_hControlPointMasters.Count() ? g_hControlPointMasters[0] : NULL; if ( pMaster && m_hPoint ) { if ( !pMaster->IsInRound( m_hPoint ) ) { return; } } if ( !TeamplayGameRules()->PointsMayBeCaptured() ) { // Points aren't allowed to be captured. If we were // being captured, we need to clean up and reset. if ( m_bCapturing ) { BreakCapture( false ); UpdateNumPlayers(); } return; } // go through our list of players Assert( GetNumberOfTeams() <= MAX_CAPTURE_TEAMS ); int iNumPlayers[MAX_CAPTURE_TEAMS]; int iNumBlockablePlayers[MAX_CAPTURE_TEAMS]; // Players in the zone who can't cap, but can block / pause caps CBaseMultiplayerPlayer *pFirstPlayerTouching[MAX_CAPTURE_TEAMS]; for ( int i = FIRST_GAME_TEAM; i < GetNumberOfTeams(); i++ ) { iNumPlayers[i] = 0; iNumBlockablePlayers[i] = 0; pFirstPlayerTouching[i] = NULL; } if ( m_hPoint ) { // Loop through the entities we're touching, and find players for ( int i = 0; i < m_hTouchingEntities.Count(); i++ ) { CBaseEntity *ent = m_hTouchingEntities[i]; if ( ent && ent->IsPlayer() ) { CBaseMultiplayerPlayer *pPlayer = ToBaseMultiplayerPlayer(ent); if ( pPlayer->IsAlive() ) { int iTeam = pPlayer->GetTeamNumber(); // If a team's not allowed to cap a point, don't count players in it at all if ( !TeamplayGameRules()->TeamMayCapturePoint( iTeam, m_hPoint->GetPointIndex() ) ) continue; if ( !TeamplayGameRules()->PlayerMayCapturePoint( pPlayer, m_hPoint->GetPointIndex() ) ) { if ( TeamplayGameRules()->PlayerMayBlockPoint( pPlayer, m_hPoint->GetPointIndex() ) ) { if ( iNumPlayers[iTeam] == 0 && iNumBlockablePlayers[iTeam] == 0 ) { pFirstPlayerTouching[iTeam] = pPlayer; } iNumBlockablePlayers[iTeam] += TeamplayGameRules()->GetCaptureValueForPlayer( pPlayer ); } continue; } if ( iTeam >= FIRST_GAME_TEAM ) { if ( iNumPlayers[iTeam] == 0 && iNumBlockablePlayers[iTeam] == 0 ) { pFirstPlayerTouching[iTeam] = pPlayer; } iNumPlayers[iTeam] += TeamplayGameRules()->GetCaptureValueForPlayer( pPlayer ); } } } } } int iTeamsInZone = 0; bool bUpdatePlayers = false; m_nTeamInZone = TEAM_UNASSIGNED; for ( int i = FIRST_GAME_TEAM; i < GetNumberOfTeams(); i++ ) { iNumPlayers[i] *= mp_simulatemultiplecappers.GetInt(); if ( m_TeamData[i].iNumTouching != iNumPlayers[i] ) { m_TeamData[i].iNumTouching = iNumPlayers[i]; bUpdatePlayers = true; } m_TeamData[i].iBlockedTouching = m_TeamData[i].iNumTouching; if ( m_TeamData[i].iNumTouching ) { iTeamsInZone++; m_nTeamInZone = i; } } if ( iTeamsInZone > 1 ) { m_nTeamInZone = TEAM_UNASSIGNED; } else { // If we've got non-cappable, yet blockable players here for the team that's defending, they // need to block the cap. This catches cases like the TF invulnerability, which needs to block // caps, but isn't allowed to contribute to a cap. for ( int i = FIRST_GAME_TEAM; i < GetNumberOfTeams(); i++ ) { if ( !iNumBlockablePlayers[i] || m_nTeamInZone == i ) continue; iTeamsInZone++; } } UpdateTeamInZone(); bool bBlocked = false; // If the cap is being blocked, reset the number of players so the client // knows to stop the capture as well. if ( mp_blockstyle.GetInt() == 1 ) { if ( m_bCapturing && iTeamsInZone > 1 ) { bBlocked = true; for ( int i = FIRST_GAME_TEAM; i < GetNumberOfTeams(); i++ ) { iNumPlayers[i] = 0; if ( m_TeamData[i].iNumTouching != iNumPlayers[i] ) { m_TeamData[i].iNumTouching = iNumPlayers[i]; bUpdatePlayers = true; } } } } if ( bUpdatePlayers ) { UpdateNumPlayers( bBlocked ); } // 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 ) { if ( m_hPoint ) { m_hPoint->SetLastContestedAt( gpGlobals->curtime ); } // Calculate the amount of modification to the cap time float flTimeDelta = gpGlobals->curtime - m_flLastReductionTime; float flReduction = flTimeDelta; if ( CaptureModeScalesWithPlayers() ) { // Diminishing returns for successive players. for ( int i = 1; i < m_TeamData[m_nTeamInZone].iNumTouching; i++ ) { flReduction += (flTimeDelta / (float)(i+1)); } } m_flLastReductionTime = gpGlobals->curtime; //if more than one team is in the zone if( iTeamsInZone > 1 ) { if ( !m_bBlocked ) { m_bBlocked = true; UpdateBlocked(); } // See if anyone gets credit for the block float flPercentToGo = m_fTimeRemaining / m_flCapTime; if ( CaptureModeScalesWithPlayers() ) { flPercentToGo = m_fTimeRemaining / ((m_flCapTime * 2) * m_TeamData[m_nCapturingTeam].iNumRequiredToCap); } if ( ( flPercentToGo <= 0.5 || TeamplayGameRules()->PointsMayAlwaysBeBlocked() ) && m_hPoint ) { // 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 CBaseMultiplayerPlayer *pBlockingPlayer = NULL; for ( int i = FIRST_GAME_TEAM; i < GetNumberOfTeams(); i++ ) { if ( m_nCapturingTeam == i ) continue; if ( pFirstPlayerTouching[i] ) { pBlockingPlayer = pFirstPlayerTouching[i]; break; } } Assert( pBlockingPlayer ); if ( pBlockingPlayer ) { bool bRepeatBlocker = false; for ( int i = m_Blockers.Count()-1; i >= 0; i-- ) { if ( m_Blockers[i].hPlayer != pBlockingPlayer ) continue; // If this guy's was a blocker, but not valid now, remove him from the list if ( m_Blockers[i].iCapAttemptNumber != m_iCapAttemptNumber || !IsTouching(m_Blockers[i].hPlayer) || ( TeamplayGameRules()->PointsMayAlwaysBeBlocked() && m_Blockers[i].flNextBlockTime < gpGlobals->curtime && m_bStartTouch ) ) { m_Blockers.Remove(i); continue; } bRepeatBlocker = true; break; } if ( !bRepeatBlocker ) { m_hPoint->CaptureBlocked( pBlockingPlayer ); // Add this guy to our blocker list int iNew = m_Blockers.AddToTail(); m_Blockers[iNew].hPlayer = pBlockingPlayer; m_Blockers[iNew].iCapAttemptNumber = m_iCapAttemptNumber; m_Blockers[iNew].flNextBlockTime = gpGlobals->curtime + 10.0f; } } } if ( mp_blockstyle.GetInt() == 0 ) { BreakCapture( false ); } return; } if ( m_bBlocked ) { m_bBlocked = false; UpdateBlocked(); } float flTotalTimeToCap = m_flCapTime; if ( CaptureModeScalesWithPlayers() ) { flTotalTimeToCap = ((m_flCapTime * 2) * m_TeamData[m_nCapturingTeam].iNumRequiredToCap); } // Now remove the reduction amount after we've determined there's only 1 team in the area if ( m_nCapturingTeam == m_nTeamInZone ) { SetCapTimeRemaining( m_fTimeRemaining - flReduction ); } else if ( m_nOwningTeam == TEAM_UNASSIGNED && m_nTeamInZone != TEAM_UNASSIGNED ) { SetCapTimeRemaining( m_fTimeRemaining + flReduction ); } else { // Caps deteriorate over time if ( TeamplayRoundBasedRules() && m_hPoint && TeamplayRoundBasedRules()->TeamMayCapturePoint(m_nCapturingTeam,m_hPoint->GetPointIndex()) ) { float flDecreaseScale = CaptureModeScalesWithPlayers() ? mp_capdeteriorate_time.GetFloat() : flTotalTimeToCap; float flDecrease = (flTotalTimeToCap / flDecreaseScale) * flTimeDelta; if ( TeamplayRoundBasedRules() && TeamplayRoundBasedRules()->InOvertime() ) { flDecrease *= 6; } SetCapTimeRemaining( m_fTimeRemaining + flDecrease ); } else { SetCapTimeRemaining( flTotalTimeToCap ); } } /* //if no-one is in the area if( iTeamsInZone == 0 ) { BreakCapture( true ); return; } //if they've lost the number of players needed to cap int iTeamMembersHere = m_TeamData[m_nCapturingTeam].iNumTouching + iNumBlockablePlayers[m_nCapturingTeam]; if ( (iTeamMembersHere == 0 ) || (mp_capstyle.GetInt() == 0 && iTeamMembersHere < m_TeamData[m_nCapturingTeam].iNumRequiredToCap) ) { BreakCapture( true ); return; } */ // if the cap is done if ( m_fTimeRemaining <= 0 ) { EndCapture( m_nCapturingTeam ); return; //we're done } else { // We may get several simultaneous CaptureThink calls from StartTouch if there are several players on the trigger // when it is enabled (like in Raid mode). We haven't started reducing m_fTimeRemaining yet but the second call to CaptureThink // from StartTouch has m_bCapturing set to true and we hit this condition and call BreakCapture right away. // We put this check here to prevent calling BreakCapture from the StartTouch call to CaptureThink. If the capture should // really be broken it will happen the next time the trigger thinks on its own. if ( !m_bStartTouch ) { if ( m_fTimeRemaining >= flTotalTimeToCap ) { BreakCapture( false ); return; } } } } else { // If there are any teams in the zone that aren't the owner, try to start capping if ( iTeamsInZone > 0 ) { for ( int i = FIRST_GAME_TEAM; i < GetNumberOfTeams(); i++ ) { if ( !m_TeamData[i].bCanCap || m_nOwningTeam == i ) continue; if ( m_TeamData[i].iNumTouching == 0 ) continue; if ( m_TeamData[i].iNumTouching < m_TeamData[i].iNumRequiredToStartCap ) continue; if ( !CaptureModeScalesWithPlayers() && m_TeamData[i].iNumTouching < m_TeamData[i].iNumRequiredToCap ) continue; StartCapture( i, CAPTURE_NORMAL ); break; } } } }
//----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- CTriggerAreaCapture::CTriggerAreaCapture() { m_TeamData.SetSize( GetNumberOfTeams() ); }
//----------------------------------------------------------------------------- // 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(); } pEnt = gEntList.FindEntityByClassname( pEnt, GetControlPointMasterName() ); } }
//----------------------------------------------------------------------------- // Purpose: Checks to see if it's time to change controllers //----------------------------------------------------------------------------- void CControlZone::ReevaluateControllingTeam( void ) { // Count the number of players in each team int i; memset( m_iPlayersInZone, 0, sizeof( m_iPlayersInZone ) ); for ( i = 0; i < m_ZonePlayerList.Size(); i++ ) { if ( m_ZonePlayerList[i] != NULL && (m_ZonePlayerList[i]->GetTeamNumber() > 0) ) { m_iPlayersInZone[ m_ZonePlayerList[i]->GetTeamNumber() ] += 1; } } // Abort immediately if we're not using touches to changes teams if ( HasSpawnFlags( CZF_DONT_USE_TOUCHES ) ) return; // if we're locked in place, no changes can occur to controlling team except through an explicit map ResetTeam if ( m_iLocked ) return; bool foundAnyTeam = false; int teamFound = 0; // check to see if any teams have no players for ( i = 1; i <= GetNumberOfTeams(); i++ ) { if ( m_iPlayersInZone[i] ) { if ( foundAnyTeam ) { // we've already found a team, so it's being contested; teamFound = ZONE_CONTESTED; break; } foundAnyTeam = true; teamFound = i; } } // no one in the area! if ( teamFound == 0 ) { // just leave it as it is, let it continue to change team // exception: if the zone state is contested, and there aren't any players in the zone, // just return to the team who used to own the zone. if ( GetTeamNumber() == ZONE_CONTESTED ) { ChangeTeam(m_iDefendingTeam); SetControllingTeam( this, m_iDefendingTeam ); } return; } // if it's the same controlling team, don't worry about it if ( teamFound == GetTeamNumber() ) { // the right team is in control, don't even think of switching m_iTryingToChangeToTeam = 0; SetNextThink( TICK_NEVER_THINK ); return; } // Find out if the zone isn't owned by anyone at all (hasn't been touched since the map started, and it started un-owned) bool bHasBeenOwned = true; if ( m_iDefendingTeam == 0 && GetTeamNumber() == 0 ) bHasBeenOwned = false; // if it's not contested, always go to contested mode if ( GetTeamNumber() != ZONE_CONTESTED && teamFound != GetTeamNumber() ) { // Unowned zones are captured immediately (no contesting stage) if ( bHasBeenOwned ) teamFound = ZONE_CONTESTED; } // if it's the team we're trying to change to, don't worry about it if ( teamFound == m_iTryingToChangeToTeam ) return; // set up the time to change to the new team soon m_iTryingToChangeToTeam = teamFound; // changing from contested->uncontested and visa-versa have different delays if ( m_iTryingToChangeToTeam != ZONE_CONTESTED ) { if ( !bHasBeenOwned ) { DevMsg( 1, "trigger_controlzone: (%s) changing team to %d NOW\n", GetDebugName(), m_iTryingToChangeToTeam ); SetNextThink( gpGlobals->curtime + 0.1f ); } else { DevMsg( 1, "trigger_controlzone: (%s) changing team to %d in %.2f seconds\n", GetDebugName(), m_iTryingToChangeToTeam, m_flTimeTillCaptured ); SetNextThink( gpGlobals->curtime + m_flTimeTillCaptured ); } } else { DevMsg( 1, "trigger_controlzone: (%s) changing to contested in %f seconds\n", GetDebugName(), m_flTimeTillContested ); SetNextThink( gpGlobals->curtime + m_flTimeTillContested ); } }
//----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- void CBaseTeamObjectiveResource::Spawn( void ) { m_iNumControlPoints = 0; // If you hit this, you've got too many teams for the control point system to handle. Assert( GetNumberOfTeams() < MAX_CONTROL_POINT_TEAMS ); for ( int i=0; i < MAX_CONTROL_POINTS; i++ ) { // data variables m_vCPPositions.Set( i, vec3_origin ); m_bCPIsVisible.Set( i, true ); m_bBlocked.Set( i, false ); // state variables m_iOwner.Set( i, TEAM_UNASSIGNED ); m_iCappingTeam.Set( i, TEAM_UNASSIGNED ); m_iTeamInZone.Set( i, TEAM_UNASSIGNED ); m_bInMiniRound.Set( i, true ); m_iWarnOnCap.Set( i, CP_WARN_NORMAL ); m_iCPGroup.Set( i, TEAM_INVALID ); m_flLazyCapPerc.Set( i, 0.0 ); m_bCPLocked.Set( i, false ); m_flUnlockTimes.Set( i, 0.0 ); m_flCPTimerTimes.Set( i, -1.0 ); m_bCPCapRateScalesWithPlayers.Set( i, true ); for ( int team = 0; team < MAX_CONTROL_POINT_TEAMS; team++ ) { int iTeamIndex = TEAM_ARRAY( i, team ); m_iTeamIcons.Set( iTeamIndex, 0 ); m_iTeamOverlays.Set( iTeamIndex, 0 ); m_iTeamReqCappers.Set( iTeamIndex, 0 ); m_flTeamCapTime.Set( iTeamIndex, 0.0f ); m_iNumTeamMembers.Set( TEAM_ARRAY( i, team ), 0 ); for ( int ipoint = 0; ipoint < MAX_PREVIOUS_POINTS; ipoint++ ) { int iIntIndex = ipoint + (i * MAX_PREVIOUS_POINTS) + (team * MAX_CONTROL_POINTS * MAX_PREVIOUS_POINTS); m_iPreviousPoints.Set( iIntIndex, -1 ); } m_bTeamCanCap.Set( iTeamIndex, false ); } } for ( int i = 0; i < MAX_TEAMS; i++ ) { m_iBaseControlPoints.Set( i, -1 ); } int nNumEntriesPerTeam = TEAM_TRAIN_MAX_HILLS * TEAM_TRAIN_FLOATS_PER_HILL; for ( int i = 0; i < TEAM_TRAIN_MAX_TEAMS; i++ ) { m_nNumNodeHillData.Set( i, 0 ); m_bTrackAlarm.Set( i, false ); int iStartingIndex = i * nNumEntriesPerTeam; for ( int j = 0 ; j < nNumEntriesPerTeam ; j++ ) { m_flNodeHillData.Set( iStartingIndex + j, 0 ); } iStartingIndex = i * TEAM_TRAIN_MAX_HILLS; for ( int j = 0; j < TEAM_TRAIN_MAX_HILLS; j++ ) { m_bHillIsDownhill.Set( iStartingIndex + j, 0 ); } } SetThink( &CBaseTeamObjectiveResource::ObjectiveThink ); SetNextThink( gpGlobals->curtime + LAZY_UPDATE_TIME ); }
//----------------------------------------------------------------------------- // Purpose: Add seconds to the timer while it is running or paused //----------------------------------------------------------------------------- void CTeamRoundTimer::AddTimerSeconds( int iSecondsToAdd, int iTeamResponsible /* = TEAM_UNASSIGNED*/ ) { if ( IsDisabled() ) return; if ( TeamplayRoundBasedRules()->InStalemate() ) return; // we only want to add time if we're round_running or team_win so the control points // don't add time when they try to set their default owner when the map is first loading if ( TeamplayRoundBasedRules()->State_Get() != GR_STATE_RND_RUNNING && TeamplayRoundBasedRules()->State_Get() != GR_STATE_TEAM_WIN ) return; if ( m_nTimerMaxLength > 0 ) { // will adding this many seconds push us over our max length? if ( GetTimeRemaining() + iSecondsToAdd > m_nTimerMaxLength ) { // adjust to only add up to our max length iSecondsToAdd = m_nTimerMaxLength - GetTimeRemaining(); } } if ( m_bTimerPaused ) { m_flTimeRemaining += (float)iSecondsToAdd; } else { m_flTimerEndTime += (float)iSecondsToAdd; } m_nTimerLength += iSecondsToAdd; CalculateOutputMessages(); if ( ObjectiveResource() && ObjectiveResource()->GetTimerInHUD() == entindex() ) { if ( !TeamplayRoundBasedRules()->InStalemate() && !TeamplayRoundBasedRules()->RoundHasBeenWon() ) { if ( iTeamResponsible >= LAST_SHARED_TEAM+1 ) { for ( int iTeam = LAST_SHARED_TEAM+1 ; iTeam < GetNumberOfTeams(); iTeam++ ) { if ( iTeam == iTeamResponsible ) { CTeamRecipientFilter filter( iTeam, true ); EmitSound( filter, entindex(), ROUND_TIMER_TIME_ADDED_WINNER ); } else { CTeamRecipientFilter filter( iTeam, true ); EmitSound( filter, entindex(), ROUND_TIMER_TIME_ADDED_LOSER ); } } } else { CReliableBroadcastRecipientFilter filter; EmitSound( filter, entindex(), ROUND_TIMER_TIME_ADDED ); } } // is this the timer we're showing in the HUD? if ( m_bShowInHUD ) { IGameEvent *event = gameeventmanager->CreateEvent( "teamplay_timer_time_added" ); if ( event ) { event->SetInt( "timer", entindex() ); event->SetInt( "seconds_added", iSecondsToAdd ); gameeventmanager->FireEvent( event ); } } } }