bool CTopologyNode::MatchesCriteria (SCriteriaCtx &Ctx, SCriteria &Crit)

//	MatchesCriteria
//
//	Returns TRUE if this node matches the given criteria

	{
	int i;

	//	Chance

	if (Crit.iChance < 100 && mathRandom(1, 100) > Crit.iChance)
		return false;

	//	Check required attributes

	for (i = 0; i < Crit.AttribsRequired.GetCount(); i++)
		if (!::HasModifier(m_sAttributes, Crit.AttribsRequired[i]))
			return false;

	//	Check disallowed attributes

	for (i = 0; i < Crit.AttribsNotAllowed.GetCount(); i++)
		if (::HasModifier(m_sAttributes, Crit.AttribsNotAllowed[i]))
			return false;

	//	Stargates

	if (m_NamedGates.GetCount() < Crit.iMinStargates)
		return false;

	if (Crit.iMaxStargates != -1 && m_NamedGates.GetCount() > Crit.iMaxStargates)
		return false;

	//	Distance to other nodes

	if (Ctx.pTopology)
		{
		for (i = 0; i < Crit.DistanceTo.GetCount(); i++)
			{
			//	If we don't have a specified nodeID then we need to find the distance
			//	to any node with the appropriate attributes

			if (Crit.DistanceTo[i].sNodeID.IsBlank())
				{
				CTopologyNodeList Checked;
				if (!Ctx.pTopology->GetTopologyNodeList().IsNodeInRangeOf(this,
						Crit.DistanceTo[i].iMinDist,
						Crit.DistanceTo[i].iMaxDist,
						Crit.DistanceTo[i].AttribsRequired,
						Crit.DistanceTo[i].AttribsNotAllowed,
						Checked))
					return false;
				}

			//	Otherwise, find the distance to the given node

			else
				{
				int iDist = Ctx.pTopology->GetDistance(GetID(), Crit.DistanceTo[i].sNodeID);

				if (iDist != -1 && iDist < Crit.DistanceTo[i].iMinDist)
					return false;

				if (iDist == -1 || (Crit.DistanceTo[i].iMaxDist != -1 && iDist > Crit.DistanceTo[i].iMaxDist))
					return false;
				}
			}
		}

	//	Done

	return true;
	}
Exemple #2
0
void CMissile::OnUpdate (Metric rSecondsPerTick)

//	OnUpdate
//
//	Update the beam

	{
	//	If we're already destroyed, then just update the timer until the
	//	vapor trail fades out

	if (m_fDestroyed)
		{
		//	Update the painter

		if (m_pPainter)
			{
			m_pPainter->OnUpdate();

			RECT rcRect;
			m_pPainter->GetRect(&rcRect);
			SetBounds(rcRect);
			}

		//	Done?

		if (--m_iLifeLeft <= 0)
			{
			Destroy(removedFromSystem, NULL);
			return;
			}
		}

	//	Otherwise, update

	else
		{
		int i;
		CSystem *pSystem = GetSystem();
		int iTick = m_iTick + GetDestiny();
		bool bDestroy = false;

		//	Accelerate, if necessary

		if (m_pDesc->m_iAccelerationFactor > 0 
				&& (iTick % 10 ) == 0)
			{
			if (m_pDesc->m_iAccelerationFactor < 100
					|| GetVel().Length() < m_pDesc->m_rMaxMissileSpeed)
				SetVel(GetVel() * (Metric)(m_pDesc->m_iAccelerationFactor / 100.0));
			}

		//	If we can choose new targets, see if we need one now

		if (m_pDesc->CanAutoTarget() && m_pTarget == NULL)
			m_pTarget = GetNearestEnemy(MAX_TARGET_RANGE, false);

		//	If this is a tracking missile, change direction to face the target

		if ((m_pDesc->m_iManeuverability > 0)
				&& m_pTarget 
				&& ((iTick % m_pDesc->m_iManeuverability) == 0))
			{
			//	Get the position and velocity of the target

			CVector vTarget = m_pTarget->GetPos() - GetPos();
			CVector vTargetVel = m_pTarget->GetVel() - GetVel();

			//	Figure out which direction to move in

			Metric rCurrentSpeed = GetVel().Length();
			Metric rTimeToIntercept = CalcInterceptTime(vTarget, vTargetVel, rCurrentSpeed);
			if (rTimeToIntercept > 0.0)
				{
				CVector vInterceptPoint = vTarget + vTargetVel * rTimeToIntercept;
				int iFireAngle = VectorToPolar(vInterceptPoint, NULL);

				//	If we are directional, then we are constrained to specific angles

				if (m_pDesc->m_bDirectional)
					{
					if (!AreAnglesAligned(iFireAngle, m_iRotation, g_RotationAngle / 2))
						{
						int iTurn = (iFireAngle + 360 - m_iRotation) % 360;

						if (iTurn >= 180)
							m_iRotation = (m_iRotation + 360 - g_RotationAngle) % 360;
						else
							m_iRotation = (m_iRotation + g_RotationAngle) % 360;

						}
					}
				else
					{
					if (!AreAnglesAligned(iFireAngle, m_iRotation, 1))
						{
						int iTurn = (iFireAngle + 360 - m_iRotation) % 360;

						if (iTurn >= 180)
							{
							int iTurnAngle = Min((360 - iTurn), g_RotationAngle);
							m_iRotation = (m_iRotation + 360 - iTurnAngle) % 360;
							}
						else
							{
							int iTurnAngle = Min(iTurn, g_RotationAngle);
							m_iRotation = (m_iRotation + iTurnAngle) % 360;
							}

						SetVel(PolarToVector(m_iRotation, rCurrentSpeed));
						}
					}

				SetVel(PolarToVector(m_iRotation, rCurrentSpeed));
				}
			}

		//	Update exhaust

		if (m_pExhaust)
			{
			if (iTick % m_pDesc->m_iExhaustRate)
				{
				if (m_pExhaust->GetCount() == m_pExhaust->GetMaxCount())
					m_pExhaust->Dequeue();

				SExhaustParticle &New = m_pExhaust->GetAt(m_pExhaust->Queue());
				New.vPos = GetPos();
				New.vVel = GetVel();
				}

			for (int i = 0; i < m_pExhaust->GetCount(); i++)
				{
				SExhaustParticle &Particle = m_pExhaust->GetAt(i);
				Particle.vVel = m_pDesc->m_rExhaustDrag * Particle.vVel;
				Particle.vPos = Particle.vPos + Particle.vVel * g_SecondsPerUpdate;
				}
			}

		//	Update the painter

		if (m_pPainter)
			{
			m_pPainter->OnUpdate();

			RECT rcRect;
			m_pPainter->GetRect(&rcRect);
			SetBounds(rcRect);
			}

		//	If we have a vapor trail and need to save rotation, do it

		if (m_pDesc->m_iVaporTrailLength 
				&& m_pDesc->m_iManeuverability)
			{
			//	Compute the current rotation

			int iDirection;
			if (m_pDesc->m_bDirectional)
				iDirection = (AlignToRotationAngle(m_iRotation) + 180) % 360;
			else
				iDirection = (m_iRotation + 180) % 360;

			//	Add the current rotation to the list of saved rotations

			if (m_pSavedRotations == NULL)
				{
				m_pSavedRotations = new int [m_pDesc->m_iVaporTrailLength];
				m_iSavedRotationsCount = 0;
				}

			int iStart = Min(m_iSavedRotationsCount, m_pDesc->m_iVaporTrailLength - 1);
			for (i = iStart; i > 0; i--)
				m_pSavedRotations[i] = m_pSavedRotations[i - 1];

			m_pSavedRotations[0] = iDirection;
			if (m_iSavedRotationsCount < m_pDesc->m_iVaporTrailLength)
				m_iSavedRotationsCount++;
			}

		//	See if the missile hit anything

		if (m_fDetonate && m_pDesc->HasFragments())
			{
			CreateFragments(GetPos());
			CreateHitEffect(GetPos());
			bDestroy = true;
			}
		else if (m_pHit)
			{
			//	If we have fragments, then explode now

			if (m_iHitDir == -1
					&& m_pDesc->HasFragments()
					&& m_iTick >= m_pDesc->m_iProximityFailsafe)
				{
				CreateFragments(m_vHitPos);
				CreateHitEffect(m_vHitPos);
				bDestroy = true;
				}

			//	Otherwise, if this was a direct hit, then we do damage

			else if (m_iHitDir != -1)
				{
				DamageResults result;
				DamageDesc Damage = m_pDesc->m_Damage;
				Damage.AddBonus(m_iBonus);
				Damage.SetCause(m_iCause);
				if (IsAutomatedWeapon())
					Damage.SetAutomatedWeapon();

				result = m_pHit->Damage(this,
						m_vHitPos,
						(m_iHitDir + 360 + mathRandom(0, 30) - 15) % 360,
						Damage);

				//	If we hit another missile (or some small object) there is a chance
				//	that we continue

				if (result == damagePassthrough)
					{
					m_iHitPoints = m_iHitPoints / 2;
					bDestroy = (m_iHitPoints == 0);
					}

				//	Set the missile to destroy itself after a hit

				else if (m_pDesc->m_iPassthrough == 0
						|| result == damageNoDamage 
						|| result == damageAbsorbedByShields
						|| mathRandom(1, 100) > m_pDesc->m_iPassthrough)
					bDestroy = true;

				CreateHitEffect(m_vHitPos);
				}
			}

		//	See if the missile has faded out

		if (bDestroy || --m_iLifeLeft <= 0)
			{
			//	If this is a fragmentation weapon, then we explode at the end of life

			if (!bDestroy && m_pDesc->HasFragments())
				{
				CreateFragments(GetPos());
				CreateHitEffect(GetPos());
				}

			//	If we've got a vapor trail effect, then keep the missile object alive
			//	but mark it destroyed

			int iFadeLife;
			if (m_pDesc->m_iVaporTrailLength)
				{
				m_fDestroyed = true;
				m_iLifeLeft = m_pDesc->m_iVaporTrailLength;
				}

			//	If we've got an effect that needs time to fade out, then keep
			//	the missile object alive

			else if (m_pPainter && (iFadeLife = m_pPainter->GetFadeLifetime()))
				{
				m_pPainter->OnBeginFade();

				m_fDestroyed = true;
				m_iLifeLeft = iFadeLife;
				}

			//	Otherwise, destroy the missile

			else
				{
				Destroy(removedFromSystem, NULL);
				return;
				}
			}
		}

	m_iTick++;
	}