bool CNavigationPath::PathIsClear (CSystem *pSystem,
								   CSovereign *pSovereign,
								   const CVector &vFrom, 
								   const CVector &vTo, 
								   CSpaceObject **retpEnemy, 
								   CVector *retvAway)

//	PathIsClear
//
//	Returns TRUE if the path from vFrom to vTo is free from enemy stations.
//	If FALSE, retpEnemy is initialized with the enemy that is blocking the
//	path and retvAway is a unit vector away from the enemy that avoids it

	{
	int i;

	//	Loop over all objects in the system

	CSpaceObject *pNearestEnemy = NULL;
	Metric rNearestDist = MAX_SAFE_DIST;
	CVector vNearestAway;

	for (i = 0; i < pSystem->GetObjectCount(); i++)
		{
		CSpaceObject *pObj = pSystem->GetObject(i);
		CSovereign *pObjSovereign;

		if (pObj
				&& (pObj->GetScale() == scaleStructure 
					|| ((pObj->GetScale() == scaleShip) && (pObj->GetVel().Length2() < MIN_SPEED2)))
				&& (pObjSovereign = pObj->GetSovereign())
				&& (pObjSovereign->IsEnemy(pSovereign))
				&& pObj->CanAttack())
			{
			CVector vAway;
			Metric rDist = CalcDistanceToPath(pObj->GetPos(), vFrom, vTo, NULL, &vAway);
			if (rDist < rNearestDist)
				{
				rNearestDist = rDist;
				pNearestEnemy = pObj;
				vNearestAway = vAway;
				}
			}
		}

	//	If we found a threatening object, return it

	if (pNearestEnemy)
		{
		if (retpEnemy)
			*retpEnemy = pNearestEnemy;
		if (retvAway)
			*retvAway = vNearestAway;
		return false;
		}

	//	Otherwise, the path is OK

	return true;
	}
bool CDockingPorts::ShipsNearPort (CSpaceObject *pOwner, CSpaceObject *pRequestingObj, const CVector &vPortPos)

//	ShipsNearPort
//
//	Returns TRUE if there are ships near the given port

	{
	int i;
	CSystem *pSystem = pOwner->GetSystem();

	for (i = 0; i < pSystem->GetObjectCount(); i++)
		{
		CSpaceObject *pObj = pSystem->GetObject(i);
		if (pObj
				&& pObj->GetCategory() == CSpaceObject::catShip
				&& !pObj->IsInactive()
				&& pObj != pRequestingObj)
			{
			Metric rDist2 = (pObj->GetPos() - vPortPos).Length2();
			if (rDist2 < MIN_PORT_DISTANCE2 && !IsDockedOrDocking(pObj))
				return true;
			}
		}

	return false;
	}
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);
					}
				}
			}
		}
	}
Example #4
0
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)];
	}
Example #5
0
CVector CreateVectorFromList (CCodeChain &CC, ICCItem *pList)

//	CreateVectorFromList
//
//	Creates a vector from a code chain list

	{
	CVector vVec;

	if (pList->IsList())
		CreateBinaryFromList(CC, pList, &vVec);
	else if (pList->IsInteger())
		{
		CSpaceObject *pObj = CreateObjFromItem(CC, pList);
		if (pObj)
			vVec = pObj->GetPos();
		}

	return vVec;
	}
Example #6
0
void GenerateSnapshot (CUniverse &Universe, CXMLElement *pCmdLine)
	{
	ALERROR error;
	int i;

	//	Get some parameters

	int iInitialUpdateTime = pCmdLine->GetAttributeIntegerBounded(CONSTLIT("initialUpdate"), 0, -1, 10);
	int iUpdateTime = pCmdLine->GetAttributeInteger(CONSTLIT("wait"));
	bool bObjOnly = pCmdLine->GetAttributeBool(CONSTLIT("objOnly"));

	//	Criteria

	CString sNode = pCmdLine->GetAttribute(CONSTLIT("node"));
	CString sCriteria = pCmdLine->GetAttribute(CONSTLIT("criteria"));

	//	Number of snapshots

	int iTotalCount = pCmdLine->GetAttributeIntegerBounded(CONSTLIT("count"), 1, -1, 1);

	//	Output

	int cxWidth;
	int cyHeight;
	if (pCmdLine->FindAttributeInteger(CONSTLIT("size"), &cxWidth))
		{
		cyHeight = cxWidth;
		}
	else
		{
		cxWidth = 1024;
		cyHeight = 1024;
		}

	//	Paint flags

	DWORD dwPaintFlags = 0;
	if (pCmdLine->GetAttributeBool(CONSTLIT("noStars")))
		dwPaintFlags |= CSystem::VWP_NO_STAR_FIELD;

	//	Output file

	CString sFilespec = pCmdLine->GetAttribute(CONSTLIT("output"));
	if (!sFilespec.IsBlank())
		sFilespec = pathStripExtension(sFilespec);

	//	Output image

	CG32bitImage Output;
	Output.Create(cxWidth, cyHeight);

	//	Update context

	SSystemUpdateCtx Ctx;
	Ctx.bForceEventFiring = true;
	Ctx.bForcePainted = true;

	RECT rcViewport;
	rcViewport.left = 0;
	rcViewport.top = 0;
	rcViewport.right = cxWidth;
	rcViewport.bottom = cyHeight;

	//	Loop over all systems until we find what we're looking for

	int iLoops = 20;
	int iNodeIndex = 0;
	int iSnapshotIndex = 0;
	CTopologyNode *pNode = Universe.GetTopologyNode(iNodeIndex);
	while (true)
		{
		//	Create the system

		CSystem *pSystem;
		if (error = Universe.CreateStarSystem(pNode, &pSystem))
			{
			printf("ERROR: Unable to create star system.\n");
			return;
			}

		//	If this is the node we want, then search

		CSpaceObject *pTarget;
		if (sNode.IsBlank() || strEquals(sNode, pNode->GetID()))
			{
			printf("Searching %s...\n", pNode->GetSystemName().GetASCIIZPointer());

			//	Set the POV

			CSpaceObject *pPOV = pSystem->GetObject(0);
			Universe.SetPOV(pPOV);
			pSystem->SetPOVLRS(pPOV);

			//	Prepare system

			Universe.UpdateExtended();
			Universe.GarbageCollectLibraryBitmaps();

			//	Update for a while

			for (i = 0; i < iInitialUpdateTime; i++)
				{
				Universe.Update(Ctx);
				Universe.PaintPOV(Output, rcViewport, 0);
				}

			//	Compose the criteria

			CSpaceObject::Criteria Criteria;
			CSpaceObject::ParseCriteria(pPOV, sCriteria, &Criteria);

			//	Get the list of all objects in the system that match the criteria

			CSpaceObject::SCriteriaMatchCtx Ctx(Criteria);
			TArray<CSpaceObject *> Results;
			for (i = 0; i < pSystem->GetObjectCount(); i++)
				{
				CSpaceObject *pObj = pSystem->GetObject(i);
				if (pObj && pObj->MatchesCriteria(Ctx, Criteria))
					Results.Insert(pObj);
				}

			//	Pick the appropriate object from the list

			if (Results.GetCount() == 0)
				pTarget = NULL;
			else if (Criteria.bNearestOnly || Criteria.bFarthestOnly)
				pTarget = Ctx.pBestObj;
			else
				pTarget = Results[mathRandom(0, Results.GetCount() - 1)];
			}
		else
			pTarget = NULL;

		//	If we found the target, then output

		if (pTarget)
			{
			Universe.SetPOV(pTarget);

			//	Wait a bit
			//
			//	NOTE: After we update, pTarget could be invalid (i.e., destroyed)
			//	so we can't use it again.

			CString sTargetName = pTarget->GetNounPhrase(0);

			for (i = 0; i < iUpdateTime; i++)
				{
				if ((i % 100) == 99)
					printf(".");

				Universe.Update(Ctx);
				Universe.PaintPOV(Output, rcViewport, 0);
				}

			if (iUpdateTime >= 99)
				printf("\n");

			//	Paint

			if (bObjOnly)
				{
				SViewportPaintCtx Ctx;
				Ctx.pObj = Universe.GetPOV();
				Ctx.XForm = ViewportTransform(Universe.GetPOV()->GetPos(), 
						g_KlicksPerPixel, 
						cxWidth / 2, 
						cyHeight / 2);
				Ctx.XFormRel = Ctx.XForm;
				Ctx.fNoRecon = true;
				Ctx.fNoDockedShips = true;
				Ctx.fNoSelection = true;
				Ctx.fNoStarfield = true;

				CSpaceObject *pPOV = pSystem->GetObject(0);
				CSpaceObject::Criteria Criteria;
				CSpaceObject::ParseCriteria(pPOV, sCriteria, &Criteria);

				//	Paint all objects that match the criteria

				CSpaceObject::SCriteriaMatchCtx CriteriaCtx(Criteria);
				for (i = 0; i < pSystem->GetObjectCount(); i++)
					{
					CSpaceObject *pObj = pSystem->GetObject(i);
					if (pObj && pObj->MatchesCriteria(CriteriaCtx, Criteria))
						{
						Ctx.pObj = pObj;
						int xObj;
						int yObj;
						Ctx.XForm.Transform(pObj->GetPos(), &xObj, &yObj);

						pObj->Paint(Output, xObj, yObj, Ctx);
						}
					}
				}
			else
				{
			
				Universe.PaintPOV(Output, rcViewport, 0);
				}

			//	Write to file

			if (!sFilespec.IsBlank())
				{
				CString sBmpFilespec;
				if (iTotalCount > 100)
					sBmpFilespec = pathAddExtensionIfNecessary(strPatternSubst(CONSTLIT("%s%03d"), sFilespec, iSnapshotIndex + 1), CONSTLIT(".bmp"));
				else if (iTotalCount > 1)
					sBmpFilespec = pathAddExtensionIfNecessary(strPatternSubst(CONSTLIT("%s%02d"), sFilespec, iSnapshotIndex + 1), CONSTLIT(".bmp"));
				else
					sBmpFilespec = pathAddExtensionIfNecessary(sFilespec, CONSTLIT(".bmp"));

				CFileWriteStream OutputFile(sBmpFilespec);
				if (OutputFile.Create() != NOERROR)
					{
					printf("ERROR: Unable to create '%s'\n", sBmpFilespec.GetASCIIZPointer());
					return;
					}

				Output.WriteToWindowsBMP(&OutputFile);
				OutputFile.Close();
				printf("Found %s: Saved to %s\n", sTargetName.GetASCIIZPointer(), sBmpFilespec.GetASCIIZPointer());
				}

			//	Otherwise, clipboard

			else
				{
				if (error = Output.CopyToClipboard())
					{
					printf("ERROR: Unable to copy image to clipboard.\n");
					return;
					}

				printf("Found %s: Copied to clipboard.\n", sTargetName.GetASCIIZPointer());
				}

			//	Reset maximum loops

			iLoops = 20;

			//	Done

			iSnapshotIndex++;
			if (iSnapshotIndex >= iTotalCount)
				break;
			}

		//	Done with old system

		Universe.DestroySystem(pSystem);

		//	Loop to the next node

		do
			{
			iNodeIndex = ((iNodeIndex + 1) % Universe.GetTopologyNodeCount());
			pNode = Universe.GetTopologyNode(iNodeIndex);
			}
		while (pNode == NULL || pNode->IsEndGame());

		//	If we're back to the first node again, restart

		if (iNodeIndex == 0)
			{
			if (--iLoops > 0)
				{
				//	Reinitialize

				Universe.Reinit();
				CString sError;
				if (Universe.InitGame(0, &sError) != NOERROR)
					{
					printf("ERROR: %s\n", sError.GetASCIIZPointer());
					return;
					}

				iNodeIndex = 0;
				pNode = Universe.GetTopologyNode(iNodeIndex);
				}
			else
				{
				printf("ERROR: Specified target could not be found.\n");
				return;
				}
			}
		}
	}
int CNavigationPath::ComputePath (CSystem *pSystem, CSovereign *pSovereign, const CVector &vFrom, const CVector &vTo, int iDepth, CVector **retpPoints)

//	ComputePath
//
//	This is a recursive function that returns a set of points that define a safe path
//	between the two given points.
//
//	We return an allocated array of CVectors in retpPoints

	{
	int i;

	//	If we're very close to our destination, then the best option is a direct path
	//	If the path is clear, then a direct path is also the best option.

	CSpaceObject *pEnemy;
	CVector vAway;
	if (iDepth >= MAX_PATH_RECURSION
			|| ((vTo - vFrom).Length2() <= MAX_SAFE_DIST2)
			|| PathIsClear(pSystem, pSovereign, vFrom, vTo, &pEnemy, &vAway))
		{
		(*retpPoints) = new CVector;
		(*retpPoints)[0] = vTo;
		return 1;
		}

	//	Otherwise, we deflect the path at the enemy base and recurse for the
	//	two path segments.

	else
		{
		//	Compute the mid-point

		CVector vMidPoint = pEnemy->GetPos() + (AVOID_DIST * vAway);

		//	Recurse

		CVector *pLeftPoints;
		int iLeftCount = ComputePath(pSystem, pSovereign, vFrom, vMidPoint, iDepth+1, &pLeftPoints);

		CVector *pRightPoints;
		int iRightCount = ComputePath(pSystem, pSovereign, vMidPoint, vTo, iDepth+1, &pRightPoints);

		//	Compose the two paths together

		int iCount = iLeftCount + iRightCount;
		ASSERT(iCount > 0);
		(*retpPoints) = new CVector [iCount];

		int iPos = 0;
		for (i = 0; i < iLeftCount; i++)
			(*retpPoints)[iPos++] = pLeftPoints[i];

		for (i = 0; i < iRightCount; i++)
			(*retpPoints)[iPos++] = pRightPoints[i];

		delete [] pLeftPoints;
		delete [] pRightPoints;

		return iCount;
		}
	}
Example #8
0
void CMissile::OnMove (const CVector &vOldPos, Metric rSeconds)

//	OnMove
//
//	Move our points

{
    //	Update the painter motion
    //	Note that we do this even if we're destroyed because we might have
    //	some fading particles.

    if (m_pPainter)
    {
        bool bBoundsChanged;
        m_pPainter->OnMove(&bBoundsChanged);

        //	Set bounds, if they've changed

        if (bBoundsChanged)
            SetBounds(m_pPainter);
    }

    //	If we're destroyed, then no further processing is needed

    if (m_fDestroyed)
    {
        //	Clear m_pHit so that we can tell the difference between the single
        //	frame in which we hit and any subsequent frames (when we're painting
        //	the exhaust only).

        m_pHit = NULL;
        return;
    }

    //	Compute threshold

    Metric rThreshold;
    if (m_pDesc->ProximityBlast() && m_iTick >= m_pDesc->GetProximityFailsafe())
        rThreshold = 128 * g_KlicksPerPixel;
    else
        rThreshold = 0.0;

    //	See if the beam hit anything after the move

    if (m_iTick > 1 || (!m_pDesc->m_bFragment && !m_fReflection))
        m_pHit = HitTest(vOldPos, rThreshold, m_pDesc->m_Damage, &m_vHitPos, &m_iHitDir);

    //	Make sure we are not too close to the source when we trigger
    //	a proximity blast.

    CSpaceObject *pSource;
    if (m_pHit && m_iHitDir == -1 && (pSource = m_Source.GetObj()))
    {
        CVector vDist = m_vHitPos - pSource->GetPos();
        Metric rDist2 = vDist.Length2();

        if (rDist2 < (rThreshold * rThreshold) / 4.0)
            m_pHit = NULL;
    }

    //	See if we pass through

    if (m_pHit
            && m_iHitDir != -1
            && m_pDesc->GetPassthrough() > 0
            && mathRandom(1, 100) <= m_pDesc->GetPassthrough()
            && m_pHit->GetPassthroughDefault() != damageNoDamageNoPassthrough)
        m_fPassthrough = true;
    else
        m_fPassthrough = false;
}
Example #9
0
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;
		}
	}
Example #10
0
void CParticleEffect::OnUpdate (Metric rSecondsPerTick)

//	OnUpdate
//
//	Update the effect

	{
	int iTick = GetSystem()->GetTick() + GetDestiny();

	//	Do not bother updating everything if we are far from the POV

	bool bFarAway = false;
	if (g_pUniverse->GetPOV() 
			&& g_pUniverse->GetCurrentSystem() == GetSystem())
		{
		Metric rPOVDist2 = (GetPos() - g_pUniverse->GetPOV()->GetPos()).Length2();
		Metric rMaxUpdateDist2 = LIGHT_SECOND * LIGHT_SECOND * 3600;
		bFarAway = (rPOVDist2 > rMaxUpdateDist2);
		}

	//	Update the particles

	SParticleArray *pGroup = m_pFirstGroup;
	while (pGroup)
		{
		SParticleType *pType = pGroup->pType;

		//	Max distance for a particle in this group

		Metric rMaxDist2 = pType->rRadius * pType->rRadius;
		Metric rMinDist2 = pType->rHoleRadius * pType->rHoleRadius;

		//	If the particle field causes damage then we need to
		//	compute its average density

		int iDensity = 0;
		if (pType->m_fDamage)
			{
			Metric rRadius2 = pType->rRadius * pType->rRadius;
			Metric rArea = rRadius2 / (LIGHT_SECOND * LIGHT_SECOND);
			iDensity = (int)(4 * pGroup->iCount / rArea);
			}

		//	Get an array of objects in the particle field that
		//	may influence the particles

		CSpaceObject *Objects[ctMaxObjsInField];
		int iObjCount = 0;
		if (!bFarAway && (pType->m_fWake || pType->m_fDamage))
			{
			Metric rMaxInfluenceDist2 = rMaxDist2;
			for (int i = 0; i < GetSystem()->GetObjectCount(); i++)
				{
				CSpaceObject *pObj = GetSystem()->GetObject(i);

				if (pObj 
						&& pObj->GetCategory() == catShip
						&& pObj != this)
					{
					CVector vDist = GetPos() - pObj->GetPos();
					Metric rDist2 = vDist.Length2();

					if (rDist2 < rMaxInfluenceDist2 
							&& (pObj->GetVel().Length2() > g_KlicksPerPixel)
							&& iObjCount < ctMaxObjsInField)
						{
						Objects[iObjCount++] = pObj;

						//	See if the object should take damage

						if (pType->m_fDamage)
							{
							CVector vDeltaV = pObj->GetVel() - GetVel();
							int iSpeed = (int)(vDeltaV.Length() / g_KlicksPerPixel);
							if (iSpeed == 0)
								iSpeed = 1;

							if (mathRandom(1, 1000) < (iDensity * iSpeed))
								{
								pObj->Damage(this,
										pObj->GetPos(),
										VectorToPolar(vDeltaV),
										pType->Damage);
								}
							}
						}
					}
				}
			}

		//	If we're computing drag then we need to compute the new velocity
		//	of the whole particle system

		CVector vNewVel;
		if (pType->m_fDrag)
			vNewVel = GetVel() * g_SpaceDragFactor;

		//	Iterate over all particles

		SParticle *pParticle = pGroup->pParticles;
		SParticle *pEnd = pParticle + pGroup->iCount;
		while (pParticle < pEnd)
			{
			if (pParticle->IsValid())
				{
				//	Lifespan. If we're far away and we're regenerating,
				//	then don't bother to compute lifespan.

				if (pType->m_fLifespan 
						&& !(bFarAway && (pType->m_fRegenerate && pType->iRegenerationTimer)))
					{
					if (--pParticle->iLifeLeft == 0)
						{
						//	Do we regenerate?

						if (pType->m_fRegenerate && pType->iRegenerationTimer)
							{
							pParticle->iLifeLeft = pType->iLifespan;
							pParticle->vPos = NullVector;

							//	Speed

							Metric rSpeed = mathRandom(1, 100) * (pType->rAveSpeed / 100.0);
							if (pType->iDirection == -1)
								pParticle->vVel = PolarToVector(mathRandom(0, 359), rSpeed);
							else
								{
								int iAngle = (pType->iDirection + 360 + mathRandom(0, 2 * pType->iDirRange) - pType->iDirRange) % 360;
								pParticle->vVel = PolarToVector(iAngle, rSpeed);
								}
							}

						//	Otherwise we die

						else
							{
							pParticle->iLifeLeft = -1;
							pGroup->iAlive--;
							pParticle++;
							continue;
							}
						}
					}

				//	Update the position

				if (!bFarAway)
					{
					pParticle->vPos = pParticle->vPos + pParticle->vVel;

					//	Change the velocity to keep the particles within
					//	the radius

					if (pType->m_fMaxRadius)
						{
						Metric rDist2 = pParticle->vPos.Length2();
						if (pType->m_fMaxRadius && rDist2 > rMaxDist2)
							{
							CVector vChange = pParticle->vPos + g_KlicksPerPixel * pParticle->vPos.Perpendicular().Normal();
							pParticle->vVel = pParticle->vVel - (0.00005 * vChange);
							}
						else if (rDist2 < rMinDist2)
							{
							CVector vNormal = pParticle->vPos.Normal();
							CVector vChange = g_KlicksPerPixel * (400 * vNormal - 50 * vNormal.Perpendicular());
							pParticle->vVel = pParticle->vVel + (0.00005 * vChange);
							}
						else
							pParticle->vVel = pParticle->vVel * pType->rDampening;
						}

					if (pType->m_fDrag)
						{
						//	Compute the new absolute velocity (after drag)
						CVector vAbsolute = pType->rDampening * (pParticle->vVel + GetVel());

						//	The particle velocity is the absolute vel minus the
						//	system velocity.
						pParticle->vVel = vAbsolute - vNewVel;
						}

					//	Change the velocity based on influences from other objects

					if (pType->m_fWake && (iTick % 4) == 0)
						{
						for (int i = 0; i < iObjCount; i++)
							{
							Metric rDist2 = (Objects[i]->GetPos() - (pParticle->vPos + GetPos())).Length2();
							if (rDist2 < g_KlicksPerPixel * g_KlicksPerPixel * 1000)
								{
								if (Objects[i]->GetVel().Dot(pParticle->vVel) < Objects[i]->GetVel().Length2())
									pParticle->vVel = pParticle->vVel + 0.2 * Objects[i]->GetVel();
								}
							}
						}
					}
				}

			pParticle++;
			}

		//	Regeneration timer

		if (pType->m_fRegenerate && pType->iRegenerationTimer)
			pType->iRegenerationTimer--;

		//	If there are no more particles left alive in this group then kill
		//	the group

		if (pGroup->iAlive == 0)
			{
			SParticleArray *pNext = pGroup->pNext;
			SParticleArray *pPrev = NULL;

			//	Find the previous group

			SParticleArray *pFind = m_pFirstGroup;
			while (pFind != pGroup)
				{
				if (pPrev)
					pPrev = pPrev->pNext;
				else
					pPrev = m_pFirstGroup;

				pFind = pFind->pNext;
				}

			//	Fix up the linked list

			if (pPrev)
				pPrev->pNext = pNext;
			else
				m_pFirstGroup = pNext;

			//	Delete the group

			delete pGroup;
			pGroup = pNext;
			}

		//	Otherwise, next group

		else
			pGroup = pGroup->pNext;
		}

	//	If we have no more groups then we destroy ourselves

	if (m_pFirstGroup == NULL)
		{
		Destroy(removedFromSystem, NULL);
		return;
		}

	//	If we're moving, slow down

	SetVel(CVector(GetVel().GetX() * g_SpaceDragFactor, GetVel().GetY() * g_SpaceDragFactor));
	}
void CDockingPorts::UpdateAll (SUpdateCtx &Ctx, CSpaceObject *pOwner)

//	UpdateAll
//
//	UpdateAll 

	{
	DEBUG_TRY

	int i;

	CSpaceObject *pPlayer = Ctx.pSystem->GetPlayer();
	Metric rDist2 = (pPlayer ? pPlayer->GetDistance2(pOwner) : 0.0);
	Metric rMaxDist = m_iMaxDist * LIGHT_SECOND;
	Metric rMaxDist2 = rMaxDist * rMaxDist;

	//	If owner is destroyed then don't bother checking for nearest player
	//	port.

	if (pPlayer 
			&& (pOwner->IsDestroyed() 
				|| pOwner->IsInactive() 
				|| pOwner == pPlayer
				|| pPlayer->IsDestroyed()))
		pPlayer = NULL;

	//	Also, don't bother checking if the owner is an enemy of the player.

	if (pPlayer && pPlayer->IsEnemy(pOwner) && !pOwner->IsAbandoned())
		pPlayer = NULL;

	//	Don't bother checking if the station is too far

	if (pPlayer && rDist2 > rMaxDist2)
		pPlayer = NULL;

	//	If this is a stargate and we are at the center (just came through) 
	//	then don't bother showing docking ports.

	if (pPlayer && pOwner->IsStargate() && rDist2 < GATE_DIST2)
		pPlayer = NULL;

	//	Loop over all ports

	for (i = 0; i < m_iPortCount; i++)
		{
		//	If a ship is docking with this port, then maneuver the ship towards
		//	the docking port.

		if (m_pPort[i].iStatus == psDocking)
			UpdateDockingManeuvers(pOwner, m_pPort[i]);

		//	Otherwise, if the port is open, see if this is the nearest port to
		//	the current player position.

		else if (m_pPort[i].iStatus == psEmpty)
			{
			if (pPlayer)
				{
				//	Compute the distance from the player to the port

				CVector vPortPos = pOwner->GetPos() + m_pPort[i].vPos;
				Metric rDist2 = (vPortPos - pPlayer->GetPos()).Length2();

				//	If this is a better port, then replace the existing 
				//	solution.

				if (Ctx.pDockingObj == NULL
							|| rDist2 < Ctx.rDockingPortDist2)
					{
					Ctx.pDockingObj = pOwner;
					Ctx.iDockingPort = i;
					Ctx.rDockingPortDist2 = rDist2;
					Ctx.vDockingPort = vPortPos;
					}
				}
			}
		}

	DEBUG_CATCH
	}
Example #12
0
bool GetPosOrObject (CEvalContext *pEvalCtx, 
					 ICCItem *pArg, 
					 CVector *retvPos, 
					 CSpaceObject **retpObj,
					 int *retiLocID)

//	GetPosOrObject
//
//	pArg is either a position or an object. We return a position and/or the object.

	{
	CCodeChain &CC(*pEvalCtx->pCC);

	CVector vPos;
	CSpaceObject *pObj = NULL;
	int iLocID = -1;

	if (pArg->IsNil())
		NULL;
	else if (pArg->IsList())
		{
		//	Is this a location criteria?

		CString sTag = pArg->GetElement(0)->GetStringValue();
		if (strEquals(sTag, CONSTLIT("location")))
			{
			CSystem *pSystem = g_pUniverse->GetCurrentSystem();
			if (pSystem == NULL)
				return false;

			//	Get the criteria and parse it

			CString sCriteria = (pArg->GetCount() > 1 ? pArg->GetElement(1)->GetStringValue() : NULL_STR);
			if (sCriteria.IsBlank())
				return false;

			CAttributeCriteria Criteria;
			if (Criteria.Parse(sCriteria) != NOERROR)
				return false;

			//	Get a random location

			if (!pSystem->FindRandomLocation(Criteria, 0, NULL, &iLocID))
				return false;

			//	Return the position

			CLocationDef *pLoc = pSystem->GetLocation(iLocID);
			vPos = pLoc->GetOrbit().GetObjectPos();
			}

		//	Otherwise, we assume a vector

		else
			vPos = CreateVectorFromList(CC, pArg);
		}
	else
		{
		pObj = CreateObjFromItem(CC, pArg);
		if (pObj)
			vPos = pObj->GetPos();
		}

	//	Done

	if (retvPos)
		*retvPos = vPos;

	if (retpObj)
		*retpObj = pObj;

	if (retiLocID)
		*retiLocID = iLocID;

	return true;
	}