Example #1
0
int CLocalNav::PathTraversable(Vector &vecSource, Vector &vecDest, BOOL fNoMonsters)
{
	TraceResult tr;
	Vector vecSrcTmp;
	Vector vecDestTmp;
	Vector vecDir;
	float flTotal;
	int retval;

	retval = TRAVERSABLE_NO;
	vecSrcTmp = vecSource;
	vecDestTmp = vecDest - vecSource;
	vecDir = vecDestTmp.Normalize();
	vecDir.z = 0;
	flTotal = vecDestTmp.Length2D();

	while (flTotal > 1)
	{
		if (flTotal >= s_flStepSize)
			vecDestTmp = vecSrcTmp + (vecDir * s_flStepSize);
		else
			vecDestTmp = vecDest;

		m_fTargetEntHit = FALSE;

		if (PathClear(vecSrcTmp, vecDestTmp, fNoMonsters, tr))
		{
			vecDestTmp = tr.vecEndPos;

			if (retval == TRAVERSABLE_NO)
				retval = TRAVERSABLE_SLOPE;
		}
		else
		{
			if (tr.fStartSolid)
				return TRAVERSABLE_NO;

			if (tr.pHit && !fNoMonsters && !FStringNull(tr.pHit->v.classname) && FClassnameIs(tr.pHit, "hostage_entity"))
				return TRAVERSABLE_NO;

			vecSrcTmp = tr.vecEndPos;

			if (tr.vecPlaneNormal.z > 0.7)
			{
				if (SlopeTraversable(vecSrcTmp, vecDestTmp, fNoMonsters, tr))
				{
					if (retval == TRAVERSABLE_NO)
						retval = TRAVERSABLE_SLOPE;
				}
				else
					return TRAVERSABLE_NO;
			}
			else
			{
				if (StepTraversable(vecSrcTmp, vecDestTmp, fNoMonsters, tr))
				{
					if (retval == TRAVERSABLE_NO)
						retval = TRAVERSABLE_STEP;
				}
				else if (StepJumpable(vecSrcTmp, vecDestTmp, fNoMonsters, tr))
				{
					if (retval == TRAVERSABLE_NO)
						retval = TRAVERSABLE_STEPJUMPABLE;
				}
				else
					return TRAVERSABLE_NO;
			}
		}

		if (PathClear(vecDestTmp, vecDestTmp - Vector(0, 0, 300), fNoMonsters, tr))
			return TRAVERSABLE_NO;

		if (!tr.fStartSolid)
			vecDestTmp = tr.vecEndPos;

		vecSrcTmp = vecDestTmp;

		if (!m_fTargetEntHit)
			flTotal = (vecDest - vecDestTmp).Length2D();
		else
			flTotal = 0;
	}

	vecDest = vecDestTmp;
	return retval;
}
//-----------------------------------------------------------------------------
// Client-side obstacle avoidance
//-----------------------------------------------------------------------------
void C_BaseHLPlayer::PerformClientSideObstacleAvoidance( float flFrameTime, CUserCmd *pCmd )
{
	// Don't avoid if noclipping or in movetype none
	switch ( GetMoveType() )
	{
	case MOVETYPE_NOCLIP:
	case MOVETYPE_NONE:
	case MOVETYPE_OBSERVER:
		return;
	default:
		break;
	}

	// Try to steer away from any objects/players we might interpenetrate
	Vector size = WorldAlignSize();

	float radius = 0.7f * sqrt( size.x * size.x + size.y * size.y );
	float curspeed = GetLocalVelocity().Length2D();

	//int slot = 1;
	//engine->Con_NPrintf( slot++, "speed %f\n", curspeed );
	//engine->Con_NPrintf( slot++, "radius %f\n", radius );

	// If running, use a larger radius
	float factor = 1.0f;

	if ( curspeed > 150.0f )
	{
		curspeed = MIN( 2048.0f, curspeed );
		factor = ( 1.0f + ( curspeed - 150.0f ) / 150.0f );

		//engine->Con_NPrintf( slot++, "scaleup (%f) to radius %f\n", factor, radius * factor );

		radius = radius * factor;
	}

	Vector currentdir;
	Vector rightdir;

	QAngle vAngles = pCmd->viewangles;
	vAngles.x = 0;

	AngleVectors( vAngles, &currentdir, &rightdir, NULL );
		
	bool istryingtomove = false;
	bool ismovingforward = false;
	if ( fabs( pCmd->forwardmove ) > 0.0f || 
		fabs( pCmd->sidemove ) > 0.0f )
	{
		istryingtomove = true;
		if ( pCmd->forwardmove > 1.0f )
		{
			ismovingforward = true;
		}
	}

	if ( istryingtomove == true )
		 radius *= 1.3f;

	CPlayerAndObjectEnumerator avoid( radius );
	partition->EnumerateElementsInSphere( PARTITION_CLIENT_SOLID_EDICTS, GetAbsOrigin(), radius, false, &avoid );

	// Okay, decide how to avoid if there's anything close by
	int c = avoid.GetObjectCount();
	if ( c <= 0 )
		return;

	//engine->Con_NPrintf( slot++, "moving %s forward %s\n", istryingtomove ? "true" : "false", ismovingforward ? "true" : "false"  );

	float adjustforwardmove = 0.0f;
	float adjustsidemove	= 0.0f;

	for ( int i = 0; i < c; i++ )
	{
		C_AI_BaseNPC *obj = dynamic_cast< C_AI_BaseNPC *>(avoid.GetObject( i ));

		if( !obj )
			continue;

		Vector vecToObject = obj->GetAbsOrigin() - GetAbsOrigin();

		float flDist = vecToObject.Length2D();
		
		// Figure out a 2D radius for the object
		Vector vecWorldMins, vecWorldMaxs;
		obj->CollisionProp()->WorldSpaceAABB( &vecWorldMins, &vecWorldMaxs );
		Vector objSize = vecWorldMaxs - vecWorldMins;

		float objectradius = 0.5f * sqrt( objSize.x * objSize.x + objSize.y * objSize.y );

		//Don't run this code if the NPC is not moving UNLESS we are in stuck inside of them.
		if ( !obj->IsMoving() && flDist > objectradius )
			  continue;

		if ( flDist > objectradius && obj->IsEffectActive( EF_NODRAW ) )
		{
			obj->RemoveEffects( EF_NODRAW );
		}

		Vector vecNPCVelocity;
		obj->EstimateAbsVelocity( vecNPCVelocity );
		float flNPCSpeed = VectorNormalize( vecNPCVelocity );

		Vector vPlayerVel = GetAbsVelocity();
		VectorNormalize( vPlayerVel );

		float flHit1, flHit2;
		Vector vRayDir = vecToObject;
		VectorNormalize( vRayDir );

		float flVelProduct = DotProduct( vecNPCVelocity, vPlayerVel );
		float flDirProduct = DotProduct( vRayDir, vPlayerVel );

		if ( !IntersectInfiniteRayWithSphere(
				GetAbsOrigin(),
				vRayDir,
				obj->GetAbsOrigin(),
				radius,
				&flHit1,
				&flHit2 ) )
			continue;

        Vector dirToObject = -vecToObject;
		VectorNormalize( dirToObject );

		float fwd = 0;
		float rt = 0;

		float sidescale = 2.0f;
		float forwardscale = 1.0f;
		bool foundResult = false;

		Vector vMoveDir = vecNPCVelocity;
		if ( flNPCSpeed > 0.001f )
		{
			// This NPC is moving. First try deflecting the player left or right relative to the NPC's velocity.
			// Start with whatever side they're on relative to the NPC's velocity.
			Vector vecNPCTrajectoryRight = CrossProduct( vecNPCVelocity, Vector( 0, 0, 1) );
			int iDirection = ( vecNPCTrajectoryRight.Dot( dirToObject ) > 0 ) ? 1 : -1;
			for ( int nTries = 0; nTries < 2; nTries++ )
			{
				Vector vecTryMove = vecNPCTrajectoryRight * iDirection;
				VectorNormalize( vecTryMove );
				
				Vector vTestPosition = GetAbsOrigin() + vecTryMove * radius * 2;

				if ( TestMove( vTestPosition, size.z * 2, radius * 2, obj->GetAbsOrigin(), vMoveDir ) )
				{
					fwd = currentdir.Dot( vecTryMove );
					rt = rightdir.Dot( vecTryMove );
					
					//Msg( "PUSH DEFLECT fwd=%f, rt=%f\n", fwd, rt );
					
					foundResult = true;
					break;
				}
				else
				{
					// Try the other direction.
					iDirection *= -1;
				}
			}
		}
		else
		{
			// the object isn't moving, so try moving opposite the way it's facing
			Vector vecNPCForward;
			obj->GetVectors( &vecNPCForward, NULL, NULL );
			
			Vector vTestPosition = GetAbsOrigin() - vecNPCForward * radius * 2;
			if ( TestMove( vTestPosition, size.z * 2, radius * 2, obj->GetAbsOrigin(), vMoveDir ) )
			{
				fwd = currentdir.Dot( -vecNPCForward );
				rt = rightdir.Dot( -vecNPCForward );

				if ( flDist < objectradius )
				{
					obj->AddEffects( EF_NODRAW );
				}

				//Msg( "PUSH AWAY FACE fwd=%f, rt=%f\n", fwd, rt );

				foundResult = true;
			}
		}

		if ( !foundResult )
		{
			// test if we can move in the direction the object is moving
			Vector vTestPosition = GetAbsOrigin() + vMoveDir * radius * 2;
			if ( TestMove( vTestPosition, size.z * 2, radius * 2, obj->GetAbsOrigin(), vMoveDir ) )
			{
				fwd = currentdir.Dot( vMoveDir );
				rt = rightdir.Dot( vMoveDir );

				if ( flDist < objectradius )
				{
					obj->AddEffects( EF_NODRAW );
				}

				//Msg( "PUSH ALONG fwd=%f, rt=%f\n", fwd, rt );

				foundResult = true;
			}
			else
			{
				// try moving directly away from the object
				Vector vTestPosition = GetAbsOrigin() - dirToObject * radius * 2;
				if ( TestMove( vTestPosition, size.z * 2, radius * 2, obj->GetAbsOrigin(), vMoveDir ) )
				{
					fwd = currentdir.Dot( -dirToObject );
					rt = rightdir.Dot( -dirToObject );
					foundResult = true;

					//Msg( "PUSH AWAY fwd=%f, rt=%f\n", fwd, rt );
				}
			}
		}

		if ( !foundResult )
		{
			// test if we can move through the object
			Vector vTestPosition = GetAbsOrigin() - vMoveDir * radius * 2;
			fwd = currentdir.Dot( -vMoveDir );
			rt = rightdir.Dot( -vMoveDir );

			if ( flDist < objectradius )
			{
				obj->AddEffects( EF_NODRAW );
			}

			//Msg( "PUSH THROUGH fwd=%f, rt=%f\n", fwd, rt );

			foundResult = true;
		}

		// If running, then do a lot more sideways veer since we're not going to do anything to
		//  forward velocity
		if ( istryingtomove )
		{
			sidescale = 6.0f;
		}

		if ( flVelProduct > 0.0f && flDirProduct > 0.0f )
		{
			sidescale = 0.1f;
		}

		float force = 1.0f;
		float forward = forwardscale * fwd * force * AVOID_SPEED;
		float side = sidescale * rt * force * AVOID_SPEED;

		adjustforwardmove	+= forward;
		adjustsidemove		+= side;
	}

	pCmd->forwardmove	+= adjustforwardmove;
	pCmd->sidemove		+= adjustsidemove;
	
	// Clamp the move to within legal limits, preserving direction. This is a little
	// complicated because we have different limits for forward, back, and side

	//Msg( "PRECLAMP: forwardmove=%f, sidemove=%f\n", pCmd->forwardmove, pCmd->sidemove );

	float flForwardScale = 1.0f;
	if ( pCmd->forwardmove > fabs( cl_forwardspeed.GetFloat() ) )
	{
		flForwardScale = fabs( cl_forwardspeed.GetFloat() ) / pCmd->forwardmove;
	}
	else if ( pCmd->forwardmove < -fabs( cl_backspeed.GetFloat() ) )
	{
		flForwardScale = fabs( cl_backspeed.GetFloat() ) / fabs( pCmd->forwardmove );
	}
	
	float flSideScale = 1.0f;
	if ( fabs( pCmd->sidemove ) > fabs( cl_sidespeed.GetFloat() ) )
	{
		flSideScale = fabs( cl_sidespeed.GetFloat() ) / fabs( pCmd->sidemove );
	}
	
	float flScale = MIN( flForwardScale, flSideScale );
	pCmd->forwardmove *= flScale;
	pCmd->sidemove *= flScale;

	//Msg( "POSTCLAMP: forwardmove=%f, sidemove=%f\n", pCmd->forwardmove, pCmd->sidemove );
}
Example #3
0
/**
 * Compute a point a fixed distance ahead along our path.
 * Returns path index just after point.
 */
int CNavPathFollower::FindPathPoint( float aheadRange, Vector *point, int *prevIndex )
{
	// find path index just past aheadRange
	int afterIndex;

	// finds the closest point on local area of path, and returns the path index just prior to it
	Vector close;
	int startIndex = FindOurPositionOnPath( &close, true );

	if (prevIndex)
		*prevIndex = startIndex;

	if (startIndex <= 0)
	{
		// went off the end of the path
		// or next point in path is unwalkable (ie: jump-down)
		// keep same point
		return m_segmentIndex;
	}

	// if we are crouching, just follow the path exactly
	if (m_improv->IsCrouching())
	{
		// we want to move to the immediately next point along the path from where we are now
		int index = startIndex+1;
		if (index >= m_path->GetSegmentCount())
			index = m_path->GetSegmentCount()-1;

		*point = (*m_path)[ index ]->pos;

		// if we are very close to the next point in the path, skip ahead to the next one to avoid wiggling
		// we must do a 2D check here, in case the goal point is floating in space due to jump down, etc
		const float closeEpsilon = 20.0f;	// 10
		while ((*point - close).Make2D().IsLengthLessThan( closeEpsilon ))
		{
			++index;

			if (index >= m_path->GetSegmentCount())
			{
				index = m_path->GetSegmentCount()-1;
				break;
			}

			*point = (*m_path)[ index ]->pos;
		}

		return index;
	}

	// make sure we use a node a minimum distance ahead of us, to avoid wiggling 
	while (startIndex < m_path->GetSegmentCount()-1)
	{
		Vector pos = (*m_path)[ startIndex+1 ]->pos;

		// we must do a 2D check here, in case the goal point is floating in space due to jump down, etc
		const float closeEpsilon = 20.0f;
		if ((pos - close).Make2D().IsLengthLessThan( closeEpsilon ))
		{
			++startIndex;
		}
		else
		{
			break;
		}
	}

	// if we hit a ladder or jump area, must stop (dont use ladder behind us)
	if (startIndex > m_segmentIndex && startIndex < m_path->GetSegmentCount() && 
			((*m_path)[ startIndex ]->ladder || (*m_path)[ startIndex ]->area->GetAttributes() & NAV_JUMP))
	{
		*point = (*m_path)[ startIndex ]->pos;
		return startIndex;
	}

	// we need the point just *ahead* of us
	++startIndex;
	if (startIndex >= m_path->GetSegmentCount())
		startIndex = m_path->GetSegmentCount()-1;

	// if we hit a ladder or jump area, must stop
	if (startIndex < m_path->GetSegmentCount() && 
		((*m_path)[ startIndex ]->ladder || (*m_path)[ startIndex ]->area->GetAttributes() & NAV_JUMP))
	{
		*point = (*m_path)[ startIndex ]->pos;
		return startIndex;
	}

	// note direction of path segment we are standing on
	Vector initDir = (*m_path)[ startIndex ]->pos - (*m_path)[ startIndex-1 ]->pos;
	initDir.NormalizeInPlace();

	Vector feet = m_improv->GetFeet();
	Vector eyes = m_improv->GetEyes();
	float rangeSoFar = 0;

	// this flag is true if our ahead point is visible
	bool visible = true;

	Vector prevDir = initDir;

	// step along the path until we pass aheadRange
	bool isCorner = false;
	int i;
	for( i=startIndex; i<m_path->GetSegmentCount(); ++i )
	{
		Vector pos = (*m_path)[i]->pos;
		Vector to = pos - (*m_path)[i-1]->pos;
		Vector dir = to.Normalize();

		// don't allow path to double-back from our starting direction (going upstairs, down curved passages, etc)
		if (DotProduct( dir, initDir ) < 0.0f) // -0.25f
		{
			--i;
			break;
		}

		// if the path turns a corner, we want to move towards the corner, not into the wall/stairs/etc
		if (DotProduct( dir, prevDir ) < 0.5f)
		{
			isCorner = true;
			--i;
			break;
		}
		prevDir = dir;

		// don't use points we cant see
		Vector probe = pos + Vector( 0, 0, HalfHumanHeight );
		if (!IsWalkableTraceLineClear( eyes, probe, WALK_THRU_BREAKABLES ))
		{
			// presumably, the previous point is visible, so we will interpolate
			visible = false;
			break;
		}

		// if we encounter a ladder or jump area, we must stop
		if (i < m_path->GetSegmentCount() && 
			((*m_path)[ i ]->ladder || (*m_path)[ i ]->area->GetAttributes() & NAV_JUMP))
			break;

		// Check straight-line path from our current position to this position
		// Test for un-jumpable height change, or unrecoverable fall
		//if (!IsStraightLinePathWalkable( &pos ))
		//{
		//	--i;
		//	break;
		//}

		Vector along = (i == startIndex) ? (pos - feet) : (pos - (*m_path)[i-1]->pos);
		rangeSoFar += along.Length2D();

		// stop if we have gone farther than aheadRange
		if (rangeSoFar >= aheadRange)
			break;
	}

	if (i < startIndex)
		afterIndex = startIndex;
	else if (i < m_path->GetSegmentCount())
		afterIndex = i;
	else
		afterIndex = m_path->GetSegmentCount()-1;


	// compute point on the path at aheadRange
	if (afterIndex == 0)
	{
		*point = (*m_path)[0]->pos;
	}
	else
	{
		// interpolate point along path segment
		const Vector *afterPoint = &(*m_path)[ afterIndex ]->pos;
		const Vector *beforePoint = &(*m_path)[ afterIndex-1 ]->pos;

		Vector to = *afterPoint - *beforePoint;
		float length = to.Length2D();

		float t = 1.0f - ((rangeSoFar - aheadRange) / length);

		if (t < 0.0f)
			t = 0.0f;
		else if (t > 1.0f)
			t = 1.0f;

		*point = *beforePoint + t * to;

		// if afterPoint wasn't visible, slide point backwards towards beforePoint until it is
		if (!visible)
		{
			const float sightStepSize = 25.0f;
			float dt = sightStepSize / length;

			Vector probe = *point + Vector( 0, 0, HalfHumanHeight );
			while( t > 0.0f && !IsWalkableTraceLineClear( eyes,  probe, WALK_THRU_BREAKABLES ) )
			{
				t -= dt;
				*point = *beforePoint + t * to;
			}

			if (t <= 0.0f)
				*point = *beforePoint;
		}
	}

	// if position found is too close to us, or behind us, force it farther down the path so we don't stop and wiggle
	if (!isCorner)
	{
		const float epsilon = 50.0f;
		Vector2D toPoint;
		Vector2D centroid( m_improv->GetCentroid().x, m_improv->GetCentroid().y );
		
		toPoint.x = point->x - centroid.x;
		toPoint.y = point->y - centroid.y;

		if (DotProduct( toPoint, initDir.Make2D() ) < 0.0f || toPoint.IsLengthLessThan( epsilon ))
		{
			int i;
			for( i=startIndex; i<m_path->GetSegmentCount(); ++i )
			{
				toPoint.x = (*m_path)[i]->pos.x - centroid.x;
				toPoint.y = (*m_path)[i]->pos.y - centroid.y;
				if ((*m_path)[i]->ladder || (*m_path)[i]->area->GetAttributes() & NAV_JUMP || toPoint.IsLengthGreaterThan( epsilon ))
				{
					*point = (*m_path)[i]->pos;
					startIndex = i;
					break;
				}
			}

			if (i == m_path->GetSegmentCount())
			{
				*point = m_path->GetEndpoint();
				startIndex = m_path->GetSegmentCount()-1;
			}
		}
	}

	// m_pathIndex should always be the next point on the path, even if we're not moving directly towards it
	if (startIndex < m_path->GetSegmentCount())
		return startIndex;

	return m_path->GetSegmentCount()-1;
}
void CAI_BlendedMotor::BuildVelocityScript( const AILocalMoveGoal_t &move )
{
	int i;
	float a;

	float idealVelocity = GetIdealSpeed();
	if (idealVelocity == 0)
	{
		idealVelocity = 50;
	}

	float idealAccel = GetIdealAccel();
	if (idealAccel == 0)
	{
		idealAccel = 100;
	}

	AI_Movementscript_t script;

	// set current location as start of script
	script.vecLocation = GetAbsOrigin();
	script.flMaxVelocity = GetCurSpeed();
	m_scriptMove.AddToTail( script );

	//-------------------------

	extern ConVar *npc_height_adjust;
	if (npc_height_adjust->GetBool() && move.bHasTraced && move.directTrace.flTotalDist != move.thinkTrace.flTotalDist)
	{
		float flDist = (move.directTrace.vEndPosition - m_scriptMove[0].vecLocation).Length2D();
		float flHeight = move.directTrace.vEndPosition.z - m_scriptMove[0].vecLocation.z;
		float flDelta;

		if (flDist > 0)
		{
			flDelta = flHeight / flDist;
		}
		else
		{
			flDelta = 0;
		}

		m_flPredictiveSpeedAdjust = 1.1 - fabs( flDelta );
		m_flPredictiveSpeedAdjust = clamp( m_flPredictiveSpeedAdjust, (flHeight > 0.0) ? 0.5 : 0.8, 1.0 );

		/*
		if ((GetOuter()->m_debugOverlays & OVERLAY_NPC_SELECTED_BIT))
		{
			Msg("m_flPredictiveSpeedAdjust %.3f  %.1f %.1f\n", m_flPredictiveSpeedAdjust, flHeight, flDist );
			NDebugOverlay::Box( move.directTrace.vEndPosition, Vector( -2, -2, -2 ), Vector( 2, 2, 2 ), 0,255,255, 0, 0.12 );
		}
		*/
	}
	if (npc_height_adjust->GetBool())
	{
		float flDist = (move.thinkTrace.vEndPosition - m_vecPrevOrigin2).Length2D();
		float flHeight = move.thinkTrace.vEndPosition.z - m_vecPrevOrigin2.z;
		float flDelta;

		if (flDist > 0)
		{
			flDelta = flHeight / flDist;
		}
		else
		{
			flDelta = 0;
		}

		float newSpeedAdjust = 1.1 - fabs( flDelta );
		newSpeedAdjust = clamp( newSpeedAdjust, (flHeight > 0.0) ? 0.5 : 0.8, 1.0 );

		// debounce speed adjust
		if (newSpeedAdjust < m_flReactiveSpeedAdjust)
		{
			m_flReactiveSpeedAdjust = m_flReactiveSpeedAdjust * 0.2 + newSpeedAdjust * 0.8;
		}
		else
		{
			m_flReactiveSpeedAdjust = m_flReactiveSpeedAdjust * 0.5 + newSpeedAdjust * 0.5;
		}

		// filter through origins
		m_vecPrevOrigin2 = m_vecPrevOrigin1;
		m_vecPrevOrigin1 = GetAbsOrigin();

		/*
		if ((GetOuter()->m_debugOverlays & OVERLAY_NPC_SELECTED_BIT))
		{
			NDebugOverlay::Box( m_vecPrevOrigin2, Vector( -2, -2, -2 ), Vector( 2, 2, 2 ), 255,0,255, 0, 0.12 );
			NDebugOverlay::Box( move.thinkTrace.vEndPosition, Vector( -2, -2, -2 ), Vector( 2, 2, 2 ), 255,0,255, 0, 0.12 );
			Msg("m_flReactiveSpeedAdjust %.3f  %.1f %.1f\n", m_flReactiveSpeedAdjust, flHeight, flDist );
		}
		*/
	}

	idealVelocity = idealVelocity * min( m_flReactiveSpeedAdjust, m_flPredictiveSpeedAdjust );

	//-------------------------

	bool bAddedExpected = false;

	// add all waypoint locations and velocities
	AI_Waypoint_t *pCurWaypoint = GetNavigator()->GetPath()->GetCurWaypoint();

	// there has to be at least one waypoint
	Assert( pCurWaypoint );

	while (pCurWaypoint && (pCurWaypoint->NavType() == NAV_GROUND || pCurWaypoint->NavType() == NAV_FLY) /*&& flTotalDist / idealVelocity < 3.0*/) // limit lookahead to 3 seconds
	{
		script.Init();
		AI_Waypoint_t *pNext = pCurWaypoint->GetNext();

		if (ai_path_adjust_speed_on_immediate_turns->GetBool() && !bAddedExpected)
		{
			// hack in next expected immediate location for move
			script.vecLocation = GetAbsOrigin() + move.dir * move.curExpectedDist;
			bAddedExpected = true;
			pNext = pCurWaypoint;
		}
		else
		{
			script.vecLocation = pCurWaypoint->vecLocation;
			script.pWaypoint = pCurWaypoint;
		}

		//DevMsg("waypoint %.1f %.1f %.1f\n", script.vecLocation.x, script.vecLocation.y, script.vecLocation.z );

		if (pNext)
		{
			switch( pNext->NavType())
			{
			case NAV_GROUND:
			case NAV_FLY:
				{
					Vector d1 = pNext->vecLocation - script.vecLocation;
					Vector d2 = script.vecLocation - m_scriptMove[m_scriptMove.Count()-1].vecLocation;
					
					// remove very short, non terminal ground links
					// FIXME: is this safe?  Maybe just check for co-located ground points?
					if (d1.Length2D() < 1.0)
					{
						/*
						if (m_scriptMove.Count() > 1)
						{
							int i = m_scriptMove.Count() - 1;
							m_scriptMove[i].vecLocation = pCurWaypoint->vecLocation;
							m_scriptMove[i].pWaypoint = pCurWaypoint;
						}
						*/
						pCurWaypoint = pNext;
						continue;
					}

					d1.z = 0;
					VectorNormalize( d1 );
					d2.z = 0;
					VectorNormalize( d2 );

					// figure velocity
					float dot = (DotProduct( d1, d2 ) + 0.2);
					if (dot > 0)
					{
						dot = clamp( dot, 0.0f, 1.0f );
						script.flMaxVelocity = idealVelocity * dot;
					}
					else
					{
						script.flMaxVelocity = 0;
					}
				}
				break;
			case NAV_JUMP:

				// FIXME: information about what the jump should look like isn't stored in the waypoints
				// this'll need to call 
				//    GetMoveProbe()->MoveLimit( NAV_JUMP, GetLocalOrigin(), GetPath()->CurWaypointPos(), MASK_NPCSOLID, GetNavTargetEntity(), &moveTrace );
				// to get how far/fast the jump will be, but this is also stateless, so it'd call it per frame.
				// So far it's not clear that the moveprobe doesn't also call this.....

				{
					float minJumpHeight = 0;
					float maxHorzVel = max( GetCurSpeed(), 100 );
					float gravity = sv_gravity->GetFloat() * GetOuter()->GetGravity();
					Vector vecApex;
					Vector rawJumpVel = GetMoveProbe()->CalcJumpLaunchVelocity(script.vecLocation, pNext->vecLocation, gravity, &minJumpHeight, maxHorzVel, &vecApex );

					script.flMaxVelocity = rawJumpVel.Length2D();
					// Msg("%.1f\n", script.flMaxVelocity );
				}
				break;
			case NAV_CLIMB:
				{
					/*
					CAI_Node *pClimbNode = GetNavigator()->GetNetwork()->GetNode(pNext->iNodeID);

					check: pClimbNode->m_eNodeInfo
						bits_NODE_CLIMB_BOTTOM, 
						bits_NODE_CLIMB_ON, 
						bits_NODE_CLIMB_OFF_FORWARD, 
						bits_NODE_CLIMB_OFF_LEFT, 
						bits_NODE_CLIMB_OFF_RIGHT
					*/

					script.flMaxVelocity = 0;
				}
				break;
			/*
			case NAV_FLY:
				// FIXME: can there be a NAV_GROUND -> NAV_FLY transition?
				script.flMaxVelocity = 0;
				break;
			*/
			default:
				break;
			}
		}
		else
		{
			script.flMaxVelocity = GetNavigator()->GetArrivalSpeed();
			// Assert( script.flMaxVelocity == 0 );
		}

		m_scriptMove.AddToTail( script );
		pCurWaypoint = pNext;
	}


	//-------------------------

	// update distances
	float flTotalDist = 0;
	for (i = 0; i < m_scriptMove.Count() - 1; i++ )
	{
		flTotalDist += m_scriptMove[i].flDist = (m_scriptMove[i+1].vecLocation - m_scriptMove[i].vecLocation).Length2D();
	}

	//-------------------------

	if ( !m_bDeceleratingToGoal && m_scriptMove.Count() && flTotalDist > 0 )
	{
		float flNeededAccel = DeltaV( m_scriptMove[0].flMaxVelocity, m_scriptMove[m_scriptMove.Count() - 1].flMaxVelocity, flTotalDist );
		m_bDeceleratingToGoal =  (flNeededAccel < -idealAccel);
		//Assert( flNeededAccel != idealAccel);
	}

	//-------------------------

	// insert slowdown points due to blocking
	if (ai_path_insert_pause_at_obstruction->GetBool() && move.directTrace.pObstruction)
	{
		float distToObstruction = (move.directTrace.vEndPosition - m_scriptMove[0].vecLocation).Length2D();

		// HACK move obstruction out "stepsize" to account for it being based on stand position and not a trace
		distToObstruction = distToObstruction + 16;

		InsertSlowdown( distToObstruction, idealAccel, false );
	}

	if (ai_path_insert_pause_at_est_end->GetBool() && GetNavigator()->GetArrivalDistance() > 0.0)
	{
		InsertSlowdown( flTotalDist - GetNavigator()->GetArrivalDistance(), idealAccel, true );
	}

	// calc initial velocity based on immediate direction changes
	if ( ai_path_adjust_speed_on_immediate_turns->GetBool() && m_scriptMove.Count() > 1)
	{
		/*
		if ((GetOuter()->m_debugOverlays & OVERLAY_NPC_SELECTED_BIT))
		{
			Vector tmp = m_scriptMove[1].vecLocation - m_scriptMove[0].vecLocation;
			VectorNormalize( tmp );
			NDebugOverlay::Line( m_scriptMove[0].vecLocation + Vector( 0, 0, 10 ), m_scriptMove[0].vecLocation + tmp * 32 + Vector( 0, 0, 10 ), 255,255,255, true, 0.1 );
			
			NDebugOverlay::Line( m_scriptMove[0].vecLocation + Vector( 0, 0, 10 ), m_scriptMove[1].vecLocation + Vector( 0, 0, 10 ), 255,0,0, true, 0.1 );

			tmp = GetCurVel();
			VectorNormalize( tmp );
			NDebugOverlay::Line( m_scriptMove[0].vecLocation + Vector( 0, 0, 10 ), m_scriptMove[0].vecLocation + tmp * 32 + Vector( 0, 0, 10 ), 0,0,255, true, 0.1 );
		}
		*/

		Vector d1 = m_scriptMove[1].vecLocation - m_scriptMove[0].vecLocation;
		d1.z = 0;
		VectorNormalize( d1 );

		Vector d2 = GetCurVel();
		d2.z = 0;
		VectorNormalize( d2 );

		float dot = (DotProduct( d1, d2 ) + MIN_STEER_DOT);
		dot = clamp( dot, 0.0f, 1.0f );
		m_scriptMove[0].flMaxVelocity = m_scriptMove[0].flMaxVelocity * dot;
	}

	// clamp forward velocities
	for (i = 0; i < m_scriptMove.Count() - 1; i++ )
	{
		// find needed acceleration
		float dv = m_scriptMove[i+1].flMaxVelocity - m_scriptMove[i].flMaxVelocity;

		if (dv > 0.0)
		{
			// find time, distance to accel to next max vel
			float t1 = dv / idealAccel;
			float d1 = m_scriptMove[i].flMaxVelocity * t1 + 0.5 * (idealAccel) * t1 * t1;

			// is there enough distance
			if (d1 > m_scriptMove[i].flDist)
			{
				float r1, r2;

				// clamp the next velocity to the possible accel in the given distance
				if (SolveQuadratic( 0.5 * idealAccel, m_scriptMove[i].flMaxVelocity, -m_scriptMove[i].flDist, r1, r2 ))
				{
					m_scriptMove[i+1].flMaxVelocity = m_scriptMove[i].flMaxVelocity + idealAccel * r1;
				}
			}
		}
	}

	// clamp decel velocities
	for (i = m_scriptMove.Count() - 1; i > 0; i-- )
	{
		// find needed deceleration
		float dv = m_scriptMove[i].flMaxVelocity - m_scriptMove[i-1].flMaxVelocity;

		if (dv < 0.0)
		{
			// find time, distance to decal to next max vel
			float t1 = -dv / idealAccel;
			float d1 = m_scriptMove[i].flMaxVelocity * t1 + 0.5 * (idealAccel) * t1 * t1;

			// is there enough distance
			if (d1 > m_scriptMove[i-1].flDist)
			{
				float r1, r2;
				
				// clamp the next velocity to the possible decal in the given distance
				if (SolveQuadratic( 0.5 * idealAccel, m_scriptMove[i].flMaxVelocity, -m_scriptMove[i-1].flDist, r1, r2 ))
				{
					m_scriptMove[i-1].flMaxVelocity = m_scriptMove[i].flMaxVelocity + idealAccel * r1;
				}
			}
		}
	}

	/*
	for (i = 0; i < m_scriptMove.Count(); i++)
	{
		NDebugOverlay::Text( m_scriptMove[i].vecLocation, (const char *)CFmtStr( "%.2f ", m_scriptMove[i].flMaxVelocity  ), false, 0.1 );
		// DevMsg("%.2f ", m_scriptMove[i].flMaxVelocity );
	}
	// DevMsg("\n");
	*/

	// insert intermediate ideal velocities
	for (i = 0; i < m_scriptMove.Count() - 1;)
	{
		// accel to ideal
		float t1 = (idealVelocity - m_scriptMove[i].flMaxVelocity) / idealAccel;
		float d1 = m_scriptMove[i].flMaxVelocity * t1 + 0.5 * (idealAccel) * t1 * t1;

		// decel from ideal
		float t2 = (idealVelocity - m_scriptMove[i+1].flMaxVelocity) / idealAccel;
		float d2 = m_scriptMove[i+1].flMaxVelocity * t2 + 0.5 * (idealAccel) * t2 * t2;

		m_scriptMove[i].flDist = (m_scriptMove[i+1].vecLocation - m_scriptMove[i].vecLocation).Length2D();

		// is it possible to accel and decal to idealVelocity between next two nodes
		if (d1 + d2 < m_scriptMove[i].flDist)
		{
			Vector start =  m_scriptMove[i].vecLocation;
			Vector end = m_scriptMove[i+1].vecLocation;
			float dist = m_scriptMove[i].flDist;

			// insert the two points needed to end accel and start decel
			if (d1 > 1.0 && t1 > 0.1)
			{
				a = d1 / dist;

				script.Init();
				script.vecLocation = end * a + start * (1 - a);
				script.flMaxVelocity = idealVelocity;
				m_scriptMove.InsertAfter( i, script );
				i++;
			}

			if (dist - d2 > 1.0 && t2 > 0.1)
			{
				// DevMsg("%.2f : ", a );

				a = (dist - d2) / dist;

				script.Init();
				script.vecLocation = end * a + start * (1 - a);
				script.flMaxVelocity = idealVelocity;
				m_scriptMove.InsertAfter( i, script );
				i++;
			}

			i++;
		}
		else
		{
			// check to see if the amount of change needed to reach target is less than the ideal acceleration
			float flNeededAccel = fabs( DeltaV( m_scriptMove[i].flMaxVelocity, m_scriptMove[i+1].flMaxVelocity, m_scriptMove[i].flDist ) );
			if (flNeededAccel < idealAccel)
			{
				// if so, they it's possible to get a bit towards the ideal velocity
				float v1 = m_scriptMove[i].flMaxVelocity;
				float v2 = m_scriptMove[i+1].flMaxVelocity;
				float dist = m_scriptMove[i].flDist;

				// based on solving:
				//		v1+A*t1-v2-A*t2=0
				//		v1*t1+0.5*A*t1*t1+v2*t2+0.5*A*t2*t2-D=0

				float tmp = idealAccel*dist+0.5*v1*v1+0.5*v2*v2;
				Assert( tmp >= 0 );
				t1 = (-v1+sqrt( tmp )) / idealAccel;
				t2 = (v1+idealAccel*t1-v2)/idealAccel;

				// if this assert hits, write down the v1, v2, dist, and idealAccel numbers and send them to me (Ken).
				// go ahead the comment it out, it's safe, but I'd like to know a test case where it's happening
				//Assert( t1 > 0 && t2 > 0 );

				// check to make sure it's really worth it
				if (t1 > 0.0 && t2 > 0.0)
				{
					d1 = v1 * t1 + 0.5 * idealAccel * t1 * t1;
					
					/*
					d2 = v2 * t2 + 0.5 * idealAccel * t2 * t2;
					Assert( fabs( d1 + d2 - dist ) < 0.001 );
					*/

					float a = d1 / m_scriptMove[i].flDist;
					script.Init();
					script.vecLocation = m_scriptMove[i+1].vecLocation * a + m_scriptMove[i].vecLocation * (1 - a);
					script.flMaxVelocity = m_scriptMove[i].flMaxVelocity + idealAccel * t1;

					if (script.flMaxVelocity < idealVelocity)
					{
						// DevMsg("insert %.2f %.2f %.2f\n", m_scriptMove[i].flMaxVelocity, script.flMaxVelocity, m_scriptMove[i+1].flMaxVelocity ); 
						m_scriptMove.InsertAfter( i, script );
						i += 1;
					}
				}
			}
			i += 1;
		}
	}

	// clamp min velocities
	for (i = 0; i < m_scriptMove.Count(); i++)
	{
		m_scriptMove[i].flMaxVelocity = max( m_scriptMove[i].flMaxVelocity, MIN_VELOCITY );
	}

	// rebuild fields
	m_scriptMove[0].flElapsedTime = 0;
	for (i = 0; i < m_scriptMove.Count() - 1; )
	{
		m_scriptMove[i].flDist = (m_scriptMove[i+1].vecLocation - m_scriptMove[i].vecLocation).Length2D();

		if (m_scriptMove[i].flMaxVelocity == 0 && m_scriptMove[i+1].flMaxVelocity == 0)
		{
			// force a minimum velocity 
			//CE_assert
			//Assert( 0 );
			m_scriptMove[i+1].flMaxVelocity = 1.0;
		}

		float t = m_scriptMove[i].flDist / (0.5 * (m_scriptMove[i].flMaxVelocity + m_scriptMove[i+1].flMaxVelocity));
		m_scriptMove[i].flTime = t;

		/*
		if (m_scriptMove[i].flDist < 0.01)
		{
			// Assert( m_scriptMove[i+1].pWaypoint == NULL );

			m_scriptMove.Remove( i + 1 );
			continue;
		}
		*/

		m_scriptMove[i+1].flElapsedTime = m_scriptMove[i].flElapsedTime + m_scriptMove[i].flTime;

		i++;
	}

	/*
	for (i = 0; i < m_scriptMove.Count(); i++)
	{
		DevMsg("(%.2f : %.2f : %.2f)", m_scriptMove[i].flMaxVelocity, m_scriptMove[i].flDist, m_scriptMove[i].flTime );
		// DevMsg("(%.2f:%.2f)", m_scriptMove[i].flTime, m_scriptMove[i].flElapsedTime );
	}
	DevMsg("\n");
	*/
}
Example #5
0
// Move along the path. Return false if end of path reached.
CCSBot::PathResult CCSBot::UpdatePathMovement(bool allowSpeedChange)
{
	if (m_pathLength == 0)
		return PATH_FAILURE;

	if (cv_bot_walk.value != 0.0f)
		Walk();

	// If we are navigating a ladder, it overrides all other path movement until complete
	if (UpdateLadderMovement())
		return PROGRESSING;

	// ladder failure can destroy the path
	if (m_pathLength == 0)
		return PATH_FAILURE;

	// we are not supposed to be on a ladder - if we are, jump off
	if (IsOnLadder())
		Jump(MUST_JUMP);

	assert(m_pathIndex < m_pathLength);

	// Check if reached the end of the path
	bool nearEndOfPath = false;
	if (m_pathIndex >= m_pathLength - 1)
	{
		Vector toEnd(pev->origin.x, pev->origin.y, GetFeetZ());
		Vector d = GetPathEndpoint() - toEnd; // can't use 2D because path end may be below us (jump down)

		const float walkRange = 200.0f;

		// walk as we get close to the goal position to ensure we hit it
		if (d.IsLengthLessThan(walkRange))
		{
			// don't walk if crouching - too slow
			if (allowSpeedChange && !IsCrouching())
				Walk();

			// note if we are near the end of the path
			const float nearEndRange = 50.0f;
			if (d.IsLengthLessThan(nearEndRange))
				nearEndOfPath = true;

			const float closeEpsilon = 20.0f;
			if (d.IsLengthLessThan(closeEpsilon))
			{
				// reached goal position - path complete
				DestroyPath();

				// TODO: We should push and pop walk state here, in case we want to continue walking after reaching goal
				if (allowSpeedChange)
					Run();

				return END_OF_PATH;
			}
		}
	}

	// To keep us moving smoothly, we will move towards
	// a point farther ahead of us down our path.
	int prevIndex = 0;				// closest index on path just prior to where we are now
	const float aheadRange = 300.0f;
	int newIndex = FindPathPoint(aheadRange, &m_goalPosition, &prevIndex);

	// BOTPORT: Why is prevIndex sometimes -1?
	if (prevIndex < 0)
		prevIndex = 0;

	// if goal position is near to us, we must be about to go around a corner - so look ahead!
	const float nearCornerRange = 100.0f;
	if (m_pathIndex < m_pathLength - 1 && (m_goalPosition - pev->origin).IsLengthLessThan(nearCornerRange))
	{
		ClearLookAt();
		InhibitLookAround(0.5f);
	}

	// if we moved to a new node on the path, setup movement
	if (newIndex > m_pathIndex)
	{
		SetPathIndex(newIndex);
	}

	if (!IsUsingLadder())
	{
		// Crouching

		// if we are approaching a crouch area, crouch
		// if there are no crouch areas coming up, stand
		const float crouchRange = 50.0f;
		bool didCrouch = false;
		for (int i = prevIndex; i < m_pathLength; i++)
		{
			const CNavArea *to = m_path[i].area;

			// if there is a jump area on the way to the crouch area, don't crouch as it messes up the jump
			// unless we are already higher than the jump area - we must've jumped already but not moved into next area
			if ((to->GetAttributes() & NAV_JUMP)/* && to->GetCenter()->z > GetFeetZ()*/)
				break;

			Vector close;
			to->GetClosestPointOnArea(&pev->origin, &close);

			if ((close - pev->origin).Make2D().IsLengthGreaterThan(crouchRange))
				break;

			if (to->GetAttributes() & NAV_CROUCH)
			{
				Crouch();
				didCrouch = true;
				break;
			}
		}

		if (!didCrouch && !IsJumping())
		{
			// no crouch areas coming up
			StandUp();
		}
		// end crouching logic
	}

	// compute our forward facing angle
	m_forwardAngle = UTIL_VecToYaw(m_goalPosition - pev->origin);

	// Look farther down the path to "lead" our view around corners
	Vector toGoal;

	if (m_pathIndex == 0)
	{
		toGoal = m_path[1].pos;
	}
	else if (m_pathIndex < m_pathLength)
	{
		toGoal = m_path[m_pathIndex].pos - pev->origin;

		// actually aim our view farther down the path
		const float lookAheadRange = 500.0f;
		if (!m_path[m_pathIndex].ladder && !IsNearJump() && toGoal.Make2D().IsLengthLessThan(lookAheadRange))
		{
			float along = toGoal.Length2D();
			int i;
			for (i = m_pathIndex + 1; i < m_pathLength; i++)
			{
				Vector delta = m_path[i].pos - m_path[i - 1].pos;
				float segmentLength = delta.Length2D();

				if (along + segmentLength >= lookAheadRange)
				{
					// interpolate between points to keep look ahead point at fixed distance
					float t = (lookAheadRange - along) / (segmentLength + along);
					Vector target;

					if (t <= 0.0f)
						target = m_path[i - 1].pos;
					else if (t >= 1.0f)
						target = m_path[i].pos;
					else
						target = m_path[i - 1].pos + t * delta;

					toGoal = target - pev->origin;
					break;
				}

				// if we are coming up to a ladder or a jump, look at it
				if (m_path[i].ladder || (m_path[i].area->GetAttributes() & NAV_JUMP))
				{
					toGoal = m_path[i].pos - pev->origin;
					break;
				}

				along += segmentLength;
			}

			if (i == m_pathLength)
			{
				toGoal = GetPathEndpoint() - pev->origin;
			}
		}
	}
	else
	{
		toGoal = GetPathEndpoint() - pev->origin;
	}

	m_lookAheadAngle = UTIL_VecToYaw(toGoal);

	// initialize "adjusted" goal to current goal
	Vector adjustedGoal = m_goalPosition;

	// Use short "feelers" to veer away from close-range obstacles
	// Feelers come from our ankles, just above StepHeight, so we avoid short walls, too
	// Don't use feelers if very near the end of the path, or about to jump
	// TODO: Consider having feelers at several heights to deal with overhangs, etc.
	if (!nearEndOfPath && !IsNearJump() && !IsJumping())
	{
		FeelerReflexAdjustment(&adjustedGoal);
	}

	// draw debug visualization
	if ((cv_bot_traceview.value == 1.0f && IsLocalPlayerWatchingMe()) || cv_bot_traceview.value == 10.0f)
	{
		DrawPath();

		const Vector *pos = &m_path[m_pathIndex].pos;
		UTIL_DrawBeamPoints(*pos, *pos + Vector(0, 0, 50), 1, 255, 255, 0);
		UTIL_DrawBeamPoints(adjustedGoal, adjustedGoal + Vector(0, 0, 50), 1, 255, 0, 255);
		UTIL_DrawBeamPoints(pev->origin, adjustedGoal + Vector(0, 0, 50), 1, 255, 0, 255);
	}

	// dont use adjustedGoal, as it can vary wildly from the feeler adjustment
	if (!IsAttacking() && IsFriendInTheWay(&m_goalPosition))
	{
		if (!m_isWaitingBehindFriend)
		{
			m_isWaitingBehindFriend = true;

			const float politeDuration = 5.0f - 3.0f * GetProfile()->GetAggression();
			m_politeTimer.Start(politeDuration);
		}
		else if (m_politeTimer.IsElapsed())
		{
			// we have run out of patience
			m_isWaitingBehindFriend = false;
			ResetStuckMonitor();

			// repath to avoid clump of friends in the way
			DestroyPath();
		}
	}
	else if (m_isWaitingBehindFriend)
	{
		// we're done waiting for our friend to move
		m_isWaitingBehindFriend = false;
		ResetStuckMonitor();
	}

	// Move along our path if there are no friends blocking our way,
	// or we have run out of patience
	if (!m_isWaitingBehindFriend || m_politeTimer.IsElapsed())
	{
		// Move along path
		MoveTowardsPosition(&adjustedGoal);

		// Stuck check
		if (m_isStuck && !IsJumping())
		{
			Wiggle();
		}
	}

	// if our goal is high above us, we must have fallen
	bool didFall = false;
	if (m_goalPosition.z - GetFeetZ() > JumpCrouchHeight)
	{
		const float closeRange = 75.0f;
		Vector2D to(pev->origin.x - m_goalPosition.x, pev->origin.y - m_goalPosition.y);
		if (to.IsLengthLessThan(closeRange))
		{
			// we can't reach the goal position
			// check if we can reach the next node, in case this was a "jump down" situation
			if (m_pathIndex < m_pathLength - 1)
			{
				if (m_path[m_pathIndex + 1].pos.z - GetFeetZ() > JumpCrouchHeight)
				{
					// the next node is too high, too - we really did fall of the path
					didFall = true;
				}
			}
			else
			{
				// fell trying to get to the last node in the path
				didFall = true;
			}
		}
	}

	// This timeout check is needed if the bot somehow slips way off
	// of its path and cannot progress, but also moves around
	// enough that it never becomes "stuck"
	const float giveUpDuration = 5.0f; // 4.0f
	if (didFall || gpGlobals->time - m_areaEnteredTimestamp > giveUpDuration)
	{
		if (didFall)
		{
			PrintIfWatched("I fell off!\n");
		}

		// if we havent made any progress in a long time, give up
		if (m_pathIndex < m_pathLength - 1)
		{
			PrintIfWatched("Giving up trying to get to area #%d\n", m_path[m_pathIndex].area->GetID());
		}
		else
		{
			PrintIfWatched("Giving up trying to get to end of path\n");
		}

		Run();
		StandUp();
		DestroyPath();

		return PATH_FAILURE;
	}

	return PROGRESSING;
}
Example #6
0
void CSupplier::UpdateTendrils()
{
	if (IsConstructing())
		return;

	TStubbed("Tendrils");
#if 0
	if (!GetPlayerOwner())
	{
		if (m_iTendrilsCallList)
			glDeleteLists((GLuint)m_iTendrilsCallList, 1);

		m_iTendrilsCallList = 0;

		DigitanksGame()->GetTerrain()->DirtyChunkTexturesWithinDistance(GetGlobalOrigin(), GetDataFlowRadius() + GetBoundingRadius());
		return;
	}

	if (GameServer()->IsLoading())
		return;

	bool bUpdateTerrain = false;
	size_t iRadius = (size_t)GetDataFlowRadius();
	while (m_aTendrils.size() < iRadius)
	{
		m_aTendrils.push_back(CTendril());
		CTendril* pTendril = &m_aTendrils[m_aTendrils.size()-1];
		pTendril->m_flLength = (float)m_aTendrils.size() + GetBoundingRadius();
		pTendril->m_vecEndPoint = DigitanksGame()->GetTerrain()->GetPointHeight(GetGlobalOrigin() + AngleVector(EAngle(0, RandomFloat(0, 360), 0)) * pTendril->m_flLength);
		pTendril->m_flScale = RandomFloat(3, 7);
		pTendril->m_flOffset = RandomFloat(0, 1);
		pTendril->m_flSpeed = RandomFloat(0.5f, 2);

		bUpdateTerrain = true;
	}

	if (bUpdateTerrain)
		DigitanksGame()->GetTerrain()->DirtyChunkTexturesWithinDistance(GetGlobalOrigin(), GetDataFlowRadius() + GetBoundingRadius());

	if (m_iTendrilsCallList)
		glDeleteLists((GLuint)m_iTendrilsCallList, 1);

	m_iTendrilsCallList = glGenLists(1);

	Color clrTeam = GetPlayerOwner()->GetColor();
	clrTeam = (Vector(clrTeam) + Vector(1,1,1))/2;

	glNewList((GLuint)m_iTendrilsCallList, GL_COMPILE);
	for (size_t i = 0; i < m_aTendrils.size(); i++)
	{
		// Only show the longest tendrils, for perf reasons.
		if (i < iRadius - 15)
			continue;

		CTendril* pTendril = &m_aTendrils[i];

		Vector vecDestination = pTendril->m_vecEndPoint;

		Vector vecPath = vecDestination - GetGlobalOrigin();
		vecPath.y = 0;

		float flDistance = vecPath.Length2D();
		Vector vecDirection = vecPath.Normalized();
		size_t iSegments = (size_t)(flDistance/3);

		GLuint iScrollingTextureProgram = (GLuint)CShaderLibrary::GetScrollingTextureProgram();

		GLuint flSpeed = glGetUniformLocation(iScrollingTextureProgram, "flSpeed");
		glUniform1f(flSpeed, pTendril->m_flSpeed);

		clrTeam.SetAlpha(105);

		CRopeRenderer oRope(GameServer()->GetRenderer(), s_iTendrilBeam, DigitanksGame()->GetTerrain()->GetPointHeight(GetGlobalOrigin()) + Vector(0, 0, 1), 1.0f);
		oRope.SetColor(clrTeam);
		oRope.SetTextureScale(pTendril->m_flScale);
		oRope.SetTextureOffset(pTendril->m_flOffset);
		oRope.SetForward(Vector(0, 0, -1));

		for (size_t i = 1; i < iSegments; i++)
		{
			clrTeam.SetAlpha((int)RemapVal((float)i, 1, (float)iSegments, 100, 30));
			oRope.SetColor(clrTeam);

			float flCurrentDistance = ((float)i*flDistance)/iSegments;
			oRope.AddLink(DigitanksGame()->GetTerrain()->GetPointHeight(GetGlobalOrigin() + vecDirection*flCurrentDistance) + Vector(0, 0, 1));
		}

		oRope.Finish(DigitanksGame()->GetTerrain()->GetPointHeight(vecDestination) + Vector(0, 0, 1));
	}
	glEndList();
#endif
}
Example #7
0
void CSupplier::PostRender() const
{
	BaseClass::PostRender();

	if (!GameServer()->GetRenderer()->IsRenderingTransparent())
		return;

	float flGrowthTime = (float)(GameServer()->GetGameTime() - m_flTendrilGrowthStartTime);

	if (flGrowthTime < 0)
		return;

	if (m_flTendrilGrowthStartTime == 0)
	{
		DigitanksGame()->GetDigitanksRenderer()->AddTendrilBatch(this);
		return;
	}

	COverheadCamera* pCamera = DigitanksGame()->GetOverheadCamera();
	Vector vecCamera = pCamera->GetGlobalOrigin();
	float flDistanceSqr = GetGlobalOrigin().DistanceSqr(vecCamera);
	float flFadeDistance = tendril_fade_distance.GetFloat();

	float flFadeAlpha = RemapValClamped(flDistanceSqr, flFadeDistance*flFadeDistance, (flFadeDistance+20)*(flFadeDistance+20), 1.0f, 0.0f);

	if (flFadeAlpha <= 0)
		return;

	float flTreeAlpha = 1.0f;
	if (DigitanksGame()->GetTerrain()->GetBit(CTerrain::WorldToArraySpace(GetGlobalOrigin().x), CTerrain::WorldToArraySpace(GetGlobalOrigin().y), TB_TREE))
		flTreeAlpha = 0.3f;

	CRenderingContext r(GameServer()->GetRenderer(), true);
	if (DigitanksGame()->ShouldRenderFogOfWar())
		r.UseFrameBuffer(DigitanksGame()->GetDigitanksRenderer()->GetVisibilityMaskedBuffer());
	r.SetDepthMask(false);
	r.UseMaterial(s_hTendrilBeam);

	r.SetUniform("flTime", (float)GameServer()->GetGameTime());
	r.SetUniform("iTexture", 0);
	r.SetUniform("flAlpha", flFadeAlpha * flTreeAlpha);

	Color clrTeam = GetPlayerOwner()?GetPlayerOwner()->GetColor():Color(255,255,255,255);
	clrTeam = (Vector(clrTeam) + Vector(1,1,1))/2;

	if (m_flTendrilGrowthStartTime > 0)
	{
		float flTotalSize = (float)m_aTendrils.size() + GetBoundingRadius();

		for (size_t i = 0; i < m_aTendrils.size(); i++)
		{
			if (i < m_aTendrils.size() - 15)
				continue;

			const CTendril* pTendril = &m_aTendrils[i];

			float flGrowthLength = RemapVal(flGrowthTime, 0, GROWTH_TIME, pTendril->m_flLength-flTotalSize, pTendril->m_flLength);

			if (flGrowthLength < 0)
				continue;

			Vector vecDestination = GetGlobalOrigin() + (pTendril->m_vecEndPoint - GetGlobalOrigin()).Normalized() * flGrowthLength;

			Vector vecPath = vecDestination - GetGlobalOrigin();
			vecPath.y = 0;

			float flDistance = vecPath.Length2D();
			Vector vecDirection = vecPath.Normalized();
			size_t iSegments = (size_t)(flDistance/3);

			r.SetUniform("flSpeed", pTendril->m_flSpeed);

			clrTeam.SetAlpha(105);

			CRopeRenderer oRope(GameServer()->GetRenderer(), s_hTendrilBeam, DigitanksGame()->GetTerrain()->GetPointHeight(GetGlobalOrigin()) + Vector(0, 0, 1), 1.0f);
			oRope.SetColor(clrTeam);
			oRope.SetTextureScale(pTendril->m_flScale);
			oRope.SetTextureOffset(pTendril->m_flOffset);
			oRope.SetForward(Vector(0, 0, -1));

			for (size_t i = 1; i < iSegments; i++)
			{
				clrTeam.SetAlpha((int)RemapVal((float)i, 1, (float)iSegments, 100, 30));
				oRope.SetColor(clrTeam);

				float flCurrentDistance = ((float)i*flDistance)/iSegments;
				oRope.AddLink(DigitanksGame()->GetTerrain()->GetPointHeight(GetGlobalOrigin() + vecDirection*flCurrentDistance) + Vector(0, 0, 1));
			}

			oRope.Finish(DigitanksGame()->GetTerrain()->GetPointHeight(vecDestination) + Vector(0, 0, 1));
		}
	}
}
Example #8
0
/* <485ecf> ../cstrike/dlls/hostage/hostage_localnav.cpp:472 */
int CLocalNav::PathTraversable(Vector &vecSource, Vector &vecDest, int fNoMonsters)
{
	TraceResult tr;
	Vector vecSrcTmp;
	Vector vecDestTmp;
	Vector vecDir;
	float_precision flTotal;
	int retval = PATH_TRAVERSABLE_EMPTY;

	vecSrcTmp = vecSource;
	vecDestTmp = vecDest - vecSource;

	vecDir = vecDestTmp.NormalizePrecision();
	vecDir.z = 0;

	flTotal = vecDestTmp.Length2D();

	while (flTotal > 1.0)
	{
		if (flTotal >= s_flStepSize)
		{
#ifndef PLAY_GAMEDLL
			vecDestTmp = vecSrcTmp + (vecDir * s_flStepSize);
#else
			// TODO: fix test demo
			vecDestTmp[0] = vecSrcTmp[0] + (vecDir[0] * s_flStepSize);
			vecDestTmp[1] = vecSrcTmp[1] + (float)(vecDir[1] * s_flStepSize);
			vecDestTmp[2] = vecSrcTmp[2] + (vecDir[2] * s_flStepSize);
#endif // PLAY_GAMEDLL

		}
		else
			vecDestTmp = vecDest;

		m_fTargetEntHit = FALSE;

		if (PathClear(vecSrcTmp, vecDestTmp, fNoMonsters, tr))
		{
			vecDestTmp = tr.vecEndPos;

			if (retval == PATH_TRAVERSABLE_EMPTY)
			{
				retval = PATH_TRAVERSABLE_SLOPE;
			}
		}
		else
		{
			if (tr.fStartSolid)
			{
				return PATH_TRAVERSABLE_EMPTY;
			}

			if (tr.pHit && !fNoMonsters && tr.pHit->v.classname)
			{
				if (FClassnameIs(tr.pHit, "hostage_entity"))
				{
					return PATH_TRAVERSABLE_EMPTY;
				}
			}

			vecSrcTmp = tr.vecEndPos;

			if (tr.vecPlaneNormal.z <= 0.7)
			{
				if (StepTraversable(vecSrcTmp, vecDestTmp, fNoMonsters, tr))
				{
					if (retval == PATH_TRAVERSABLE_EMPTY)
					{
						retval = PATH_TRAVERSABLE_STEP;
					}
				}
				else
				{
					if (!StepJumpable(vecSrcTmp, vecDestTmp, fNoMonsters, tr))
					{
						return PATH_TRAVERSABLE_EMPTY;
					}

					if (retval == PATH_TRAVERSABLE_EMPTY)
					{
						retval = PATH_TRAVERSABLE_STEPJUMPABLE;
					}
				}
			}
			else
			{
				if (!SlopeTraversable(vecSrcTmp, vecDestTmp, fNoMonsters, tr))
				{
					return PATH_TRAVERSABLE_EMPTY;
				}

				if (retval == PATH_TRAVERSABLE_EMPTY)
				{
					retval = PATH_TRAVERSABLE_SLOPE;
				}
			}
		}

		Vector vecDropDest = vecDestTmp - Vector(0, 0, 300);

		if (PathClear(vecDestTmp, vecDropDest, fNoMonsters, tr))
		{
			return PATH_TRAVERSABLE_EMPTY;
		}

		if (!tr.fStartSolid)
			vecDestTmp = tr.vecEndPos;

		vecSrcTmp = vecDestTmp;

		BOOL fProgressThisTime = m_fTargetEntHit;
		Vector vecSrcThisTime = vecDest - vecDestTmp;

		if (fProgressThisTime)
			break;

		flTotal = vecSrcThisTime.Length2D();
	}

	vecDest = vecDestTmp;

	return retval;
}
Example #9
0
float CSDKPlayerAnimState::GetOuterXYSpeed()
{
	Vector vel;
	GetOuterAbsVelocity( vel );
	return vel.Length2D();
}
void CSDKPlayer::CheckBallShield(const Vector &oldPos, Vector &newPos, const Vector &oldVel, Vector &newVel, const QAngle &oldAng, QAngle &newAng)
{
	bool stopPlayer = false;
	const float border = (GetFlags() & FL_SHIELD_KEEP_IN) ? -mp_shield_border.GetInt() : mp_shield_border.GetInt();

	int forward;
#ifdef CLIENT_DLL
	forward = GetPlayersTeam(this)->m_nForward;
#else
	forward = GetTeam()->m_nForward;
#endif

	if (SDKGameRules()->m_nShieldType != SHIELD_NONE)
	{
		if (SDKGameRules()->m_nShieldType == SHIELD_GOALKICK || 
			SDKGameRules()->m_nShieldType == SHIELD_PENALTY ||
			SDKGameRules()->m_nShieldType == SHIELD_FREEKICK ||
			(SDKGameRules()->m_nShieldType == SHIELD_KICKOFF && !SDKGameRules()->IsIntermissionState()) ||
			SDKGameRules()->m_nShieldType == SHIELD_CORNER)
		{
			const float radius = mp_shield_ball_radius.GetFloat();
			Vector dir = newPos - SDKGameRules()->m_vShieldPos;

			if (dir.Length2DSqr() < pow(radius, 2))
			{
				dir.z = 0;
				dir.NormalizeInPlace();
				newPos = SDKGameRules()->m_vShieldPos + dir * radius;
				stopPlayer = true;
			}
		}

		if (SDKGameRules()->m_nShieldType == SHIELD_GOALKICK || 
			SDKGameRules()->m_nShieldType == SHIELD_PENALTY ||
			SDKGameRules()->m_nShieldType == SHIELD_KEEPERHANDS)
		{
			int side = (SDKGameRules()->m_nShieldType == SHIELD_PENALTY ? GetGlobalTeam(SDKGameRules()->m_nShieldTeam)->GetOppTeamNumber() : SDKGameRules()->m_nShieldTeam);
			Vector min = GetGlobalTeam(side)->m_vPenBoxMin - border;
			Vector max = GetGlobalTeam(side)->m_vPenBoxMax + border;

			if (GetFlags() & FL_SHIELD_KEEP_OUT || SDKGameRules()->m_nShieldType == SHIELD_PENALTY)
			{
				if (SDKGameRules()->m_vKickOff.GetY() > min.y)
					min.y -= 500;
				else
					max.y += 500;
			}

			bool isInsideBox = newPos.x > min.x && newPos.y > min.y && newPos.x < max.x && newPos.y < max.y; 
			Vector boxCenter = (min + max) / 2;

			if (GetFlags() & FL_SHIELD_KEEP_OUT && isInsideBox)
			{
				bool oldPosInBox = true;

				if (newPos.x > min.x && oldPos.x <= min.x && newPos.x < boxCenter.x)
				{
					newPos.x = min.x;
					oldPosInBox = false; 
				}
				else if (newPos.x < max.x && oldPos.x >= max.x && newPos.x > boxCenter.x)
				{
					newPos.x = max.x;
					oldPosInBox = false; 
				}

				if (newPos.y > min.y && oldPos.y <= min.y && newPos.y < boxCenter.y)
				{
					newPos.y = min.y;
					oldPosInBox = false; 
				}
				else if (newPos.y < max.y && oldPos.y >= max.y && newPos.y > boxCenter.y)
				{
					newPos.y = max.y;
					oldPosInBox = false; 
				}

				stopPlayer = true;

				if (SDKGameRules()->m_nShieldType == SHIELD_KEEPERHANDS && oldPosInBox)
				{
					Vector goalCenter = GetGlobalTeam(SDKGameRules()->m_nShieldTeam)->m_vGoalCenter;
					goalCenter.y -= GetGlobalTeam(SDKGameRules()->m_nShieldTeam)->m_nForward * 500;

					if ((goalCenter - newPos).Length2DSqr() < (goalCenter - oldPos).Length2DSqr())
					{
						newPos.x = oldPos.x;
						newPos.y = oldPos.y;
						stopPlayer = true;
					}
					else
						stopPlayer = false;
				}
			}
			else if (GetFlags() & FL_SHIELD_KEEP_IN && !isInsideBox)
			{
				if (newPos.x < min.x)
					newPos.x = min.x;
				else if (newPos.x > max.x)
					newPos.x = max.x;

				if (newPos.y < min.y)
					newPos.y = min.y;
				else if (newPos.y > max.y)
					newPos.y = max.y;

				stopPlayer = true;
			}
		}

		if (SDKGameRules()->m_nShieldType == SHIELD_THROWIN && GetFlags() & FL_SHIELD_KEEP_OUT ||
			SDKGameRules()->m_nShieldType == SHIELD_FREEKICK || 
			SDKGameRules()->m_nShieldType == SHIELD_CORNER ||  
			SDKGameRules()->m_nShieldType == SHIELD_KICKOFF ||
			SDKGameRules()->m_nShieldType == SHIELD_PENALTY && (GetFlags() & FL_SHIELD_KEEP_OUT))
		{
			float radius = SDKGameRules()->GetShieldRadius(GetTeamNumber(), GetFlags() & FL_SHIELD_KEEP_IN) + border;
			Vector dir = newPos - SDKGameRules()->m_vShieldPos;

			if (!SDKGameRules()->IsIntermissionState() &&
				((GetFlags() & FL_SHIELD_KEEP_OUT) && dir.Length2D() < radius ||
				(GetFlags() & FL_SHIELD_KEEP_IN) && dir.Length2D() > radius))
			{
				dir.z = 0;
				dir.NormalizeInPlace();
				newPos = SDKGameRules()->m_vShieldPos + dir * radius;
				stopPlayer = true;
			}

			if (SDKGameRules()->m_nShieldType == SHIELD_KICKOFF && (GetFlags() & FL_SHIELD_KEEP_OUT)
				&& (!SDKGameRules()->IsIntermissionState() || SDKGameRules()->State_Get() == MATCH_PERIOD_WARMUP && mp_shield_block_opponent_half.GetBool()))
			{
				int forward;
				#ifdef CLIENT_DLL
					forward = GetPlayersTeam(this)->m_nForward;
				#else
					forward = GetTeam()->m_nForward;
				#endif
				float yBorder = SDKGameRules()->m_vKickOff.GetY() - abs(border) * forward;
				if (ZeroSign(newPos.y - yBorder) == forward)
				{
					newPos.y = yBorder;
					stopPlayer = true;
				}
			}

			if (SDKGameRules()->m_nShieldType == SHIELD_FREEKICK && mp_shield_block_sixyardbox.GetBool())
			{
				int teamPosType;
				#ifdef CLIENT_DLL
					teamPosType = GameResources()->GetTeamPosType(entindex());
				#else
					teamPosType = GetTeamPosType();
				#endif
				if (teamPosType != POS_GK || GetTeamNumber() != GetGlobalTeam(SDKGameRules()->m_nShieldTeam)->GetOppTeamNumber())
				{
					int side = GetGlobalTeam(SDKGameRules()->m_nShieldTeam)->GetOppTeamNumber();
					Vector min = GetGlobalTeam(side)->m_vSixYardBoxMin - border;
					Vector max = GetGlobalTeam(side)->m_vSixYardBoxMax + border;

					if (GetGlobalTeam(side)->m_nForward == 1)
						min.y -= 500;
					else
						max.y += 500;

					bool isInsideBox = newPos.x > min.x && newPos.y > min.y && newPos.x < max.x && newPos.y < max.y; 
					Vector boxCenter = (min + max) / 2;

					if (isInsideBox)
					{
						if (newPos.x > min.x && oldPos.x <= min.x && newPos.x < boxCenter.x)
							newPos.x = min.x;
						else if (newPos.x < max.x && oldPos.x >= max.x && newPos.x > boxCenter.x)
							newPos.x = max.x;

						if (newPos.y > min.y && oldPos.y <= min.y && newPos.y < boxCenter.y)
							newPos.y = min.y;
						else if (newPos.y < max.y && oldPos.y >= max.y && newPos.y > boxCenter.y)
							newPos.y = max.y;

						stopPlayer = true;
					}
				}
			}
		}

		if (SDKGameRules()->m_nShieldType == SHIELD_THROWIN && GetFlags() & FL_SHIELD_KEEP_IN)
		{
			const int xLength = mp_shield_throwin_movement_x.GetInt();
			const int yLength = mp_shield_throwin_movement_y.GetInt();
			Vector xSign = SDKGameRules()->m_vShieldPos.GetX() > SDKGameRules()->m_vKickOff.GetX() ? 1 : -1;
			Vector min = SDKGameRules()->m_vShieldPos + Vector(xSign == -1 ? -xLength : 0, -yLength / 2, 0);
			Vector max = SDKGameRules()->m_vShieldPos + Vector(xSign == -1 ? 0 : xLength, yLength / 2, 0);

			bool isInsideBox = newPos.x > min.x && newPos.y > min.y && newPos.x < max.x && newPos.y < max.y;

			if (!isInsideBox)
			{
				if (newPos.x < min.x)
					newPos.x = min.x;
				else if (newPos.x > max.x)
					newPos.x = max.x;

				if (newPos.y < min.y)
					newPos.y = min.y;
				else if (newPos.y > max.y)
					newPos.y = max.y;

				stopPlayer = true;
			}
		}
	}

	if (!SDKGameRules()->IsIntermissionState() && mp_field_padding_enabled.GetBool())
	{
		float border = mp_field_padding.GetInt();
		Vector min = SDKGameRules()->m_vFieldMin - border;
		Vector max = SDKGameRules()->m_vFieldMax + border;

		if (newPos.x < min.x || newPos.y < min.y || newPos.x > max.x || newPos.y > max.y)
		{
			if (newPos.x < min.x)
				newPos.x = min.x;
			else if (newPos.x > max.x)
				newPos.x = max.x;

			if (newPos.y < min.y)
				newPos.y = min.y;
			else if (newPos.y > max.y)
				newPos.y = max.y;

			stopPlayer = true;
		}
	}

	if (stopPlayer)
	{
		//newVel = oldVel;
		trace_t	trace;
		UTIL_TraceHull(newPos, newPos, GetPlayerMins(), GetPlayerMaxs(), MASK_PLAYERSOLID, this, COLLISION_GROUP_PLAYER, &trace);

		if (trace.startsolid)
		{
			// Stay at the old pos since the new pos is taken
			newPos = oldPos;
		}

		Vector dir = newPos - oldPos;
		dir.z = 0;
		float speed = dir.NormalizeInPlace();
		newVel = dir * min(speed * 100, mp_runspeed.GetInt());
		//newVel.x = (newPos - oldPos).x * 100;
		//newVel.y = (newPos - oldPos).y * 100;
		//newPos = pos;
	}
}
Example #11
0
void CKeeperBot::BotAdjustPos()
{
	float modifier = KEEPER_MID_COEFF;
	QAngle ang = m_oldcmd.viewangles;
	Vector target = GetTeam()->m_vGoalCenter;

	if (m_vBallVel.Length2D() > 750 && m_flAngToBallVel < 60)
	{
		float yDist = GetTeam()->m_vGoalCenter.GetY() - m_vBallPos.y;
		float vAng = acos(Sign(yDist) * m_vBallDir2D.y);
		float xDist = Sign(m_vBallDir2D.x) * abs(yDist) * tan(vAng);
		target.x = clamp(m_vBallPos.x + xDist, GetTeam()->m_vGoalCenter.GetX() - 150, GetTeam()->m_vGoalCenter.GetX() + 150);
	}

	if (m_pBall->State_Get() == BALL_STATE_KEEPERHANDS && m_pBall->GetCurrentPlayer() == this)
	{
		if (ShotButtonsReleased())
		{
			modifier = KEEPER_CLOSE_COEFF;
			//m_cmd.buttons |= (IN_ATTACK2 | IN_ATTACK);
			m_cmd.buttons |= IN_ALT1;
			CSDKPlayer *pPl = FindClosestPlayerToSelf(true, true);
			if (!pPl && SDKGameRules()->IsIntermissionState())
				pPl = FindClosestPlayerToSelf(false, true);

			if (pPl)
			{
				VectorAngles(pPl->GetLocalOrigin() - GetLocalOrigin(), ang);
				ang[PITCH] = g_IOSRand.RandomFloat(-40, 0);
				//m_flBotNextShot = gpGlobals->curtime + 1;
			}
			else
			{
				VectorAngles(Vector(0, GetTeam()->m_nForward, 0), ang);
				ang[YAW] += g_IOSRand.RandomFloat(-45, 45);
				ang[PITCH] = g_IOSRand.RandomFloat(-40, 0);
				//m_flBotNextShot = gpGlobals->curtime + 1;
			}
		}
	}
	else// if (gpGlobals->curtime >= m_flBotNextShot)
	{
		VectorAngles(m_vDirToBall, ang);
		float ballDistToGoal = (m_vBallPos - GetTeam()->m_vGoalCenter).Length2D();
		CSDKPlayer *pClosest = FindClosestPlayerToBall();
		m_cmd.buttons |= IN_ATTACK;

		if (ballDistToGoal < 750 && m_vDirToBall.Length2D() < 200 && m_vDirToBall.z < 200 && (m_vDirToBall.z < 80 || m_vBallVel.z <= 0))
		{
			modifier = KEEPER_CLOSE_COEFF;// max(0.15f, 1 - ballDistToGoal / 750);
			VectorAngles(Vector(0, GetTeam()->m_nForward, 0), ang);
			bool diving = false;

			if (m_flAngToBallVel < 60 && m_flAngToBallVel > 15)
			{
				if (abs(m_vDirToBall.x) > 50 && abs(m_vDirToBall.x) < 200 && m_vDirToBall.z < 150 && abs(m_vDirToBall.x) < 150 && m_vBallVel.Length() > 200)
				{
					m_cmd.buttons |= IN_JUMP;
					m_cmd.buttons |= Sign(m_vDirToBall.x) == GetTeam()->m_nRight ? IN_MOVERIGHT : IN_MOVELEFT;
					//m_cmd.buttons |= (IN_ATTACK2 | IN_ATTACK);
					diving = true;
				}
				else if (m_vDirToBall.z > 100 && m_vDirToBall.z < 150 && m_vDirToBall.Length2D() < 100)
				{
					m_cmd.buttons |= IN_JUMP;
					//m_cmd.buttons |= (IN_ATTACK2 | IN_ATTACK);
					diving = true;
				}
				else if (abs(m_vDirToBall.y) > 50 && abs(m_vDirToBall.y) < 200 && m_vDirToBall.z < 100 && abs(m_vDirToBall.x) < 50 && m_vBallVel.Length() < 200 && pClosest != this)
				{
					m_cmd.buttons |= IN_JUMP;
					m_cmd.buttons |= Sign(m_vLocalDirToBall.x) == GetTeam()->m_nForward ? IN_FORWARD : IN_BACK;
					//m_cmd.buttons |= (IN_ATTACK2 | IN_ATTACK);
					diving = true;
				}
			}

			if (!diving)
			{
				if (m_vDirToBall.Length2D() < 50)
				{
					modifier = KEEPER_CLOSE_COEFF;
					//m_cmd.buttons |= (IN_ATTACK2 | IN_ATTACK);
					CSDKPlayer *pPl = FindClosestPlayerToSelf(true, true);
					if (!pPl && SDKGameRules()->IsIntermissionState())
						pPl = FindClosestPlayerToSelf(false, true);

					if (pPl)
					{
						VectorAngles(pPl->GetLocalOrigin() - GetLocalOrigin(), ang);
						ang[PITCH] = g_IOSRand.RandomFloat(-40, 0);
						//m_flBotNextShot = gpGlobals->curtime + 1;
					}
					else
					{
						VectorAngles(Vector(0, GetTeam()->m_nForward, 0), ang);
						ang[YAW] += g_IOSRand.RandomFloat(-45, 45);
						ang[PITCH] = g_IOSRand.RandomFloat(-40, 0);
						//m_flBotNextShot = gpGlobals->curtime + 1;
					}
				}
				else
					modifier = KEEPER_CLOSE_COEFF;
			}
		}
		else if (ballDistToGoal < 1250 && m_flAngToBallVel < 60 && m_vBallVel.Length2D() > 300 && (m_vBallVel.z > 100 || m_vDirToBall.z > 100))
		{
			modifier = KEEPER_FAR_COEFF;
		}
		else if (ballDistToGoal < 1000 && m_vDirToBall.z < 80 && m_vBallVel.Length2D() < 300 && m_vBallVel.z < 100)
		{
			if (pClosest == this)
				modifier = KEEPER_CLOSE_COEFF;
			else
				modifier = max(KEEPER_FAR_COEFF, 1 - pow(min(1, ballDistToGoal / 750.0f), 2));
		}
		else
		{
			modifier = KEEPER_MID_COEFF;
		}

		m_cmd.viewangles = ang;
		m_LastAngles = m_cmd.viewangles;
		SetLocalAngles(m_cmd.viewangles);
		SnapEyeAngles(ang);

		Vector targetPosDir = target + modifier * (m_vBallPos - target) - GetLocalOrigin();
		targetPosDir.z = 0;
		float dist = targetPosDir.Length2D();
		VectorNormalizeFast(targetPosDir);
		Vector localDir;
		VectorIRotate(targetPosDir, EntityToWorldTransform(), localDir);
		//float speed;
		//if (dist < 10)
		//	speed = 0;
		//else if (dist < 100)
		//	speed = mp_runspeed.GetInt();
		//else
		//	speed = mp_sprintspeed.GetInt();
		//float speed = clamp(dist - 10, 0, mp_runspeed.GetInt());
		float speed = 0;

		if (dist > 30)
			speed = clamp(5 * dist, 0, mp_sprintspeed.GetInt() * (mp_botkeeperskill.GetInt() / 100.0f));

		if (speed > mp_runspeed.GetInt())
			m_cmd.buttons |= IN_SPEED;

		m_cmd.forwardmove = localDir.x * speed;
		m_cmd.sidemove = -localDir.y * speed;

		if (m_cmd.forwardmove > 0)
			m_cmd.buttons |= IN_FORWARD;
		else if (m_cmd.forwardmove < 0)
			m_cmd.buttons |= IN_BACK;

		if (m_cmd.sidemove > 0)
			m_cmd.buttons |= IN_RIGHT;
		else if (m_cmd.sidemove < 0)
			m_cmd.buttons |= IN_MOVELEFT;
	}

	m_cmd.viewangles = ang;
}
Example #12
0
void CKeeperBot::BotCenter()
{
	Vector dir = GetTeam()->m_vGoalCenter - GetLocalOrigin();
	m_cmd.sidemove = Sign(dir.x) * max(0, dir.Length2D() - 10);
	m_cmd.forwardmove = Sign(dir.y) * max(0, dir.Length2D() - 10);
}