예제 #1
0
void CTeamTrainWatcher::WatcherAlarmThink( void )
{
	CTeamControlPoint *pPoint = m_CPLinks[m_iNumCPLinks-1].hCP.Get();
	if ( pPoint )
	{
		pPoint->EmitSound( TEAM_TRAIN_ALARM_SINGLE );
	}

	SetContextThink( &CTeamTrainWatcher::WatcherAlarmThink, gpGlobals->curtime + TW_ALARM_THINK_INTERVAL, TW_ALARM_THINK );
}
//-----------------------------------------------------------------------------
// Purpose: 
//-----------------------------------------------------------------------------
int CTeamControlPointRound::GetPointOwner( int point )
{
	Assert( point >= 0 );
	Assert( point < MAX_CONTROL_POINTS );

	CTeamControlPoint *pPoint = m_ControlPoints[point];

	if ( pPoint )
		return pPoint->GetOwner();

	return TEAM_UNASSIGNED;
}
예제 #3
0
CBaseEntity* GetCapturePointByIndex( int iCaptureIndex )
{
    CTeamControlPoint *pTeamControlPoint = (CTeamControlPoint *)gEntList.FindEntityByClassname( NULL, "team_control_point" );

    while ( pTeamControlPoint )
    {
        if ( pTeamControlPoint->GetPointIndex() == iCaptureIndex )
        {
            return pTeamControlPoint;
        }

        pTeamControlPoint = (CTeamControlPoint *)gEntList.FindEntityByClassname( pTeamControlPoint, "team_control_point" );
    }

    return NULL;
}
//-----------------------------------------------------------------------------
// Purpose: 
//-----------------------------------------------------------------------------
void CTeamControlPointRound::FindControlPoints( void )
{
	// Let out control point masters know that the round has started
	CTeamControlPointMaster *pMaster = g_hControlPointMasters.Count() ? g_hControlPointMasters[0] : NULL;

	if ( pMaster )
	{
		// go through all the points
		CBaseEntity *pEnt = gEntList.FindEntityByClassname( NULL, pMaster->GetControlPointName() );
		
		while( pEnt )
		{
			CTeamControlPoint *pPoint = assert_cast<CTeamControlPoint *>(pEnt);

			if ( pPoint )
			{
				const char *pString = STRING( m_iszCPNames );
				const char *pName = STRING( pPoint->GetEntityName() );

				// HACK to work around a problem with cp_a being returned for an entity name with cp_A
				const char *pos = Q_stristr( pString, pName );
				if ( pos )
				{
					int len = Q_strlen( STRING( pPoint->GetEntityName() ) );
					if ( *(pos + len) == ' ' || *(pos + len) == '\0' )
					{
						if( m_ControlPoints.Find( pPoint ) == m_ControlPoints.InvalidIndex() )
						{
							DevMsg( 2, "Adding control point %s to control point round %s\n", pPoint->GetEntityName().ToCStr(), GetEntityName().ToCStr() );
							m_ControlPoints.AddToHead( pPoint );
						}
					}
				}
			}

			pEnt = gEntList.FindEntityByClassname( pEnt, pMaster->GetControlPointName() );
		}
	}

	if( m_ControlPoints.Count() == 0 ) 
	{
		Warning( "Error! No control points found in map for team_game_round %s!\n", GetEntityName().ToCStr() );
	}
}
//-----------------------------------------------------------------------------
// 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;
}
ActionResult<CTFBot> CTFBotCapturePoint::Update(CTFBot *actor, float dt)
{
	if (TFGameRules()->InSetup()) {
		this->m_PathFollower.Invalidate();
		this->m_ctRecomputePath.Start(RandomFloat(1.0f, 2.0f));
		
		return ActionResult<CTFBot>::Continue();
	}
	
	CTeamControlPoint *point = actor->GetMyControlPoint();
	if (point == nullptr) {
		return ActionResult<CTFBot>::SuspendFor(new CTFBotSeekAndDestroy(10.0f),
			"Seek and destroy until a point becomes available");
	}
	
	if (point->GetTeamNumber() == actor->GetTeamNumber()) {
		return ActionResult<CTFBot>::ChangeTo(new CTFBotDefendPoint(),
			"We need to defend our point(s)");
	}
	
	const CKnownEntity *threat = actor->GetVisionInterface()->GetPrimaryKnownThreat(false);
	if (threat != nullptr && threat->IsVisibleRecently()) {
		actor->EquipBestWeaponForThreat(threat);
	}
	
	if ((!actor->IsPointBeingCaptured(point) || actor->GetTimeSinceWeaponFired() < 2.0f) &&
		!actor->IsCapturingPoint() && !TFGameRules()->InOvertime() &&
		actor->GetTimeLeftToCapture() >= tf_bot_offense_must_push_time.GetFloat() &&
		!TFGameRules()->IsInTraining() && !actor->IsNearPoint(point) &&
		threat != nullptr && threat->IsVisibleRecently()) {
		float duration = RandomFloat(tf_bot_capture_seek_and_destroy_min_duration.GetFloat(),
			tf_bot_capture_seek_and_destroy_max_duration.GetFloat());
		
		return ActionResult<CTFBot>::SuspendFor(new CTFBotSeekAndDestroy(duration),
			"Too early to capture - hunting");
	}
	
	if (actor->IsCapturingPoint()) {
		if (point->GetPointIndex() > 7) {
			return ActionResult<CTFBot>::Continue();
		}
		
		// TODO
		
		// ...
		
		// Path::Compute
	}
	
	if (this->m_ctRecomputePath.IsElapsed()) {
		VPROF_BUDGET("CTFBotCapturePoint::Update( repath )", "NextBot");
		
		CTFBotPathCost cost_func(actor, SAFEST_ROUTE);
		this->m_PathFollower.Compute(actor, point->GetAbsOrigin(), cost_func, 0.0f, true);
		
		this->m_ctRecomputePath.Start(RandomFloat(2.0f, 3.0f));
	}
	
	if (TFGameRules()->IsInTraining() && !actor->IsAnyPointBeingCaptured() &&
		this->m_PathFollower.GetLength() < 1000.0f) {
		actor->SpeakConceptIfAllowed(MP_CONCEPT_PLAYER_GO);
	} else {
		this->m_PathFollower.Update(actor);
	}
	
	return ActionResult<CTFBot>::Continue();
}
예제 #7
0
void CTeamTrainWatcher::WatcherThink( void )
{
	if ( m_bWaitingToRecede )
	{
		if ( m_flRecedeTime < gpGlobals->curtime )
		{
			m_bWaitingToRecede = false;

			// don't actually recede in overtime
			if ( TeamplayRoundBasedRules() && !TeamplayRoundBasedRules()->InOvertime() )
			{
				// fire recede output
				m_OnTrainStartRecede.FireOutput( this, this );
				HandleTrainMovement( true );
			}
		}
	}

	bool bDisableAlarm = (TeamplayRoundBasedRules() && TeamplayRoundBasedRules()->State_Get() != GR_STATE_RND_RUNNING);
	if ( bDisableAlarm )
	{
		StopCaptureAlarm();
	}

	// given its next node, we can walk the nodes and find the linear
	// distance to the next cp node, or to the goal node

	CFuncTrackTrain *pTrain = m_hTrain;
	if ( pTrain )
	{
		int iOldTrainSpeedLevel = m_iTrainSpeedLevel;

		// how fast is the train moving?
		float flSpeed = pTrain->GetDesiredSpeed();

		// divide speed into regions
		// anything negative is -1

		if ( flSpeed < 0 )
		{
			m_iTrainSpeedLevel = -1;

			// even though our desired speed might be negative,
			// our actual speed might be zero if we're at a dead end...
			// this will turn off the < image when the train is done moving backwards
			if ( pTrain->GetCurrentSpeed() == 0 )
			{
				m_iTrainSpeedLevel = 0;
			}
		}
		else if ( flSpeed > m_flSpeedLevels[2] )
		{
			m_iTrainSpeedLevel = 3;
		}
		else if ( flSpeed > m_flSpeedLevels[1] )
		{
			m_iTrainSpeedLevel = 2;
		}
		else if ( flSpeed > m_flSpeedLevels[0] )
		{
			m_iTrainSpeedLevel = 1;
		}
		else
		{
			m_iTrainSpeedLevel = 0;
		}

		if ( m_iTrainSpeedLevel != iOldTrainSpeedLevel )
		{
			// make sure the sparks are off if we're not moving backwards anymore
			if ( m_bHandleTrainMovement )
			{
				if ( m_iTrainSpeedLevel == 0 && iOldTrainSpeedLevel != 0 )
				{
					HandleSparks( false );
				}
			}

			// play any concepts that we might need to play		
			if ( TeamplayRoundBasedRules() )
			{
				if ( m_iTrainSpeedLevel == 0 && iOldTrainSpeedLevel != 0 )
				{
					TeamplayRoundBasedRules()->HaveAllPlayersSpeakConceptIfAllowed( MP_CONCEPT_CART_STOP );
					m_flNextSpeakForwardConceptTime = 0;
				}
				else if ( m_iTrainSpeedLevel < 0 && iOldTrainSpeedLevel == 0 )
				{
					TeamplayRoundBasedRules()->HaveAllPlayersSpeakConceptIfAllowed( MP_CONCEPT_CART_MOVING_BACKWARD );
					m_flNextSpeakForwardConceptTime = 0;
				}
			}
		}

		if ( m_iTrainSpeedLevel > 0 && m_flNextSpeakForwardConceptTime < gpGlobals->curtime )
		{
			if ( m_hAreaCap.Get() )
			{
				for ( int i = 1; i <= gpGlobals->maxClients; i++ )
				{
					CBaseMultiplayerPlayer *pPlayer = ToBaseMultiplayerPlayer( UTIL_PlayerByIndex( i ) );
					if ( pPlayer )
					{
						if ( m_hAreaCap->IsTouching( pPlayer ) )
						{
							pPlayer->SpeakConceptIfAllowed( MP_CONCEPT_CART_MOVING_FORWARD );
						}
					}
				}
			}

			m_flNextSpeakForwardConceptTime = gpGlobals->curtime + 3.0;
		}

		// what percent progress are we at?
		CPathTrack *pNode = ( pTrain->m_ppath ) ? pTrain->m_ppath->GetNext() : NULL;

		// if we're moving backwards, GetNext is going to be wrong
		if ( flSpeed < 0 )
		{
			pNode = pTrain->m_ppath;
		}

		if ( pNode )
		{
			float flDistanceToGoal = 0;

			// distance to next node
			Vector vecDir = pNode->GetLocalOrigin() - pTrain->GetLocalOrigin();
			flDistanceToGoal = vecDir.Length();

			// distance of next node to goal node
			if ( pNode && pNode != m_hGoalNode )
			{
				// walk this until we get to goal node, or a dead end
				CPathTrack *pPrev = pNode;
				pNode = pNode->GetNext();
				while ( pNode )
				{
					vecDir = pNode->GetLocalOrigin() - pPrev->GetLocalOrigin();
					flDistanceToGoal += vecDir.Length();

					if ( pNode == m_hGoalNode )
						break;

					pPrev = pNode;
					pNode = pNode->GetNext();
				}
			}

			if ( m_flTotalPathDistance <= 0 )
			{
				Assert( !"No path distance in team_train_watcher\n" );
				m_flTotalPathDistance = 1;
			}

			m_flTotalProgress = clamp( 1.0 - ( flDistanceToGoal / m_flTotalPathDistance ), 0.0, 1.0 );

			m_flTrainDistanceFromStart = m_flTotalPathDistance - flDistanceToGoal;

			// play alert sounds if necessary
			for ( int iCount = 0 ; iCount < m_iNumCPLinks ; iCount++ )
			{
				if ( m_flTrainDistanceFromStart < m_CPLinks[iCount].flDistanceFromStart - TEAM_TRAIN_ALERT_DISTANCE )
				{
					// back up twice the alert distance before resetting our flag to play the warning again
					if ( ( m_flTrainDistanceFromStart < m_CPLinks[iCount].flDistanceFromStart - ( TEAM_TRAIN_ALERT_DISTANCE * 2 ) ) || // has receded back twice the alert distance or...
						 ( !m_bTrainCanRecede ) ) // used to catch the case where the train doesn't normally recede but has rolled back down a hill away from the CP
					{
						// reset our alert flag
						m_CPLinks[iCount].bAlertPlayed = false;
					}
				}
				else
				{
					if ( m_flTrainDistanceFromStart < m_CPLinks[iCount].flDistanceFromStart && !m_CPLinks[iCount].bAlertPlayed )
					{
						m_CPLinks[iCount].bAlertPlayed = true;
						bool bFinalPointInMap = false;

						CTeamControlPoint *pCurrentPoint = m_CPLinks[iCount].hCP.Get();
						CTeamControlPointMaster *pMaster = g_hControlPointMasters.Count() ? g_hControlPointMasters[0] : NULL;
						if ( pMaster )
						{
							// if we're not playing mini-rounds 
							if ( !pMaster->PlayingMiniRounds() )  
							{
								for ( int i = FIRST_GAME_TEAM ; i < MAX_CONTROL_POINT_TEAMS ; i++ )
								{
									if ( ObjectiveResource() && ObjectiveResource()->TeamCanCapPoint( pCurrentPoint->GetPointIndex(), i ) )
									{
										if ( pMaster->WouldNewCPOwnerWinGame( pCurrentPoint, i ) )
										{
											bFinalPointInMap = true;
										}
									}
								}
							}
							else 
							{
								// or this is the last round
								if ( pMaster->NumPlayableControlPointRounds() == 1 )
								{
									CTeamControlPointRound *pRound = pMaster->GetCurrentRound();
									if ( pRound )
									{
										for ( int i = FIRST_GAME_TEAM ; i < MAX_CONTROL_POINT_TEAMS ; i++ )
										{
											if ( ObjectiveResource() && ObjectiveResource()->TeamCanCapPoint( pCurrentPoint->GetPointIndex(), i ) )
											{
												if ( pRound->WouldNewCPOwnerWinGame( pCurrentPoint, i ) )
												{
													bFinalPointInMap = true;
												}
											}
										}
									}
								}
							}
						}

						PlayCaptureAlert( pCurrentPoint, bFinalPointInMap );
					}
				}
			}

			// check to see if we need to start or stop the alarm
			if ( flDistanceToGoal <= TEAM_TRAIN_ALARM_DISTANCE )
			{
				if ( ObjectiveResource() )
				{
					ObjectiveResource()->SetTrackAlarm( GetTeamNumber(), true );
				}

				if ( !bDisableAlarm )
				{
					if ( !m_pAlarm )
					{
						if ( m_iNumCPLinks > 0 && !m_bAlarmPlayed )
						{
							// start the alarm at the final point
							StartCaptureAlarm( m_CPLinks[m_iNumCPLinks-1].hCP.Get() );
							m_bAlarmPlayed = true; // used to prevent the alarm from starting again on maps where the train doesn't recede (alarm loops for short time then only plays singles)
						}
					}
					else
					{
						if ( !m_bTrainCanRecede ) // if the train won't recede, we only want to play the alarm for a short time
						{
							if ( m_flAlarmEndTime > 0 && m_flAlarmEndTime < gpGlobals->curtime )
							{
								StopCaptureAlarm();
								SetContextThink( &CTeamTrainWatcher::WatcherAlarmThink, gpGlobals->curtime + TW_ALARM_THINK_INTERVAL, TW_ALARM_THINK );
							}
						}
					}
				}
			}
			else
			{
				if ( ObjectiveResource() )
				{
					ObjectiveResource()->SetTrackAlarm( GetTeamNumber(), false );
				}

				StopCaptureAlarm();
				m_bAlarmPlayed = false;
			}
		}

		if ( tf_show_train_path.GetBool() )
		{
			CPathTrack *nextNode = NULL;
			CPathTrack *node = m_hStartNode;

			CPathTrack::BeginIteration();
			while( node )
			{
				node->Visit();
				nextNode = node->GetNext();

				if ( !nextNode || nextNode->HasBeenVisited() )
					break;

				NDebugOverlay::Line( node->GetAbsOrigin(), nextNode->GetAbsOrigin(), 255, 255, 0, true, NDEBUG_PERSIST_TILL_NEXT_SERVER );

				node = nextNode;
			}
			CPathTrack::EndIteration();

			// show segment of path train is actually on
			node = pTrain->m_ppath;
			if ( node && node->GetNext() )
			{
				NDebugOverlay::HorzArrow( node->GetAbsOrigin(), node->GetNext()->GetAbsOrigin(), 5.0f, 255, 0, 0, 255, true, NDEBUG_PERSIST_TILL_NEXT_SERVER );
			}
		}
	}

	SetContextThink( &CTeamTrainWatcher::WatcherThink, gpGlobals->curtime + 0.1, TW_THINK );
}