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; }
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++; }