Exemplo n.º 1
0
        /// <summary>
        /// Final defensive fire scans through all potential FCs that could fire defensively on the incoming missile to see if it is intercepeted.
        /// All PD enabled FCs will attempt to shoot down this missile except ones from the same faction, as this missile is practically right on top of said FC.
        /// In other words allied/neutral status isn't taken into account.
        /// </summary>
        /// <param name="P">Faction list</param>
        /// <param name="Missile">Missile to try to intercept</param>
        /// <param name="RNG">Random Number Generator</param>
        /// <returns>Whether the missile has been intercepted</returns>
        public static bool FinalDefensiveFire(BindingList <Faction> P, OrdnanceTN Missile, Random RNG)
        {
            bool       Intercept     = false;
            StarSystem CurrentSystem = Missile.missileGroup.contact.Position.System;
            float      PointBlank    = 10000.0f / (float)Constants.Units.KM_PER_AU;

            /// <summary>
            /// loop through every faction.
            /// </summary>
            foreach (Faction faction in P)
            {
                /// <summary>
                /// Is the current faction different from the missile group faction, and does the faction have a detected contacts list for the current system?
                /// </summary>
                if (faction != Missile.missileGroup.ordnanceGroupFaction && faction.DetectedContactLists.ContainsKey(CurrentSystem) == true)
                {
                    /// <summary>
                    /// Is the Missile group in this detected contact list?
                    /// </summary>
                    if (faction.DetectedContactLists[CurrentSystem].DetectedMissileContacts.ContainsKey(Missile.missileGroup) == true)
                    {
                        /// <summary>
                        /// Is the detection an active detection?
                        /// </summary>
                        if (faction.DetectedContactLists[CurrentSystem].DetectedMissileContacts[Missile.missileGroup].active == true)
                        {
                            /// <summary>
                            /// Does this faction have any point defense enabled FCs in this system?
                            /// </summary>
                            if (faction.PointDefense.ContainsKey(CurrentSystem) == true)
                            {
                                /// <summary>
                                /// loop through all the possible PD enabled FC.
                                /// </summary>
                                foreach (KeyValuePair <ComponentTN, ShipTN> pair in faction.PointDefense[CurrentSystem].PointDefenseFC)
                                {
                                    ShipTN Ship = pair.Value;

                                    /// <summary>
                                    /// Ship jump sickness will prevent point defense from operating.
                                    /// </summary>
                                    if (Ship.IsJumpSick())
                                    {
                                        continue;
                                    }

                                    /// <summary>
                                    /// Only want BFCs in FDF mode for now.
                                    /// </summary>
                                    if (faction.PointDefense[CurrentSystem].PointDefenseType[pair.Key] == false && pair.Value.ShipBFC[pair.Key.componentIndex].pDState == PointDefenseState.FinalDefensiveFire)
                                    {
                                        BeamFireControlTN ShipBeamFC = pair.Value.ShipBFC[pair.Key.componentIndex];

                                        /// <summary>
                                        /// Do a distance check on pair.Value vs the missile itself. if that checks out to be less than 10k km(or equal to zero), then
                                        /// check to see if the FC can shoot down said missile. This should never be run before a sensor sweep
                                        /// </summary>
                                        float dist = -1;

                                        /// <summary>
                                        /// dist is in AU.
                                        /// </summary>
                                        Missile.missileGroup.contact.DistTable.GetDistance(Ship.ShipsTaskGroup.Contact, out dist);

                                        /// <summary>
                                        /// if distance is less than the 10k km threshold attempt to intercept at Point blank range.
                                        /// </summary>
                                        if (dist < PointBlank)
                                        {
                                            /// <summary>
                                            /// Finally intercept the target.
                                            /// </summary>
                                            bool WF = false;
                                            Intercept = ShipBeamFC.InterceptTarget(RNG, 0, Missile, Ship.ShipsFaction,
                                                                                   Ship.ShipsTaskGroup.Contact, Ship, out WF);
                                            /// <summary>
                                            /// Add this ship to the weapon recharge list since it has fired. This is done here in Sim, or for FDF_Self in Ship.cs
                                            /// </summary>
                                            if (WF == true)
                                            {
                                                if (faction.RechargeList.ContainsKey(Ship) == true)
                                                {
                                                    /// <summary>
                                                    /// If our recharge value does not have Recharge beams in it(bitflag 2 for now), then add it.
                                                    /// </summary>
                                                    if ((faction.RechargeList[pair.Value] & (int)Faction.RechargeStatus.Weapons) != (int)Faction.RechargeStatus.Weapons)
                                                    {
                                                        faction.RechargeList[pair.Value] = (faction.RechargeList[pair.Value] + (int)Faction.RechargeStatus.Weapons);
                                                    }
                                                }
                                                else
                                                {
                                                    faction.RechargeList.Add(pair.Value, (int)Faction.RechargeStatus.Weapons);
                                                }
                                            }

                                            /// <summary>
                                            /// break out of the first foreach loop.
                                            /// </summary>
                                            if (Intercept == true)
                                            {
                                                break;
                                            }
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
                /// <summary>
                /// now break out of the faction loop as this missile has been shot down.
                /// </summary>
                if (Intercept == true)
                {
                    break;
                }
            }
            return(Intercept);
        }
Exemplo n.º 2
0
        /// <summary>
        /// Area defensive fire will sweep through a faction's list of BFCs and MFCs to fire at detected ordnance in range.
        /// </summary>
        /// <param name="Fact">Faction to search for fire controls of</param>
        /// <param name="RNG">"global" rng from further up.</param>
        public static void AreaDefensiveFire(Faction Fact, Random RNG)
        {
            /// <summary>
            /// No point defense set FCs, just return.
            /// </summary>
            if (Fact.PointDefense.Count == 0)
            {
                return;
            }

            /// <summary>
            /// Look through each starsystem with a point defense list.
            /// </summary>
            foreach (KeyValuePair <StarSystem, PointDefenseList> pair in Fact.PointDefense)
            {
                StarSystem CurrentSystem = pair.Key;

                /// <summary>
                /// No detected contacts in this system.
                /// </summary>
                if (Fact.DetectedContactLists.ContainsKey(CurrentSystem) == false)
                {
                    break;
                }

                /// <summary>
                /// No missile contacts in this system.
                /// </summary>
                if (Fact.DetectedContactLists[CurrentSystem].DetectedMissileContacts.Count == 0)
                {
                    break;
                }

                /// <summary>
                /// now loop through each FC in the current starsystem.
                /// </summary>
                foreach (KeyValuePair <ComponentTN, ShipTN> pair2 in pair.Value.PointDefenseFC)
                {
                    /// <summary>
                    /// The firing ship.
                    /// </summary>
                    ShipTN Ship = pair2.Value;

                    /// <summary>
                    /// Ship jump sickness will prevent point defense from operating.
                    /// </summary>
                    if (Ship.IsJumpSick())
                    {
                        continue;
                    }

                    /// <summary>
                    /// BFC set to Area defense mode
                    /// </summary>
                    if (pair.Value.PointDefenseType[pair2.Key] == false && pair2.Value.ShipBFC[pair2.Key.componentIndex].pDState == PointDefenseState.AreaDefense)
                    {
                        BeamFireControlTN ShipBeamFC = pair2.Value.ShipBFC[pair2.Key.componentIndex];
                        /// <summary>
                        /// loop through every missile contact. will have to do distance checks here.
                        /// </summary>
                        foreach (KeyValuePair <OrdnanceGroupTN, FactionContact> MisPair in Fact.DetectedContactLists[CurrentSystem].DetectedMissileContacts)
                        {
                            OrdnanceGroupTN DetectedMissileGroup = MisPair.Key;
                            /// <summary>
                            /// This missile group is already destroyed and will be cleaned up by sim later.
                            /// </summary>
                            if (DetectedMissileGroup.missilesDestroyed == DetectedMissileGroup.missiles.Count)
                            {
                                break;
                            }

                            /// <summary>
                            /// Do a distance check on pair.Value vs the missile itself. if that checks out to be less than 10k km(or equal to zero), then
                            /// check to see if the FC can shoot down said missile. This should never be run before a sensor sweep
                            /// </summary>
                            float dist;

                            DetectedMissileGroup.contact.DistTable.GetDistance(Ship.ShipsTaskGroup.Contact, out dist);

                            /// <summary>
                            /// Only bother with checks here that are within the maximum beam distance.
                            /// </summary>
                            if (dist <= Constants.Units.BEAM_AU_MAX)
                            {
                                /// <summary>
                                /// Value is in units of 10k km
                                /// </summary>
                                float rangeAreaDefenseKm;

                                /// <summary>
                                /// The user put in an absurdly large value. for convienence, just do this to get maximum range.
                                /// </summary>

                                if (ShipBeamFC.pDRange > (float)Constants.Units.TEN_KM_MAX)
                                {
                                    /// <summary>
                                    /// Max possible beam range in KM.
                                    /// </summary>
                                    rangeAreaDefenseKm = (float)Constants.Units.BEAM_KM_MAX;
                                }
                                else
                                {
#warning magic number related to 10k
                                    rangeAreaDefenseKm = ShipBeamFC.pDRange * 10000.0f;
                                }

                                float distKM = dist * (float)Constants.Units.KM_PER_AU;

                                /// <summary>
                                /// Additional paranoia check of range, I need to fix Area defense PD range values to ship bfc range in any event, that hasn't been done yet.
                                /// </summary>
#warning magic number for total bfc range.
                                float totalRange = ShipBeamFC.beamFireControlDef.range * 2.0f;

                                float range = Math.Min(totalRange, rangeAreaDefenseKm);

                                /// <summary>
                                /// the BFC is set for range defense and is in range of this missile.
                                /// </summary>
                                if (distKM <= range)
                                {
#warning magic number related to 10k km increments.
                                    /// <summary>
                                    /// Increment is a 10k km unit, so distance must be divided by 10000 to yield the appropriate number.
                                    /// </summary>
                                    int increment = (int)Math.Floor((float)distKM / 10000.0f);

                                    bool Intercept         = false;
                                    int  MissilesToDestroy = 0;

                                    /// <summary>
                                    /// Can't foreach this one, as I do not want every missile, only the ones not destroyed.
                                    /// </summary>
                                    for (int MissileIterator = DetectedMissileGroup.missilesDestroyed; MissileIterator < DetectedMissileGroup.missiles.Count; MissileIterator++)
                                    {
                                        bool WF = false;
                                        Intercept = ShipBeamFC.InterceptTarget(RNG, increment, DetectedMissileGroup.missiles[MissileIterator], Ship.ShipsFaction,
                                                                               Ship.ShipsTaskGroup.Contact, Ship, out WF);

                                        /// <summary>
                                        /// Add this ship to the weapon recharge list since it has fired. This is done here in Sim, or for FDF_Self in Ship.cs
                                        /// </summary>
                                        if (WF == true)
                                        {
                                            if (Fact.RechargeList.ContainsKey(Ship) == true)
                                            {
                                                /// <summary>
                                                /// If our recharge value does not have Recharge beams in it(bitflag 2 for now), then add it.
                                                /// </summary>
                                                if ((Fact.RechargeList[Ship] & (int)Faction.RechargeStatus.Weapons) != (int)Faction.RechargeStatus.Weapons)
                                                {
                                                    Fact.RechargeList[Ship] = (Fact.RechargeList[Ship] + (int)Faction.RechargeStatus.Weapons);
                                                }
                                            }
                                            else
                                            {
                                                Fact.RechargeList.Add(Ship, (int)Faction.RechargeStatus.Weapons);
                                            }
                                        }

                                        if (Intercept == true)
                                        {
                                            /// <summary>
                                            /// Destroy the missile, check if the ordnance group should be removed, if its gone also remove it from the detected contacts list and break that loop.
                                            /// </summary>

                                            MissilesToDestroy++;
                                        }
                                        else if (Intercept == false)
                                        {
                                            /// <summary>
                                            /// This FC can't intercept any more missiles, advance to the next one.
                                            /// </summary>
                                            break;
                                        }
                                    }

                                    /// <summary>
                                    /// Set the missiles destroyed count as appropriate.
                                    /// </summary>
                                    DetectedMissileGroup.missilesDestroyed = DetectedMissileGroup.missilesDestroyed + MissilesToDestroy;

                                    if (DetectedMissileGroup.missilesDestroyed != 0 && Fact.MissileRemoveList.Contains(DetectedMissileGroup) == false)
                                    {
                                        /// <summary>
                                        /// Tell sim to remove missiles from this group, or remove it entirely.
                                        /// </summary>
                                        Fact.MissileRemoveList.Add(DetectedMissileGroup);
                                    }

                                    if (Intercept == false)
                                    {
                                        /// <summary>
                                        /// This condition means advance to the next FC.
                                        /// </summary>
                                        break;
                                    }
                                }
                            }
                        }
                    }
                    /// <summary>
                    /// MFC set to any pd mode that can be applied: 1v2 up to 5v1.
                    /// </summary>
                    else if (pair.Value.PointDefenseType[pair2.Key] == true && pair2.Value.ShipMFC[pair2.Key.componentIndex].pDState >= PointDefenseState.AMM1v2 &&
                             pair2.Value.ShipMFC[pair2.Key.componentIndex].pDState <= PointDefenseState.AMM5v1)
                    {
                        MissileFireControlTN ShipMissileFC = pair2.Value.ShipMFC[pair2.Key.componentIndex];

                        int MissilesLaunched = 0;
                        int MissilesToLaunch = 0;
                        foreach (KeyValuePair <OrdnanceGroupTN, FactionContact> MisPair in Fact.DetectedContactLists[CurrentSystem].DetectedMissileContacts)
                        {
                            OrdnanceGroupTN DetectedMissileGroup = MisPair.Key;

                            /// <summary>
                            /// Advance to next missile group.
                            /// </summary>
                            if (DetectedMissileGroup.missilesDestroyed == DetectedMissileGroup.missiles.Count)
                            {
                                break;
                            }

                            /// <summary>
                            /// Do a distance check on pair.Value vs the missile itself. if that checks out to be less than 10k km(or equal to zero), then
                            /// check to see if the FC can shoot down said missile. This should never be run before a sensor sweep
                            /// </summary>
                            float dist;

                            DetectedMissileGroup.contact.DistTable.GetDistance(Ship.ShipsTaskGroup.Contact, out dist);


                            float MFCEngageDistKm    = ShipMissileFC.mFCSensorDef.maxRange;
                            float rangeAreaDefenseKm = ShipMissileFC.pDRange;

                            /// <summary>
                            /// Range is in 10K units so it has to be adjusted to AU for later down.
                            /// </summary>
#warning magic 10k number here
                            float range = (Math.Min(MFCEngageDistKm, rangeAreaDefenseKm) / (float)Constants.Units.KM_PER_AU);
                            range = range * 10000.0f;

                            int MSize    = 0;
                            int AltMSize = 0;

#warning the +6 is another magic number.
                            if ((int)Math.Ceiling(DetectedMissileGroup.missiles[0].missileDef.size) <= (Constants.OrdnanceTN.MissileResolutionMinimum + 6))
                            {
                                MSize    = Constants.OrdnanceTN.MissileResolutionMinimum;
                                AltMSize = 0;
                            }
                            else if ((int)Math.Ceiling(DetectedMissileGroup.missiles[0].missileDef.size) <= (Constants.OrdnanceTN.MissileResolutionMaximum + 6))
                            {
                                MSize    = (int)Math.Ceiling(DetectedMissileGroup.missiles[0].missileDef.size);
                                AltMSize = 0;
                            }
                            else if ((int)Math.Ceiling(DetectedMissileGroup.missiles[0].missileDef.size) > (Constants.OrdnanceTN.MissileResolutionMaximum + 6))
                            {
                                MSize    = -1;
                                AltMSize = (int)Math.Ceiling(Math.Ceiling(DetectedMissileGroup.missiles[0].missileDef.size) / (Constants.OrdnanceTN.MissileResolutionMaximum + 6));
                            }

                            int MFCRange = ShipMissileFC.mFCSensorDef.GetActiveDetectionRange(AltMSize, MSize);

                            bool CanDetect = Fact.LargeDetection(dist, MFCRange);

                            /// <summary>
                            /// Can this MFC fire on the targetted missile?
                            /// </summary>
                            if (CanDetect == true && dist <= range)
                            {
                                /// <summary>
                                /// Do AMM defense here. Check to see how many amms are targeted on this missile, if less than defense setting fire more.
                                /// How do I handle 1v2 mode? rounding obviously. if more than 1 missile in group send half, send atleast 1 for 1, and round for odd missile amounts.
                                /// missiles won't be destroyed here, as they were in beam fire mode, this will just launch amms at missile groups.
                                /// </summary>

                                /// <summary>
                                /// Get total missiles currently targetted on this group. Keeping track of a total missiles incoming variable would mean handling a lot of interactions where
                                /// missiles can be destroyed, run out of fuel, etc. so I'll just loop through this for now.
                                /// </summary>
#warning this missile count can be optimized, but it would be difficult to do so.
                                int TotalCount = 0;
                                foreach (OrdnanceGroupTN OrdGroupTargetting in DetectedMissileGroup.ordGroupsTargetting)
                                {
                                    TotalCount = TotalCount + OrdGroupTargetting.missiles.Count;
                                }

                                float Value = TotalCount / DetectedMissileGroup.missiles.Count;

                                switch (ShipMissileFC.pDState)
                                {
#warning more magic numbers in how point defense states are handled.
                                case PointDefenseState.AMM1v2:
                                    if (Value < 0.5f)
                                    {
                                        int Max = (int)Math.Ceiling((float)DetectedMissileGroup.missiles.Count / 2.0f);
                                        MissilesToLaunch = Max - TotalCount;
                                    }
                                    break;

                                case PointDefenseState.AMM1v1:
                                    if (Value < 1.0f)
                                    {
                                        int Max = DetectedMissileGroup.missiles.Count;
                                        MissilesToLaunch = Max - TotalCount;
                                    }
                                    break;

                                case PointDefenseState.AMM2v1:
                                    if (Value < 2.0f)
                                    {
                                        int Max = DetectedMissileGroup.missiles.Count * 2;
                                        MissilesToLaunch = Max - TotalCount;
                                    }
                                    break;

                                case PointDefenseState.AMM3v1:
                                    if (Value < 3.0f)
                                    {
                                        int Max = DetectedMissileGroup.missiles.Count * 3;
                                        MissilesToLaunch = Max - TotalCount;
                                    }
                                    break;

                                case PointDefenseState.AMM4v1:
                                    if (Value < 4.0f)
                                    {
                                        int Max = DetectedMissileGroup.missiles.Count * 4;
                                        MissilesToLaunch = Max - TotalCount;
                                    }
                                    break;

                                case PointDefenseState.AMM5v1:
                                    if (Value < 5.0f)
                                    {
                                        int Max = DetectedMissileGroup.missiles.Count * 5;
                                        MissilesToLaunch = Max - TotalCount;
                                    }
                                    break;
                                }

                                if (MissilesToLaunch != 0)
                                {
                                    /// <summary>
                                    /// launch up to MissilesToLaunch amms in a new ord group at the target.
                                    /// <summary>
                                    MissilesLaunched = ShipMissileFC.FireWeaponsPD(Ship.ShipsTaskGroup, Ship, DetectedMissileGroup, MissilesToLaunch);


                                    /// <summary>
                                    /// Add this ship to the weapon recharge list since it has fired. This is done here in Sim, or for FDF_Self in Ship.cs
                                    /// </summary>
                                    if (MissilesLaunched != 0)
                                    {
                                        if (Fact.RechargeList.ContainsKey(Ship) == true)
                                        {
                                            /// <summary>
                                            /// If our recharge value does not have Recharge beams in it(bitflag 2 for now), then add it.
                                            /// </summary>
                                            if ((Fact.RechargeList[Ship] & (int)Faction.RechargeStatus.Weapons) != (int)Faction.RechargeStatus.Weapons)
                                            {
                                                Fact.RechargeList[Ship] = (Fact.RechargeList[Ship] + (int)Faction.RechargeStatus.Weapons);
                                            }
                                        }
                                        else
                                        {
                                            Fact.RechargeList.Add(Ship, (int)Faction.RechargeStatus.Weapons);
                                        }
                                    }

                                    /// <summary>
                                    /// This FC can no longer fire at ordnance groups in range.
                                    /// </summary>
                                    if (MissilesLaunched != MissilesToLaunch)
                                    {
                                        break;
                                    }
                                }
                            }

                            /// <summary>
                            /// advance to the next FC.
                            /// </summary>
                            if (MissilesLaunched != MissilesToLaunch && MissilesToLaunch != 0)
                            {
                                break;
                            }
                        }
                    }
                }
            }
        }