Example #1
0
// If next step of path uses a ladder, prepare to traverse it
void CCSBot::SetupLadderMovement()
{
	if (m_pathIndex < 1 || m_pathLength == 0)
		return;

	const ConnectInfo *to = &m_path[m_pathIndex];

	if (to->ladder)
	{
		m_spotEncounter = nullptr;
		m_areaEnteredTimestamp = gpGlobals->time;

		m_pathLadder = to->ladder;
		m_pathLadderTimestamp = gpGlobals->time;

		// to get to next area, we must traverse a ladder
		if (to->how == GO_LADDER_UP)
		{
			m_pathLadderState = APPROACH_ASCENDING_LADDER;
			m_pathLadderFaceIn = true;
			PrintIfWatched("APPROACH_ASCENDING_LADDER\n");
			m_goalPosition = m_pathLadder->m_bottom;

			AddDirectionVector(&m_goalPosition, m_pathLadder->m_dir, HalfHumanWidth * 2.0f);
			m_lookAheadAngle = DirectionToAngle(OppositeDirection(m_pathLadder->m_dir));
		}
		else
		{
			// try to mount ladder "face out" first
			m_goalPosition = m_pathLadder->m_top;
			AddDirectionVector(&m_goalPosition, OppositeDirection(m_pathLadder->m_dir), HalfHumanWidth * 2.0f);

			TraceResult result;
			Vector from = m_pathLadder->m_top;
			Vector to = m_goalPosition;

			UTIL_TraceLine(from, to, ignore_monsters, ENT(m_pathLadder->m_entity->pev), &result);

			if (result.flFraction == 1.0f)
			{
				PrintIfWatched("APPROACH_DESCENDING_LADDER (face out)\n");

				m_pathLadderState = APPROACH_DESCENDING_LADDER;
				m_pathLadderFaceIn = false;
				m_lookAheadAngle = DirectionToAngle(m_pathLadder->m_dir);
			}
			else
			{
				PrintIfWatched("APPROACH_DESCENDING_LADDER (face in)\n");
				m_pathLadderState = APPROACH_DESCENDING_LADDER;
				m_pathLadderFaceIn = true;
				m_lookAheadAngle = DirectionToAngle(OppositeDirection(m_pathLadder->m_dir));
				m_goalPosition = m_pathLadder->m_top;
				AddDirectionVector(&m_goalPosition, m_pathLadder->m_dir, HalfHumanWidth);
			}
		}
	}
}
Example #2
0
/**
 * Connect this ladder to given area
 */
void CNavLadder::ConnectTo( CNavArea *area )
{
	float center = (m_top.z + m_bottom.z) * 0.5f;

	if (area->GetCenter().z > center)
	{
		// connect to top
		NavDirType dir;

		Vector dirVector = area->GetCenter() - m_top;
		if ( fabs( dirVector.x ) > fabs( dirVector.y ) )
		{
			if ( dirVector.x > 0.0f ) // east
			{
				dir = EAST;
			}
			else // west
			{
				dir = WEST;
			}
		}
		else
		{
			if ( dirVector.y > 0.0f ) // south
			{
				dir = SOUTH;
			}
			else // north
			{
				dir = NORTH;
			}
		}

		if ( m_dir == dir )
		{
			m_topBehindArea = area;
		}
		else if ( OppositeDirection( m_dir ) == dir )
		{
			m_topForwardArea = area;
		}
		else if ( DirectionLeft( m_dir ) == dir )
		{
			m_topLeftArea = area;
		}
		else
		{
			m_topRightArea = area;
		}
	}
	else
	{
		// connect to bottom
		m_bottomArea = area;
	}
}
Example #3
0
bool Map::hasFace(MapCoordinates Coordinates, Direction DirectionType) const
{
    MapCoordinates TargetMapCoordinates = Coordinates;
    Direction TargetFace = DirectionType;

    if (isDirectionPositive(DirectionType)) // East, South and Top Directions get translated to adjacent Cells avoiding a bounce back call
    {
        // Do something for edge of Map cases??
        TargetMapCoordinates.TranslateMapCoordinates(DirectionType);
        TargetFace = OppositeDirection(TargetFace);
    }

    CellCoordinates TargetCellCoordinates = CellCoordinates(TargetMapCoordinates);
    Cell* TargetCell = getCell(TargetCellCoordinates);

    if (TargetCell != NULL)
    {
        return TargetCell->hasFace(CubeCoordinates(TargetMapCoordinates), TargetFace);
    }
    return false;
}
Example #4
0
// Move actual view angles towards desired ones.
// This is the only place v_angle is altered.
// TODO: Make stiffness and turn rate constants timestep invariant.
void CCSBot::UpdateLookAngles()
{
	const float deltaT = g_flBotCommandInterval;
	float maxAccel;
	float stiffness;
	float damping;

	// springs are stiffer when attacking, so we can track and move between targets better
	if (IsAttacking())
	{
		stiffness = 300.0f;
		damping = 30.0f;
		maxAccel = 3000.0f;
	}
	else
	{
		stiffness = 200.0f;
		damping = 25.0f;
		maxAccel = 3000.0f;
	}

	// these may be overridden by ladder logic
	float useYaw = m_lookYaw;
	float usePitch = m_lookPitch;

	// Ladders require precise movement, therefore we need to look at the
	// ladder as we approach and ascend/descend it.
	// If we are on a ladder, we need to look up or down to traverse it - override pitch in this case.
	// If we're trying to break something, though, we actually need to look at it before we can
	// look at the ladder
	if (IsUsingLadder())
	{
		// set yaw to aim at ladder
		Vector to = m_pathLadder->m_top - pev->origin;
		float idealYaw = UTIL_VecToYaw(to);

		NavDirType faceDir = m_pathLadder->m_dir;

		if (m_pathLadderFaceIn)
		{
			faceDir = OppositeDirection(faceDir);
		}

		const float lookAlongLadderRange = 100.0f;
		const float ladderPitch = 60.0f;

		// adjust pitch to look up/down ladder as we ascend/descend
		switch (m_pathLadderState)
		{
			case APPROACH_ASCENDING_LADDER:
			{
				Vector to = m_goalPosition - pev->origin;
				useYaw = idealYaw;

				if (to.IsLengthLessThan(lookAlongLadderRange))
					usePitch = -ladderPitch;
				break;
			}
			case APPROACH_DESCENDING_LADDER:
			{
				Vector to = m_goalPosition - pev->origin;
				useYaw = idealYaw;

				if (to.IsLengthLessThan(lookAlongLadderRange))
					usePitch = ladderPitch;
				break;
			}
			case FACE_ASCENDING_LADDER:
			{
				useYaw = idealYaw;
				usePitch = -ladderPitch;
				break;
			}
			case FACE_DESCENDING_LADDER:
			{
				useYaw = idealYaw;
				usePitch = ladderPitch;
				break;
			}
			case MOUNT_ASCENDING_LADDER:
			case ASCEND_LADDER:
			{
				useYaw = DirectionToAngle(faceDir) + StayOnLadderLine(this, m_pathLadder);
				usePitch = -ladderPitch;
				break;
			}
			case MOUNT_DESCENDING_LADDER:
			case DESCEND_LADDER:
			{
				useYaw = DirectionToAngle(faceDir) + StayOnLadderLine(this, m_pathLadder);
				usePitch = ladderPitch;
				break;
			}
			case DISMOUNT_ASCENDING_LADDER:
			case DISMOUNT_DESCENDING_LADDER:
			{
				useYaw = DirectionToAngle(faceDir);
				break;
			}
		}
	}

	// Yaw
	float angleDiff = NormalizeAngle(useYaw - pev->v_angle.y);

	// if almost at target angle, snap to it
	const float onTargetTolerance = 1.0f;
	if (angleDiff < onTargetTolerance && angleDiff > -onTargetTolerance)
	{
		m_lookYawVel = 0.0f;
		pev->v_angle.y = useYaw;
	}
	else
	{
		// simple angular spring/damper
		float accel = stiffness * angleDiff - damping * m_lookYawVel;

		// limit rate
		if (accel > maxAccel)
			accel = maxAccel;

		else if (accel < -maxAccel)
			accel = -maxAccel;

		m_lookYawVel += deltaT * accel;
		pev->v_angle.y += deltaT * m_lookYawVel;
	}

	// Pitch
	// Actually, this is negative pitch.
	angleDiff = usePitch - pev->v_angle.x;

	angleDiff = NormalizeAngle(angleDiff);

	if (false && angleDiff < onTargetTolerance && angleDiff > -onTargetTolerance)
	{
		m_lookPitchVel = 0.0f;
		pev->v_angle.x = usePitch;
	}
	else
	{
		// simple angular spring/damper
		// double the stiffness since pitch is only +/- 90 and yaw is +/- 180
		float accel = 2.0f * stiffness * angleDiff - damping * m_lookPitchVel;

		// limit rate
		if (accel > maxAccel)
			accel = maxAccel;

		else if (accel < -maxAccel)
			accel = -maxAccel;

		m_lookPitchVel += deltaT * accel;
		pev->v_angle.x += deltaT * m_lookPitchVel;
	}

	// limit range - avoid gimbal lock
	if (pev->v_angle.x < -89.0f)
		pev->v_angle.x = -89.0f;
	else if (pev->v_angle.x > 89.0f)
		pev->v_angle.x = 89.0f;

	pev->v_angle.z = 0.0f;
}
Example #5
0
/**
 * Determine actual path positions
 */
bool CNavPath::ComputePathPositions( void )
{
	if (m_segmentCount == 0)
		return false;

	// start in first area's center
	m_path[0].pos = *m_path[0].area->GetCenter();
	m_path[0].ladder = NULL;
	m_path[0].how = NUM_TRAVERSE_TYPES;

	for( int i=1; i<m_segmentCount; ++i )
	{
		const PathSegment *from = &m_path[ i-1 ];
		PathSegment *to = &m_path[ i ];

		if (to->how <= GO_WEST)		// walk along the floor to the next area
		{
			to->ladder = NULL;

			// compute next point, keeping path as straight as possible
			from->area->ComputeClosestPointInPortal( to->area, (NavDirType)to->how, &from->pos, &to->pos );

			// move goal position into the goal area a bit
			const float stepInDist = 5.0f;		// how far to "step into" an area - must be less than min area size
			AddDirectionVector( &to->pos, (NavDirType)to->how, stepInDist );

			// we need to walk out of "from" area, so keep Z where we can reach it
			to->pos.z = from->area->GetZ( &to->pos );

			// if this is a "jump down" connection, we must insert an additional point on the path
			if (to->area->IsConnected( from->area, NUM_DIRECTIONS ) == false)
			{
				// this is a "jump down" link

				// compute direction of path just prior to "jump down"
				Vector2D dir;
				DirectionToVector2D( (NavDirType)to->how, &dir );

				// shift top of "jump down" out a bit to "get over the ledge"
				const float pushDist = 25.0f;
				to->pos.x += pushDist * dir.x;
				to->pos.y += pushDist * dir.y;

				// insert a duplicate node to represent the bottom of the fall
				if (m_segmentCount < MAX_PATH_SEGMENTS-1)
				{
					// copy nodes down
					for( int j=m_segmentCount; j>i; --j )
						m_path[j] = m_path[j-1];

					// path is one node longer
					++m_segmentCount;

					// move index ahead into the new node we just duplicated
					++i;

					m_path[i].pos.x = to->pos.x + pushDist * dir.x;
					m_path[i].pos.y = to->pos.y + pushDist * dir.y;

					// put this one at the bottom of the fall
					m_path[i].pos.z = to->area->GetZ( &m_path[i].pos );
				}
			}
		}
		else if (to->how == GO_LADDER_UP)		// to get to next area, must go up a ladder
		{
			// find our ladder
			const NavLadderList *list = from->area->GetLadderList( LADDER_UP );
			NavLadderList::const_iterator iter;
			for( iter = list->begin(); iter != list->end(); ++iter )
			{
				CNavLadder *ladder = *iter;

				// can't use "behind" area when ascending...
				if (ladder->m_topForwardArea == to->area ||
						ladder->m_topLeftArea == to->area ||
						ladder->m_topRightArea == to->area)
				{
					to->ladder = ladder;
					to->pos = ladder->m_bottom;
					AddDirectionVector( &to->pos, ladder->m_dir, 2.0f*HalfHumanWidth );
					break;
				}
			}

			if (iter == list->end())
			{
				//PrintIfWatched( "ERROR: Can't find ladder in path\n" );
				return false;
			}
		}
		else if (to->how == GO_LADDER_DOWN)		// to get to next area, must go down a ladder
		{
			// find our ladder
			const NavLadderList *list = from->area->GetLadderList( LADDER_DOWN );
			NavLadderList::const_iterator iter;
			for( iter = list->begin(); iter != list->end(); ++iter )
			{
				CNavLadder *ladder = *iter;

				if (ladder->m_bottomArea == to->area)
				{
					to->ladder = ladder;
					to->pos = ladder->m_top;
					AddDirectionVector( &to->pos, OppositeDirection( ladder->m_dir ), 2.0f*HalfHumanWidth );
					break;
				}
			}

			if (iter == list->end())
			{
				//PrintIfWatched( "ERROR: Can't find ladder in path\n" );
				return false;
			}
		}
	}

	return true;
}