Exemple #1
0
Metric VectorToPolarRadians (const CVector &vP, Metric *retrRadius)

//	VectorToPolarRadians
//
//	Converts from a vector to polar coordinates (see PolarToVector)

	{
	Metric rAngle;
	Metric rRadius;
	Metric rSqrRadius = vP.Dot(vP);

	//	If we are at the origin then the angle is undefined

	if (rSqrRadius == 0.0)
		{
		rAngle = 0.0;
		rRadius = 0.0;
		}
	else
		{
		rRadius = sqrt(rSqrRadius);
		if (vP.GetX() >= 0.0)
			rAngle = (vP.GetY() >= 0.0 ? asin(vP.GetY() / rRadius) : (2 * g_Pi) + asin(vP.GetY() / rRadius));
		else
			rAngle = g_Pi - asin(vP.GetY() / rRadius);
		}

	//	Done

	if (retrRadius)
		*retrRadius = rRadius;

	return rAngle;
	}
Exemple #2
0
int VectorToPolar (const CVector &vP, Metric *retrRadius)

//	VectorToPolar
//
//	Converts from a vector to polar coordinates (see PolarToVector)

	{
	int iAngle;
	Metric rRadius;
	Metric rSqrRadius = vP.Dot(vP);

	//	If we are at the origin then the angle is undefined

	if (rSqrRadius == 0.0)
		{
		iAngle = 0;
		rRadius = 0.0;
		}
	else
		{
		rRadius = sqrt(rSqrRadius);
		if (vP.GetX() >= 0.0)
			iAngle = (((int)(180 * asin(vP.GetY() / rRadius) / g_Pi)) + 360) % 360;
		else
			iAngle = 180 - ((int)(180 * asin(vP.GetY() / rRadius) / g_Pi));
		}

	//	Done

	if (retrRadius)
		*retrRadius = rRadius;

	return iAngle;
	}
void CAutoDefenseClass::Update (CInstalledDevice *pDevice, 
								CSpaceObject *pSource, 
								int iTick,
								bool *retbSourceDestroyed,
								bool *retbConsumedItems)

//	Update
//
//	Update device

	{
	if (pDevice->IsReady() && pDevice->IsEnabled())
		{
		int i;

		//	Look for a target

		CSpaceObject *pBestTarget = NULL;
		Metric rBestDist2 = MAX_INTERCEPT_DISTANCE * MAX_INTERCEPT_DISTANCE;

		for (i = 0; i < pSource->GetSystem()->GetObjectCount(); i++)
			{
			CSpaceObject *pObj = pSource->GetSystem()->GetObject(i);

			if (pObj
					&& pObj->GetCategory() == CSpaceObject::catMissile
					&& pObj->GetSource() != pSource
					&& (pObj->GetSource() == NULL || pSource->IsEnemy(pObj->GetSource())))
				{
				CVector vRange = pObj->GetPos() - pSource->GetPos();
				Metric rDistance2 = vRange.Dot(vRange);

				if (rDistance2 < rBestDist2)
					{
					pBestTarget = pObj;
					rBestDist2 = rDistance2;
					}
				}
			}

		//	If we found a target, try to shoot at it

		if (pBestTarget)
			{
			CDeviceClass *pWeapon = GetWeapon();

			if (pWeapon)
				{
				int iFireAngle;
				if (pWeapon->IsWeaponAligned(pSource, pDevice, pBestTarget, &iFireAngle))
					{
					pDevice->SetFireAngle(iFireAngle);
					pWeapon->Activate(pDevice, pSource, pBestTarget, iFireAngle, retbSourceDestroyed, retbConsumedItems);
					pDevice->SetActivationDelay(m_iRechargeTicks);
					}
				}
			}
		}
	}
Exemple #4
0
void CZoanthropeAI::ImplementCombatManeuvers (CSpaceObject *pTarget)

//	ImplementCombatManeuvers
//
//	Move and fire

	{
	CVector vTarget = pTarget->GetPos() - m_pShip->GetPos();
	Metric rTargetDist2 = vTarget.Dot(vTarget);

	//	Fire on the target as best we can (if iFireDir is not -1, then it
	//	is the angle that we should turn towards to be able to fire).

	int iFireDir;
	m_AICtx.ImplementFireWeaponOnTarget(m_pShip, -1, -1, pTarget, vTarget, rTargetDist2, &iFireDir);

	//	Compute our flocking position

	CVector vFlockPos;
	CVector vFlockVel;
	int iFlockFacing;

	if (rTargetDist2 > COMBAT_RANGE2
			&& m_AICtx.CalcFlockingFormation(m_pShip, NULL, MAX_FLOCK_DIST, SEPARATION_RANGE, &vFlockPos, &vFlockVel, &iFlockFacing))
		{
		m_AICtx.ImplementFormationManeuver(m_pShip, vFlockPos, vFlockVel, m_pShip->AlignToRotationAngle(iFlockFacing));
		}

	//	Otherwise, if we are the leader, then fight

	else
		{
		//	If we're not well in range of our primary weapon then
		//	get closer to the target. (Or if we are not moving)

		if (rTargetDist2 > m_AICtx.GetPrimaryAimRange2())
			{
			//	Try to flank our target, if we are faster

			bool bFlank = (m_pShip->GetMaxSpeed() > pTarget->GetMaxSpeed());
			m_AICtx.ImplementCloseOnTarget(m_pShip, pTarget, vTarget, rTargetDist2, bFlank);

			iFireDir = -1;
			}
		else if (pTarget->CanMove()
				&& (m_pShip->GetVel().Length2() < (0.01 * 0.01 * LIGHT_SPEED * LIGHT_SPEED)))
			{
			m_AICtx.ImplementSpiralOut(m_pShip, vTarget);
			iFireDir = -1;
			}

		//	If necessary, turn to aim our weapon based on the fire solution

		if (iFireDir != -1
				&& !m_AICtx.NoDogfights())
			m_AICtx.ImplementManeuver(m_pShip, iFireDir, false);
		}
	}
CSpaceObject *CFerianShipAI::FindRandomAsteroid (void)

//	FindRandomAsteroid
//
//	Returns a random asteroid within 60 light-seconds

	{
	int i;
	Metric rMaxDist2 = MAX_MINING_RANGE2;
	Metric rCloseDist2 = CLOSE_MINING_RANGE2;
	CSpaceObject *Table[MAX_RANDOM_COUNT];
	int iCount = 0;

	for (i = 0; 
			(i < m_pShip->GetSystem()->GetObjectCount() && iCount < MAX_RANDOM_COUNT); 
			i++)
		{
		CSpaceObject *pObj = m_pShip->GetSystem()->GetObject(i);

		if (pObj && pObj->HasAttribute(ATTRIBUTE_ASTEROID))
			{
			CVector vRange = pObj->GetPos() - m_pShip->GetPos();
			Metric rDistance2 = vRange.Dot(vRange);

			//	If we're within the max dist, add it to the list

			if (rDistance2 < rMaxDist2)
				Table[iCount++] = pObj;

			//	If we're within 10 light-seconds, add it twice more (to increase
			//	the probability)

			if (rDistance2 < rCloseDist2)
				{
				Table[iCount++] = pObj;
				Table[iCount++] = pObj;
				}
			}
		}

	//	Pick a random entry from the list

	if (iCount == 0)
		return NULL;
	else
		return Table[mathRandom(0, iCount-1)];
	}
BOOL CRVTrackerDrawPoly::OnStart()
{
	// Make sure they're in the right edit mode for this..
	if ((m_pView->GetEditMode() != BRUSH_EDITMODE) && (m_pView->GetEditMode() != GEOMETRY_EDITMODE))
		return FALSE;

	//make sure that they weren't waiting for a polygon to finish, this fixes
	//a weird issue where a new tracker would get started after one just finished,
	//causing another brush drawing to begin right after the old one finished
	if(m_bFinishDrawingPoly)
	{
		return FALSE;
	}

	CEditVert		vert;

	if( m_pView->GetVertexFromPoint(m_cCurPt, vert) )
	{
		if( !m_pView->IsPerspectiveViewType( ))
		{
			CVector vOffset;
			vOffset = m_pView->EditGrid( ).Forward( );
			vOffset = m_pView->EditGrid( ).Forward( ) * vOffset.Dot( m_pView->GetRegion( )->m_vMarker );
			vert += vOffset;
		}
		m_pView->m_EditState = EDIT_DRAWINGPOLY;
	}
	else
		// Not sure how this would happen, but if we can't create the first vertex, cancel the tracker
		return FALSE;

	// Setup the new brush.
	m_pView->DrawingBrush().m_Points.Append( vert );
	m_pView->DrawingBrush().m_Points.Append( vert );

	// Update the view
	m_pView->GetDocument()->UpdateAllViews(m_pView);
	m_pView->DrawRect();

	return TRUE;
}
Exemple #7
0
 /* norm */
 float Len2() {
   return fScalar*fScalar + cV.Dot( cV );
 }
Exemple #8
0
void CZoanthropeAI::Behavior (void)

//	Behavior

	{
	//	Reset

	ResetBehavior();

	//	Behave according to our state

	switch (m_State)
		{
		case stateNone:
			BehaviorStart();
			break;

		case stateAttackingOnPatrol:
			{
			ASSERT(m_pTarget);
			ImplementCombatManeuvers(m_pTarget);
			m_AICtx.ImplementFireOnTargetsOfOpportunity(m_pShip, m_pTarget);

			//	See if we're out of our zone

			Metric rRange = LIGHT_SECOND * GetCurrentOrderData();
			if (CheckOutOfZone(GetCurrentOrderTarget(),
					rRange - PATROL_SENSOR_RANGE,
					rRange + PATROL_SENSOR_RANGE,
					30))
				SetState(stateNone);
			break;
			}

		case stateAttackingThreat:
			{
			ASSERT(m_pTarget);
			ImplementCombatManeuvers(m_pTarget);
			m_AICtx.ImplementFireOnTargetsOfOpportunity(m_pShip, m_pTarget);

			//	Every once in a while check to see if we've wandered too far from
			//	our base.

			if (CheckOutOfRange(GetCurrentOrderTarget(), PATROL_SENSOR_RANGE, 20))
				SetState(stateNone);
			break;
			}

		case stateOnCourseForStargate:
			{
			m_AICtx.ImplementGating(m_pShip, m_pBase);
			m_AICtx.ImplementAttackNearestTarget(m_pShip, ATTACK_RANGE, &m_pTarget);
			m_AICtx.ImplementFireOnTargetsOfOpportunity(m_pShip);
			break;
			}

		case stateOnEscortCourse:
			{
			ASSERT(m_pBase);

			CVector vFlockPos;
			CVector vFlockVel;
			int iFlockFacing;
			if (m_AICtx.CalcFlockingFormation(m_pShip, m_pBase, MAX_FLOCK_DIST, SEPARATION_RANGE, &vFlockPos, &vFlockVel, &iFlockFacing))
				{
				m_AICtx.ImplementFormationManeuver(m_pShip, vFlockPos, vFlockVel, m_pShip->AlignToRotationAngle(iFlockFacing));
				}
			else
				{
				CVector vTarget = m_pBase->GetPos() - m_pShip->GetPos();
				Metric rTargetDist2 = vTarget.Dot(vTarget);

				m_AICtx.ImplementCloseOnTarget(m_pShip, m_pBase, vTarget, rTargetDist2);
				m_AICtx.ImplementAttackNearestTarget(m_pShip, m_AICtx.GetMaxWeaponRange(), &m_pTarget);
				m_AICtx.ImplementFireOnTargetsOfOpportunity(m_pShip);
				}

			//	See if there is anything to attack

			CSpaceObject *pTarget;
			if (CheckForEnemiesInRange(m_pShip, PATROL_SENSOR_RANGE, 30, &pTarget))
				SetState(stateAttackingThreat, m_pBase, pTarget);

			break;
			}

		case stateOnPatrolOrbit:
			{
			ASSERT(m_pBase);

			CVector vFlockPos;
			CVector vFlockVel;
			int iFlockFacing;
			if (m_AICtx.CalcFlockingFormation(m_pShip, NULL, MAX_FLOCK_DIST, SEPARATION_RANGE, &vFlockPos, &vFlockVel, &iFlockFacing))
				{
				m_AICtx.ImplementFormationManeuver(m_pShip, vFlockPos, vFlockVel, m_pShip->AlignToRotationAngle(iFlockFacing));
				}
			else
				{
				m_AICtx.ImplementOrbit(m_pShip, m_pBase, LIGHT_SECOND * GetCurrentOrderData());
				m_AICtx.ImplementAttackNearestTarget(m_pShip, m_AICtx.GetMaxWeaponRange(), &m_pTarget);
				m_AICtx.ImplementFireOnTargetsOfOpportunity(m_pShip);
				}

			//	See if there is anything to attack

			CSpaceObject *pTarget;
			if (CheckForEnemiesInRange(m_pShip, PATROL_SENSOR_RANGE, 30, &pTarget))
				SetState(stateAttackingOnPatrol, m_pBase, pTarget);
			break;
			}

		case stateReturningFromThreat:
			{
			ASSERT(m_pBase);
			m_AICtx.ImplementDocking(m_pShip, m_pBase);
			m_AICtx.ImplementAttackNearestTarget(m_pShip, m_AICtx.GetMaxWeaponRange(), &m_pTarget);
			m_AICtx.ImplementFireOnTargetsOfOpportunity(m_pShip);

			//	See if there is anything to attack

			CSpaceObject *pTarget;
			if (CheckForEnemiesInRange(m_pBase, PATROL_SENSOR_RANGE, 30, &pTarget))
				SetState(stateAttackingThreat, m_pBase, pTarget);
			break;
			}

		case stateWaiting:
			m_AICtx.ImplementStop(m_pShip);

			if (m_pTarget)
				m_AICtx.ImplementAttackTarget(m_pShip, m_pTarget, true);

			m_AICtx.ImplementAttackNearestTarget(m_pShip, m_AICtx.GetMaxWeaponRange(), &m_pTarget);
			m_AICtx.ImplementFireOnTargetsOfOpportunity(m_pShip);
			break;

		case stateWaitingForThreat:
			{
			ASSERT(m_pBase);
			CSpaceObject *pTarget;
			if (CheckForEnemiesInRange(m_pBase, PATROL_SENSOR_RANGE, 30, &pTarget))
				SetState(stateAttackingThreat, m_pBase, pTarget);
			break;
			}
		}
	}
BOOL CRVTrackerDrawPoly::OnRotate()
{
	// Get the brush
	CEditBrush *pBrush = &m_pView->DrawingBrush();

	// Make sure we've got at least three points specified
	if (pBrush->m_Points.GetSize() < 3)
		return FALSE;

	// The origin's point #1
	CVector vOrigin = pBrush->m_Points[0];
	// The original rotation direction's point #2
	CVector vBase = pBrush->m_Points[1];
	// The new rotation's point #3
	CVector vNew = pBrush->m_Points[2];

	// Get the base direction
	CVector vBaseDir = vBase - vOrigin;
	float fBaseMag = vBaseDir.Mag();
	// Don't allow duplicate points
	if (fBaseMag < 0.01f)
		return TRUE;
	vBaseDir *= 1.0f / fBaseMag;

	// Get the rotation direction
	CVector vNewDir = vNew - vOrigin;
	float fNewMag = vNewDir.Mag();
	// Don't allow duplicate points
	if (fNewMag < 0.01f)
		return TRUE;
	vNewDir *= 1.0f / fNewMag;

	// Get the rotation axis
	CVector vRotAxis = vNewDir.Cross(vBaseDir);

	// Get the sin of the angle from the cross product
	float fRotAngle = vRotAxis.Mag();

	// Don't bother if the angle's 0...
	if (fRotAngle == 0.0f)
		return TRUE;

	// Normalize the axis
	vRotAxis *= 1.0f / fRotAngle;

	// Get the actual angle
	fRotAngle = (float)asin(fRotAngle);

	// Handle obtuse angles..
	if (vBaseDir.Dot(vNewDir) < 0.0f)
		fRotAngle = MATH_PI - fRotAngle;

	LTMatrix mRotation;
	// Get the rotation matrix
	mRotation.SetupRot(vRotAxis, fRotAngle);

	// Set up an undo..
	CEditRegion *pRegion = m_pView->GetRegion();
	PreActionList actionList;
	for (uint32 nUndoLoop = 0; nUndoLoop < pRegion->m_Selections; ++nUndoLoop)
		actionList.AddTail(new CPreAction(ACTION_MODIFYNODE, pRegion->m_Selections[nUndoLoop]));
	m_pView->GetRegionDoc()->Modify(&actionList, TRUE);

	// If we're in geometry mode..
	if (m_pView->GetEditMode() == GEOMETRY_EDITMODE)
	{
		// Get the selected vertices
		CVertRefArray vertList;
		m_pView->GetSelectedVerts(vertList);
		// Rotate 'em
		for (uint32 nVertLoop = 0; nVertLoop < vertList.GetSize(); ++nVertLoop)
		{
			CVertRef vert = vertList[nVertLoop];
			if (!vert.IsValid())
				continue;
			vert() -= vOrigin;
			mRotation.Apply(vert());
			vert() += vOrigin;
		}
	}
	else
	{
		// Otherwise, rotate all the selected nodes
		for (uint32 nNodeLoop = 0; nNodeLoop < pRegion->m_Selections.GetSize( ); ++nNodeLoop)
		{
			pRegion->m_Selections[nNodeLoop]->Rotate(mRotation, vOrigin);
		}

		// Update the selection box since stuff rotated...
		m_pView->GetRegionDoc()->UpdateSelectionBox();
	}

	return TRUE;
}
Exemple #10
0
void CAutonAI::Behavior (void)

//	Behavior
//
//	Fly, fight, die

	{
	//	Reset

	ResetBehavior();

	//	Behave according to our state

	switch (m_State)
		{
		case stateNone:
			BehaviorStart();
			break;

		case stateAttackingTarget:
			ASSERT(m_pTarget);
			m_AICtx.ImplementAttackTarget(m_pShip, m_pTarget);
			m_AICtx.ImplementFireOnTargetsOfOpportunity(m_pShip, m_pTarget);
			break;

		case stateEscorting:
			m_AICtx.ImplementEscort(m_pShip, m_pDest, &m_pTarget);
			break;

		case stateFollowing:
			{
			ASSERT(m_pDest);
			CVector vTarget = m_pDest->GetPos() - m_pShip->GetPos();
			Metric rTargetDist2 = vTarget.Dot(vTarget);
			Metric rMaxDist = (MAX_FOLLOW_DISTANCE) + (g_KlicksPerPixel * (m_pShip->GetDestiny() % 120));

			if (rTargetDist2 > (rMaxDist * rMaxDist))
				m_AICtx.ImplementCloseOnTarget(m_pShip, m_pDest, vTarget, rTargetDist2);
			else if (rTargetDist2 < (g_KlicksPerPixel * g_KlicksPerPixel * 1024.0))
				m_AICtx.ImplementSpiralOut(m_pShip, vTarget);
			else
				m_AICtx.ImplementStop(m_pShip);

			if (m_pTarget)
				m_AICtx.ImplementAttackTarget(m_pShip, m_pTarget, true);

			m_AICtx.ImplementAttackNearestTarget(m_pShip, ATTACK_RANGE, &m_pTarget);
			m_AICtx.ImplementFireOnTargetsOfOpportunity(m_pShip);
			break;
			}

		case stateOnCourseForStargate:
			m_AICtx.ImplementGating(m_pShip, m_pDest);
			m_AICtx.ImplementAttackNearestTarget(m_pShip, ATTACK_RANGE, &m_pTarget);
			m_AICtx.ImplementFireOnTargetsOfOpportunity(m_pShip);
			break;

		case stateWaiting:
			m_AICtx.ImplementHold(m_pShip);

			if (m_pTarget)
				m_AICtx.ImplementAttackTarget(m_pShip, m_pTarget, true);

			m_AICtx.ImplementAttackNearestTarget(m_pShip, ATTACK_RANGE, &m_pTarget);
			m_AICtx.ImplementFireOnTargetsOfOpportunity(m_pShip);
			break;

		default:
			ASSERT(false);
		}
	}
// Wrap the textures, starting at a poly index
void CRVTrackerTextureWrap::WrapTexture(CTWPolyInfo *pPoly, const CVector &vWrapDir, CTextExtents &cExtents) const
{
	// Mark this poly as wrapped
	pPoly->m_bTouched = TRUE;

	CTexturedPlane& Texture = pPoly->m_pPoly->GetTexture(GetCurrTexture());

	// Get the texture space
	LTVector vWrapO = Texture.GetO();
	LTVector vWrapP = Texture.GetP();
	LTVector vWrapQ = Texture.GetQ();

	// Get the texture offset projections
	float fWrapOdotP = vWrapO.Dot(vWrapP);
	float fWrapOdotQ = vWrapO.Dot(vWrapQ);

	// Update the texturing extents
	for (uint32 nExtentLoop = 0; nExtentLoop < pPoly->m_aEdges.GetSize(); ++nExtentLoop)
	{
		LTVector vEdgePt = pPoly->m_aEdges[nExtentLoop]->m_aPt[0];

		float fCurU = vWrapP.Dot(vEdgePt) - fWrapOdotP;
		float fCurV = vWrapQ.Dot(vEdgePt) - fWrapOdotQ;

		cExtents.m_fMinU = LTMIN(fCurU, cExtents.m_fMinU);
		cExtents.m_fMaxU = LTMAX(fCurU, cExtents.m_fMaxU);
		cExtents.m_fMinV = LTMIN(fCurV, cExtents.m_fMinV);
		cExtents.m_fMaxV = LTMAX(fCurV, cExtents.m_fMaxV);
	}

	CMoArray<uint32> aNeighbors;
	CMoArray<float> aDots;

	// Insert the neighbors into a list in dot-product order
	for (uint32 nNeighborLoop = 0; nNeighborLoop < pPoly->m_aNeighbors.GetSize(); ++nNeighborLoop)
	{
		CTWPolyInfo *pNeighbor = pPoly->m_aNeighbors[nNeighborLoop];

		// Skip edges that don't have a neighbor
		if (!pNeighbor)
			continue;

		// Skip neighbors that are already wrapped
		if (pNeighbor->m_bTouched)
			continue;

		// Get our dot product
		float fCurDot = vWrapDir.Dot(pPoly->m_aEdges[nNeighborLoop]->m_Plane.m_Normal);

		if ((m_bRestrictWalkDir) && (fCurDot < 0.707f))
			continue;

		// Mark this neighbor as touched (to avoid later polygons pushing it onto the stack)
		pNeighbor->m_bTouched = TRUE;

		// Insert it into the list
		for (uint32 nInsertLoop = 0; nInsertLoop < aNeighbors.GetSize(); ++nInsertLoop)
		{
			if (fCurDot > aDots[nInsertLoop])
				break;
		}
		aDots.Insert(nInsertLoop, fCurDot);
		aNeighbors.Insert(nInsertLoop, nNeighborLoop);
	}

	// Recurse through its neighbors
	for (uint32 nWrapLoop = 0; nWrapLoop < aNeighbors.GetSize(); ++nWrapLoop)
	{
		CTWPolyInfo *pNeighbor = pPoly->m_aNeighbors[aNeighbors[nWrapLoop]];
		CTWEdgeInfo *pEdge = pPoly->m_aEdges[aNeighbors[nWrapLoop]];

		//////////////////////////////////////////////////////////////////////////////
		// Wrap this neighbor

		// Create a matrix representing the basis of the polygon in relation to this edge
		LTMatrix mPolyBasis;
		mPolyBasis.SetTranslation(0.0f, 0.0f, 0.0f);
		mPolyBasis.SetBasisVectors(&pEdge->m_vDir, &pPoly->m_pPoly->m_Plane.m_Normal, &pEdge->m_Plane.m_Normal);

		// Create a new basis for the neighbor polygon
		LTMatrix mNeighborBasis;
		LTVector vNeighborForward;
		vNeighborForward = pNeighbor->m_pPoly->m_Plane.m_Normal.Cross(pEdge->m_vDir);
		// Just to be sure..
		vNeighborForward.Norm();
		mNeighborBasis.SetTranslation(0.0f, 0.0f, 0.0f);
		mNeighborBasis.SetBasisVectors(&pEdge->m_vDir, &pNeighbor->m_pPoly->m_Plane.m_Normal, &vNeighborForward);

		// Create a rotation matrix from here to there
		LTMatrix mRotation;
		mRotation = mNeighborBasis * ~mPolyBasis;

		// Rotate the various vectors
		LTVector vNewP;
		LTVector vNewQ;
		LTVector vNewDir;

		mRotation.Apply3x3(vWrapP, vNewP);
		mRotation.Apply3x3(vWrapQ, vNewQ);
		mRotation.Apply3x3(vWrapDir, vNewDir);

		// Rotate the texture basis if we're following a path
		if (m_nWrapStyle == k_WrapPath)
		{
			LTVector vNeighborEdgeDir;
			if (GetSimilarEdgeDir(pNeighbor, vNewDir, vNeighborEdgeDir, 0.707f))
			{
				LTMatrix mRotatedNeighbor;
				LTVector vNeighborRight;
				vNeighborRight = vNeighborEdgeDir.Cross(pNeighbor->m_pPoly->m_Plane.m_Normal);
				vNeighborRight.Norm();
				// Make sure we're pointing the right way...
				if (vNeighborRight.Dot(pEdge->m_vDir) < 0.0f)
					vNeighborRight = -vNeighborRight;
				mRotatedNeighbor.SetTranslation(0.0f, 0.0f, 0.0f);
				mRotatedNeighbor.SetBasisVectors(&vNeighborRight, &pNeighbor->m_pPoly->m_Plane.m_Normal, &vNeighborEdgeDir);
				// Build a basis based on an edge from the current polygon 
				LTVector vBestPolyEdge;
				GetSimilarEdgeDir(pPoly, vWrapDir, vBestPolyEdge);
				LTVector vPolyRight = vBestPolyEdge.Cross(pNeighbor->m_pPoly->m_Plane.m_Normal);
				vPolyRight.Norm();
				// Make sure we're pointing the right way...
				if (vPolyRight.Dot(pEdge->m_vDir) < 0.0f)
					vPolyRight = -vPolyRight;
				// Build the poly edge matrix
				LTMatrix mPolyEdgeBasis;
				mPolyEdgeBasis.SetTranslation(0.0f, 0.0f, 0.0f);
				mPolyEdgeBasis.SetBasisVectors(&vPolyRight, &pNeighbor->m_pPoly->m_Plane.m_Normal, &vBestPolyEdge);

				// Get a matrix from here to there
				LTMatrix mRotator;
				mRotator = mRotatedNeighbor * ~mPolyEdgeBasis;
				// Rotate the texture basis
				mRotator.Apply3x3(vNewP);
				mRotator.Apply3x3(vNewQ);
				// And use the new edge as the new direction
				vNewDir = vNeighborEdgeDir;
			}

			// Remove skew from vNewP/vNewQ
			if ((float)fabs(vNewP.Dot(vNewQ)) > 0.001f)
			{
				float fMagP = vNewP.Mag();
				float fMagQ = vNewQ.Mag();
				vNewQ *= 1.0f / fMagQ;
				vNewP -= vNewQ * vNewQ.Dot(vNewP);
				vNewP.Norm(fMagP);
				vNewQ *= fMagQ;
			}
		}

		// Get the first edge point..
		CVector vEdgePt = pEdge->m_aPt[0];

		// Calculate the texture coordinate at this point
		float fWrapU = vWrapP.Dot(vEdgePt) - fWrapOdotP;
		float fWrapV = vWrapQ.Dot(vEdgePt) - fWrapOdotQ;

		// Build the new offset
		float fNewOdotP = vNewP.Dot(vEdgePt) - fWrapU;
		float fNewOdotQ = vNewQ.Dot(vEdgePt) - fWrapV;
		LTVector vNewO;
		vNewO.Init();
		float fNewPMag = vNewP.MagSqr();
		if (fNewPMag > 0.0f)
			vNewO += vNewP * (fNewOdotP / fNewPMag);
		float fNewQMag = vNewQ.MagSqr();
		if (fNewQMag > 0.0f)
			vNewO += vNewQ * (fNewOdotQ / fNewQMag);

		pNeighbor->m_pPoly->SetTextureSpace(GetCurrTexture(), vNewO, vNewP, vNewQ);

		// Recurse into this neighbor
		WrapTexture(pNeighbor, vNewDir, cExtents);
	}
}
BOOL CRVTrackerTextureWrap::OnEnd()
{
	// If we're getting OnEnd because the dialog got displayed, skip out
	if (m_bShowingDialog)
		return TRUE;

	// Show the options dialog
	m_bShowingDialog = TRUE;
	CAutoTextureOptionsDlg cDlg;
	// Load the options from the registry
	cDlg.LoadOptionsFromReg();

	//if the skip tracker is active, just avoid the dialog
	int nModalResult;
	if(m_pSkipTracker && m_pSkipTracker->GetActive())
		nModalResult = IDOK;
	else
		nModalResult = cDlg.DoModal();

	m_bShowingDialog = FALSE;

	// Get the wrapping direction
	CVector vWrapDir = m_pView->DrawingBrush().m_Points[1] - m_pView->DrawingBrush().m_Points[0];
	// Clear the drawing brush (so it doesn't hang around if they cancel)
	m_pView->DrawingBrush().Term();

	// Jump out if they cancelled
	if (nModalResult != IDOK)
		return TRUE;
	// Get the style..
	m_nWrapStyle = cDlg.m_nStyle;
	if (m_nWrapStyle >= k_WrapInvalid)
		return TRUE;
	// Save the options to the registry
	cDlg.SaveOptionsToReg();
	// Get the options
	m_bScaleToFit = cDlg.m_bScale;
	m_bAdjustOffset = cDlg.m_bOffset;
	m_bRestrictWalkDir = cDlg.m_bRestrictDir;

	// This might take a while...
	m_pView->BeginWaitCursor();

	// Select the brushes with selected faces in geometry mode so this can be undone
	if (m_pView->GetEditMode() == GEOMETRY_EDITMODE)
	{
		CPolyRefArray &rTaggedPolies = m_pView->TaggedPolies();
		for (uint32 nFindBaseLoop = 0; nFindBaseLoop < rTaggedPolies.GetSize(); ++nFindBaseLoop)
		{
			if (!rTaggedPolies[nFindBaseLoop].IsValid())
				continue;
			m_pView->GetRegion()->SelectNode(rTaggedPolies[nFindBaseLoop]()->m_pBrush->AsNode());
		}
		m_pView->GetRegionDoc()->NotifySelectionChange();
	}

	// They'll probably want to be able to undo this...
	m_pView->GetRegionDoc()->SetupUndoForSelections();

	// If we didn't move, try and figure out a wrap direction
	if (vWrapDir.MagSqr() <= 0.01f)
	{
		// Try going to the right
		vWrapDir = m_pView->Nav().Right();
		// Make sure we're actually still on the poly...
		CEditPlane *pPlane = &(m_rBasePoly()->m_Plane);
		vWrapDir -= pPlane->m_Normal * vWrapDir.Dot(pPlane->m_Normal);
		// If that doesn't work..
		if (vWrapDir.MagSqr() <= 0.01f)
		{
			// Try going forward
			vWrapDir = m_pView->Nav().Forward();
			vWrapDir -= pPlane->m_Normal * vWrapDir.Dot(pPlane->m_Normal);
		}
	}
	vWrapDir.Norm();

	// Build the polygon set
	CTWPolyList aPolyList;
	BuildPolyList(aPolyList);

	// Find our base poly
	uint32 nBasePolyIndex = FindPolyIndex(aPolyList, m_rBasePoly());

	// Wrap the textures, starting at the base poly index
	CTextExtents cExtents;
	WrapTexture(aPolyList[nBasePolyIndex], vWrapDir, cExtents);

	// Scale the textures to an even multiple
	if (m_bScaleToFit)
		ScaleToMultiple(aPolyList, cExtents);

	// Offset the textures to fit at the top/left
	if (m_bAdjustOffset)
		AlignToTopLeft(aPolyList, cExtents);

	// Clear the polygon set
	ClearPolyList(aPolyList);

	// Redraw the views
	POSITION pos = m_pView->GetDocument()->GetFirstViewPosition();
	while (pos)
	{
		CView *pView = m_pView->GetDocument()->GetNextView(pos);
		pView->Invalidate(FALSE);
	}

	// This might take a while...
	m_pView->EndWaitCursor();

	return TRUE;
}
void CFleetShipAI::Behavior (void)

//	Behavior

	{
	//	Reset

	ResetBehavior();

	//	Use basic items

	UseItemsBehavior();

	//	Behave according to our state

	switch (m_State)
		{
		case stateNone:
			BehaviorStart();
			break;

		case stateAttackAtWill:
			{
			//	If we don't have a target, find one

			if (m_pTarget == NULL && m_pShip->IsDestinyTime(13))
				m_pTarget = m_pShip->GetNearestEnemy(ATTACK_AT_WILL_RANGE, true);

			//	If we have a target, attack

			if (m_pTarget)
				{
				ImplementAttackTarget(m_pTarget);
				ImplementFireOnTargetsOfOpportunity(m_pTarget);
				}

			//	Otherwise, stay in formation

			else
				{
				ImplementKeepFormation();
				ImplementFireOnTargetsOfOpportunity();
				ImplementFireOnNearestTarget();
				}

			break;
			}

		case stateAttackInFormation:
			{
			bool bInFormation;
			ImplementKeepFormation(&bInFormation);

			//	Fire the primary weapon (most of the time)

			if (bInFormation && mathRandom(1, 3) > 1)
				ImplementFireWeapon();

			//	Decrement counter

			if (m_iCounter > 0)
				{
				if (--m_iCounter == 0)
					{
					SetState(stateKeepFormation);
					m_iCounter = 0;
					}
				}

			break;
			}

		case stateAttackOnPatrol:
			ASSERT(m_pTarget);
			ImplementAttackTarget(m_pTarget);
			ImplementFireOnTargetsOfOpportunity(m_pTarget);

			//	Check to see if we've wandered outside our patrol zone

			if (m_pShip->IsDestinyTime(20))
				{
				CSpaceObject *pCenter = GetCurrentOrderTarget();
				Metric rMaxRange2 = PATROL_ORBIT_DIST + PATROL_SENSOR_RANGE;
				rMaxRange2 = rMaxRange2 * rMaxRange2;
				Metric rMinRange2 = std::max(0.0, PATROL_ORBIT_DIST - PATROL_SENSOR_RANGE);
				rMinRange2 = rMinRange2 * rMinRange2;

				int iTick = m_pShip->GetSystem()->GetTick();
				CVector vRange = pCenter->GetPos() - m_pShip->GetPos();
				Metric rDistance2 = vRange.Dot(vRange);

				//	If we're outside of our patrol range then stop the attack

				if (rDistance2 > rMaxRange2 || rDistance2 < rMinRange2)
					SetState(stateNone);
				}
			break;

		case stateAttackTarget:
			{
			ASSERT(m_pTarget);
			if (m_pTarget->CanMove())
				ImplementAttackTarget(m_pTarget);
			else
				{
				//	Attack the target as best we can

				CVector vTarget = m_pTarget->GetPos() - m_pShip->GetPos();
				Metric rTargetDist2 = vTarget.Dot(vTarget);
				ImplementFireWeaponOnTarget(-1, -1, m_pTarget, vTarget, rTargetDist2);

				//	Maneuver to a proper position near the target

				Metric rRange;
				int iCounterAdj;
				if (m_pAISettings->iCombatStyle == aicombatStandOff)
					{
					rRange = m_rBestWeaponRange / 2.0;
					iCounterAdj = 2;
					}
				else
					{
					rRange = m_rBestWeaponRange / 6.0;
					iCounterAdj = 1;
					}

				if (m_iCounter == 0)
					{
					m_vVector = ComputeAttackPos(m_pTarget, rRange, &m_iAngle);
					m_iCounter = mathRandom(130, 160) * iCounterAdj;
					}
				else
					m_iCounter--;

				ImplementFormationManeuver(m_vVector, NullVector, m_iAngle);
				}

			ImplementFireOnTargetsOfOpportunity(m_pTarget);
			break;
			}

		case stateKeepFormation:
			ImplementKeepFormation();
			ImplementFireOnTargetsOfOpportunity();
			ImplementFireOnNearestTarget();
			break;

		case stateOnCourseForDocking:
			ASSERT(m_pDest);
			ImplementDocking(m_pDest);
			ImplementFireOnTargetsOfOpportunity();
			ImplementFireOnNearestTarget();
			break;

		case stateOnCourseForStargate:
			ASSERT(m_pDest);
			ImplementGating(m_pDest);
			ImplementFireOnTargetsOfOpportunity();
			ImplementFireOnNearestTarget();
			break;

		case stateOnPatrolOrbit:
			ASSERT(m_pDest);
			ImplementOrbit(m_pDest, PATROL_ORBIT_DIST);
			ImplementAttackNearestTarget(m_rMaxWeaponRange, &m_pTarget, m_pDest);
			ImplementFireOnTargetsOfOpportunity(NULL, m_pDest);

			//	Check to see if any enemy ships appear

			if (m_pShip->IsDestinyTime(30))
				{
				CSpaceObject *pPrincipal = GetCurrentOrderTarget();
				CSpaceObject *pTarget = CalcEnemyShipInRange(pPrincipal, PATROL_SENSOR_RANGE, m_pDest);
				if (pTarget)
					{
					SetState(stateAttackOnPatrol);
					m_pTarget = pTarget;
					ASSERT(m_pTarget->DebugIsValid() && m_pTarget->NotifyOthersWhenDestroyed());
					}
				}
			break;
		}
	}
Exemple #14
0
Metric CalcDistanceToPath (const CVector &Pos,
						   const CVector &Path1,
						   const CVector &Path2,
						   CVector *retvNearestPoint,
						   CVector *retvAway)

//	CalcDistanceToPath
//
//	Returns the distance from Pos to the path from Path1 to Path2.

	{
	//	Create a unit vector from Path1 to Path2

	CVector vPath;
	vPath = Path2 - Path1;
	vPath = vPath.Normal();

	//	Create a vector perpendicular to the path

	CVector vPerp = vPath.Perpendicular();

	//	Create a vector from the point to one of the endpoints

	CVector vPoint = Path1 - Pos;

	//	Project this vector on to the perpendicular

	CVector vToLine = vPoint.Dot(vPerp) * vPerp;

	//	Compute the point on the line that is nearest Pos

	CVector vIntersect = Pos + vToLine;

	//	See if the point is between the two path endpoints

	bool bBetween = false;
	if (Path1.GetX() < Path2.GetX())
		bBetween = vIntersect.GetX() > Path1.GetX() && vIntersect.GetX() < Path2.GetX();
	else
		bBetween = vIntersect.GetX() > Path2.GetX() && vIntersect.GetX() < Path1.GetX();

	if (bBetween)
		{
		if (Path1.GetY() < Path2.GetY())
			bBetween = vIntersect.GetY() > Path1.GetY() && vIntersect.GetY() < Path2.GetY();
		else
			bBetween = vIntersect.GetY() > Path2.GetY() && vIntersect.GetY() < Path1.GetY();
		}

	//	If we're between, then the nearest distance is the distance to the path

	if (bBetween)
		{
		if (retvNearestPoint)
			*retvNearestPoint = vIntersect;
		if (retvAway)
			*retvAway = vToLine.Normal();
		return vToLine.Length();
		}

	//	Otherwise, the nearest distance is the nearest distance to the two endpoints

	else
		{
		CVector vDist1 = Path1 - Pos;
		CVector vDist2 = Path2 - Pos;
		Metric rLen1 = vDist1.Length();
		Metric rLen2 = vDist2.Length();

		if (rLen1 < rLen2)
			{
			if (retvNearestPoint)
				*retvNearestPoint = Path1;
			if (retvAway)
				*retvAway = vDist1.Normal();
			return rLen1;
			}
		else
			{
			if (retvNearestPoint)
				*retvNearestPoint = Path2;
			if (retvAway)
				*retvAway = vDist2.Normal();
			return rLen2;
			}
		}
	}