/// <summary> /// Constructor for detected contact related order. /// </summary> /// <param name="TypeOrder">Type</param> /// <param name="SecondaryOrder">Secondary</param> /// <param name="TertiaryOrder">Tertiary</param> /// <param name="Delay">Order delay</param> /// <param name="ShipsOrder">Ship target of order</param> public Orders(Constants.ShipTN.OrderType TypeOrder, int SecondaryOrder, int TertiaryOrder, int Delay, ShipTN ShipsOrder) { TypeOf = TypeOrder; Target = ShipsOrder.ShipsTaskGroup.Contact; Secondary = SecondaryOrder; Tertiary = TertiaryOrder; ShipOrder = ShipsOrder; TaskGroup = ShipsOrder.ShipsTaskGroup; OrderDelay = Delay; OrderTimeRequirement = -1; Name = TypeOrder.ToString() + " " + ShipOrder.Name.ToString(); }
/// <summary> /// Initializer for detected ship event. FactionContact is the detector side of what is detected, while ShipTN itself stores the detectee side. /// multiple of these can exist, but only 1 per faction hopefully. /// </summary> /// <param name="DetectedShip">Ship detected.</param> /// <param name="Thermal">Was the detection thermal based?</param> /// <param name="em">Detection via EM?</param> /// <param name="Active">Active detection?</param> /// <param name="tick">What tick did this detection event occur on?</param> public FactionContact(Faction CurrentFaction, ShipTN DetectedShip, bool Thermal, bool em, int EMSig, bool Active, uint tick, uint year) { ship = DetectedShip; missileGroup = null; pop = null; thermal = Thermal; EM = em; EMSignature = EMSig; active = Active; String Contact = "New contact detected:"; if (thermal == true) { thermalTick = tick; thermalYear = year; Contact = String.Format("{0} Thermal Signature {1}", Contact, DetectedShip.CurrentThermalSignature); } if (EM == true) { EMTick = tick; EMYear = year; Contact = String.Format("{0} EM Signature {1}", Contact, EMSignature); } if (active == true) { activeTick = tick; activeYear = year; Contact = String.Format("{0} TCS {1}", Contact, DetectedShip.TotalCrossSection); } /// <summary> /// Print to the message log. /// </summary> MessageEntry NMsg = new MessageEntry(MessageEntry.MessageType.ContactNew, DetectedShip.ShipsTaskGroup.Contact.Position.System, DetectedShip.ShipsTaskGroup.Contact, GameState.Instance.GameDateTime, GameState.Instance.LastTimestep, Contact); CurrentFaction.MessageLog.Add(NMsg); /// <summary> /// Inform SimEntity. /// </summary> GameState.SE.SetInterrupt(InterruptType.NewSensorContact); }
/// <summary> /// End Copy Paste from Ship.cs /// </summary> /// <summary> /// Constructor for missiles. /// </summary> /// <param name="mfCtrl">MFC directing this missile.</param> /// <param name="definition">definition of the missile.</param> public OrdnanceTN(MissileFireControlTN mfCtrl, OrdnanceDefTN definition, ShipTN ShipFiredFrom) : base() { Name = definition.Name; MFC = mfCtrl; Target = MFC.target; FiringShip = ShipFiredFrom; MissileDef = definition; /// <summary> /// Litres of fuel available to this missile. /// </summary> Fuel = definition.fuel * 2500.0f; Separated = false; OnOwnSensors = false; }
/// <summary> /// Fire this MFC in point defense mode. /// </summary> /// <param name="TG">Taskgroup the MFC is in</param> /// <param name="FiredFrom">Ship the MFC is on</param> /// <param name="Target">Target of point defense fire.</param> /// <param name="MissilesToFire">Number of missiles to fire at it</param> /// <returns></returns> public int FireWeaponsPD(TaskGroupTN TG, ShipTN FiredFrom, OrdnanceGroupTN Target, int MissilesToFire) { /// <summary> /// simple stupid sanity check. /// </summary> if (MissilesToFire == 0) { return(0); } int LaunchCount = 0; /// <summary> /// Just a temporary variable for this function. /// </summary> BindingList <OrdnanceGroupTN> LocalMissileGroups = new BindingList <OrdnanceGroupTN>(); foreach (MissileLauncherTN LaunchTube in m_lLinkedWeapons) //int loop = 0; loop < LinkedWeapons.Count; loop++) { if (LaunchTube.isDestroyed == false && LaunchTube.loadTime == 0 && LaunchTube.loadedOrdnance != null) { if (FiredFrom.ShipOrdnance.ContainsKey(LaunchTube.loadedOrdnance) == true) { OrdnanceTN newMissile = new OrdnanceTN(this, LaunchTube.loadedOrdnance, FiredFrom); /// <summary> /// Point defense does not go by MFC targetting. have to add target here. /// </summary> newMissile.target = new TargetTN(Target); LaunchCount++; /// <summary> /// Create a new missile group /// </summary> if (LocalMissileGroups.Count == 0) { OrdnanceGroupTN newMissileGroup = new OrdnanceGroupTN(TG, newMissile); LocalMissileGroups.Add(newMissileGroup); TG.TaskGroupFaction.MissileGroups.Add(newMissileGroup); /// <summary> /// Add this ordnance group to the ord groups targetting list for the intended target missile group. /// This is only necessary here as Manually fired MFC missiles are connected to their MFC. /// </summary> Target.ordGroupsTargetting.Add(newMissileGroup); } /// <summary> /// An existing missile group may be useable. /// </summary> else { bool foundGroup = false; foreach (OrdnanceGroupTN OrdGroup in LocalMissileGroups) { /// <summary> /// All Missile groups should be composed of just 1 type of missile for convienence. if (OrdGroup.missiles[0].missileDef.Id == LaunchTube.loadedOrdnance.Id) { OrdGroup.AddMissile(newMissile); foundGroup = true; break; } } /// <summary> /// Have to create a new missile group after all. /// </summary> if (foundGroup == false) { OrdnanceGroupTN newMissileGroup = new OrdnanceGroupTN(TG, newMissile); LocalMissileGroups.Add(newMissileGroup); TG.TaskGroupFaction.MissileGroups.Add(newMissileGroup); /// <summary> /// Add this ordnance group to the ord groups targetting list for the intended target missile group. /// This is only necessary here as Manually fired MFC missiles are connected to their MFC. /// </summary> Target.ordGroupsTargetting.Add(newMissileGroup); } } /// <summary> /// Decrement the loaded ordnance count, and remove the type entirely if this was the last one. /// </summary> FiredFrom.ShipOrdnance[LaunchTube.loadedOrdnance] = FiredFrom.ShipOrdnance[LaunchTube.loadedOrdnance] - 1; if (FiredFrom.ShipOrdnance[LaunchTube.loadedOrdnance] == 0) { FiredFrom.ShipOrdnance.Remove(LaunchTube.loadedOrdnance); } /// <summary> /// Set the launch tube cooldown time as a missile was just fired from it. /// </summary> LaunchTube.loadTime = LaunchTube.missileLauncherDef.rateOfFire; if (LaunchCount == MissilesToFire) { break; } } else { String Msg = String.Format("No ordnance {0} on ship {1} is available for Launch Tube {2} in PD Mode", LaunchTube.Name, FiredFrom.Name, LaunchTube.Name); MessageEntry newMessage = new MessageEntry(MessageEntry.MessageType.FiringNoAvailableOrdnance, TG.Contact.Position.System, TG.Contact, GameState.Instance.GameDateTime, GameState.Instance.LastTimestep, Msg); TG.TaskGroupFaction.MessageLog.Add(newMessage); } } else if (LaunchTube.isDestroyed == true) { String Msg = String.Format("Destroyed launch tube {0} is still attached to {1}'s MFC in PD Mode", LaunchTube.Name, FiredFrom.Name); MessageEntry newMessage = new MessageEntry(MessageEntry.MessageType.Error, TG.Contact.Position.System, TG.Contact, GameState.Instance.GameDateTime, GameState.Instance.LastTimestep, Msg); TG.TaskGroupFaction.MessageLog.Add(newMessage); } else if (LaunchTube.loadedOrdnance == null) { String Msg = String.Format("No loaded ordnance for launch tube {0} on ship {1} in PD Mode", LaunchTube.Name, FiredFrom.Name); MessageEntry newMessage = new MessageEntry(MessageEntry.MessageType.FiringNoLoadedOrdnance, TG.Contact.Position.System, TG.Contact, GameState.Instance.GameDateTime, GameState.Instance.LastTimestep, Msg); TG.TaskGroupFaction.MessageLog.Add(newMessage); } } return(LaunchCount); }
/// <summary> /// Fire Weapons spawns new missiles groups or adds missiles to existing ones. /// </summary> /// <param name="TG">Taskgroup this MFC is in.</param> /// <param name="FiredFrom">Ship these missiles were fired from.</param> /// <returns>If missiles were fired at all from this MFC. true = atleast 1 missile(and therefore missile group, false = no missiles.</returns> public bool FireWeapons(TaskGroupTN TG, ShipTN FiredFrom) { bool retv = false; if (m_oTarget != null) { /// <summary> /// Just a temporary variable for this function. /// </summary> BindingList <OrdnanceGroupTN> LocalMissileGroups = new BindingList <OrdnanceGroupTN>(); foreach (MissileLauncherTN LaunchTube in m_lLinkedWeapons) { if (LaunchTube.isDestroyed == false && LaunchTube.loadTime == 0 && LaunchTube.loadedOrdnance != null) { if (FiredFrom.ShipOrdnance.ContainsKey(LaunchTube.loadedOrdnance) == true) { OrdnanceTN newMissile = new OrdnanceTN(this, LaunchTube.loadedOrdnance, FiredFrom); /// <summary> /// Create a new missile group /// </summary> if (LocalMissileGroups.Count == 0) { OrdnanceGroupTN newMissileGroup = new OrdnanceGroupTN(TG, newMissile); LocalMissileGroups.Add(newMissileGroup); TG.TaskGroupFaction.MissileGroups.Add(newMissileGroup); } /// <summary> /// An existing missile group may be useable. /// </summary> else { bool foundGroup = false; foreach (OrdnanceGroupTN OrdGroup in LocalMissileGroups) { /// <summary> /// All Missile groups should be composed of just 1 type of missile for convienence. if (OrdGroup.missiles[0].missileDef.Id == LaunchTube.loadedOrdnance.Id) { OrdGroup.AddMissile(newMissile); foundGroup = true; break; } } /// <summary> /// Have to create a new missile group after all. /// </summary> if (foundGroup == false) { OrdnanceGroupTN newMissileGroup = new OrdnanceGroupTN(TG, newMissile); LocalMissileGroups.Add(newMissileGroup); TG.TaskGroupFaction.MissileGroups.Add(newMissileGroup); } } /// <summary> /// Decrement the loaded ordnance count, and remove the type entirely if this was the last one. /// </summary> FiredFrom.ShipOrdnance[LaunchTube.loadedOrdnance] = FiredFrom.ShipOrdnance[LaunchTube.loadedOrdnance] - 1; if (FiredFrom.ShipOrdnance[LaunchTube.loadedOrdnance] == 0) { FiredFrom.ShipOrdnance.Remove(LaunchTube.loadedOrdnance); } /// <summary> /// Set the launch tube cooldown time as a missile was just fired from it. /// </summary> LaunchTube.loadTime = LaunchTube.missileLauncherDef.rateOfFire; /// <summary> /// return that a missile was launched. /// </summary> retv = true; } else { String Msg = String.Format("No ordnance {0} on ship {1} is available for Launch Tube {2}", LaunchTube.Name, FiredFrom.Name, LaunchTube.Name); MessageEntry newMessage = new MessageEntry(MessageEntry.MessageType.FiringNoAvailableOrdnance, TG.Contact.Position.System, TG.Contact, GameState.Instance.GameDateTime, GameState.Instance.LastTimestep, Msg); TG.TaskGroupFaction.MessageLog.Add(newMessage); } } else if (LaunchTube.isDestroyed == true) { String Msg = String.Format("Destroyed launch tube {0} is still attached to {1}'s MFC", LaunchTube.Name, FiredFrom.Name); MessageEntry newMessage = new MessageEntry(MessageEntry.MessageType.Error, TG.Contact.Position.System, TG.Contact, GameState.Instance.GameDateTime, GameState.Instance.LastTimestep, Msg); TG.TaskGroupFaction.MessageLog.Add(newMessage); } else if (LaunchTube.loadedOrdnance == null) { String Msg = String.Format("No loaded ordnance for launch tube {0} on ship {1}", LaunchTube.Name, FiredFrom.Name); MessageEntry newMessage = new MessageEntry(MessageEntry.MessageType.FiringNoLoadedOrdnance, TG.Contact.Position.System, TG.Contact, GameState.Instance.GameDateTime, GameState.Instance.LastTimestep, Msg); TG.TaskGroupFaction.MessageLog.Add(newMessage); } } return(retv); } else { return(false); } }
/// <summary> /// Simple assignment of a ship as a target to this mfc. /// </summary> /// <param name="ShipTarget">Ship to be targeted.</param> public void assignTarget(ShipTN ShipTarget) { m_oTarget = new TargetTN(ShipTarget); }
/// <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); }
/// <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; } } } } } }
/// <summary> /// Fire this MFC in point defense mode. /// </summary> /// <param name="TG">Taskgroup the MFC is in</param> /// <param name="FiredFrom">Ship the MFC is on</param> /// <param name="Target">Target of point defense fire.</param> /// <param name="MissilesToFire">Number of missiles to fire at it</param> /// <returns></returns> public int FireWeaponsPD(TaskGroupTN TG, ShipTN FiredFrom, OrdnanceGroupTN Target, int MissilesToFire) { /// <summary> /// simple stupid sanity check. /// </summary> if (MissilesToFire == 0) { return 0; } int LaunchCount = 0; /// <summary> /// Just a temporary variable for this function. /// </summary> BindingList<OrdnanceGroupTN> LocalMissileGroups = new BindingList<OrdnanceGroupTN>(); foreach (MissileLauncherTN LaunchTube in m_lLinkedWeapons) //int loop = 0; loop < LinkedWeapons.Count; loop++) { if (LaunchTube.isDestroyed == false && LaunchTube.loadTime == 0 && LaunchTube.loadedOrdnance != null) { if (FiredFrom.ShipOrdnance.ContainsKey(LaunchTube.loadedOrdnance) == true) { OrdnanceTN newMissile = new OrdnanceTN(this, LaunchTube.loadedOrdnance, FiredFrom); /// <summary> /// Point defense does not go by MFC targetting. have to add target here. /// </summary> newMissile.target = new TargetTN(Target); LaunchCount++; /// <summary> /// Create a new missile group /// </summary> if (LocalMissileGroups.Count == 0) { OrdnanceGroupTN newMissileGroup = new OrdnanceGroupTN(TG, newMissile); LocalMissileGroups.Add(newMissileGroup); TG.TaskGroupFaction.MissileGroups.Add(newMissileGroup); /// <summary> /// Add this ordnance group to the ord groups targetting list for the intended target missile group. /// This is only necessary here as Manually fired MFC missiles are connected to their MFC. /// </summary> Target.ordGroupsTargetting.Add(newMissileGroup); } /// <summary> /// An existing missile group may be useable. /// </summary> else { bool foundGroup = false; foreach (OrdnanceGroupTN OrdGroup in LocalMissileGroups) { /// <summary> /// All Missile groups should be composed of just 1 type of missile for convienence. if (OrdGroup.missiles[0].missileDef.Id == LaunchTube.loadedOrdnance.Id) { OrdGroup.AddMissile(newMissile); foundGroup = true; break; } } /// <summary> /// Have to create a new missile group after all. /// </summary> if (foundGroup == false) { OrdnanceGroupTN newMissileGroup = new OrdnanceGroupTN(TG, newMissile); LocalMissileGroups.Add(newMissileGroup); TG.TaskGroupFaction.MissileGroups.Add(newMissileGroup); /// <summary> /// Add this ordnance group to the ord groups targetting list for the intended target missile group. /// This is only necessary here as Manually fired MFC missiles are connected to their MFC. /// </summary> Target.ordGroupsTargetting.Add(newMissileGroup); } } /// <summary> /// Decrement the loaded ordnance count, and remove the type entirely if this was the last one. /// </summary> FiredFrom.ShipOrdnance[LaunchTube.loadedOrdnance] = FiredFrom.ShipOrdnance[LaunchTube.loadedOrdnance] - 1; if (FiredFrom.ShipOrdnance[LaunchTube.loadedOrdnance] == 0) { FiredFrom.ShipOrdnance.Remove(LaunchTube.loadedOrdnance); } /// <summary> /// Set the launch tube cooldown time as a missile was just fired from it. /// </summary> LaunchTube.loadTime = LaunchTube.missileLauncherDef.rateOfFire; if (LaunchCount == MissilesToFire) break; } else { String Msg = String.Format("No ordnance {0} on ship {1} is available for Launch Tube {2} in PD Mode", LaunchTube.Name, FiredFrom.Name, LaunchTube.Name); MessageEntry newMessage = new MessageEntry(MessageEntry.MessageType.FiringNoAvailableOrdnance, TG.Contact.Position.System, TG.Contact, GameState.Instance.GameDateTime, GameState.Instance.LastTimestep, Msg); TG.TaskGroupFaction.MessageLog.Add(newMessage); } } else if (LaunchTube.isDestroyed == true) { String Msg = String.Format("Destroyed launch tube {0} is still attached to {1}'s MFC in PD Mode", LaunchTube.Name, FiredFrom.Name); MessageEntry newMessage = new MessageEntry(MessageEntry.MessageType.Error, TG.Contact.Position.System, TG.Contact, GameState.Instance.GameDateTime, GameState.Instance.LastTimestep, Msg); TG.TaskGroupFaction.MessageLog.Add(newMessage); } else if (LaunchTube.loadedOrdnance == null) { String Msg = String.Format("No loaded ordnance for launch tube {0} on ship {1} in PD Mode", LaunchTube.Name, FiredFrom.Name); MessageEntry newMessage = new MessageEntry(MessageEntry.MessageType.FiringNoLoadedOrdnance, TG.Contact.Position.System, TG.Contact, GameState.Instance.GameDateTime, GameState.Instance.LastTimestep, Msg); TG.TaskGroupFaction.MessageLog.Add(newMessage); } } return LaunchCount; }
/// <summary> /// Fire Weapons spawns new missiles groups or adds missiles to existing ones. /// </summary> /// <param name="TG">Taskgroup this MFC is in.</param> /// <param name="FiredFrom">Ship these missiles were fired from.</param> /// <returns>If missiles were fired at all from this MFC. true = atleast 1 missile(and therefore missile group, false = no missiles.</returns> public bool FireWeapons(TaskGroupTN TG, ShipTN FiredFrom) { bool retv = false; if (m_oTarget != null) { /// <summary> /// Just a temporary variable for this function. /// </summary> BindingList<OrdnanceGroupTN> LocalMissileGroups = new BindingList<OrdnanceGroupTN>(); foreach (MissileLauncherTN LaunchTube in m_lLinkedWeapons) { if (LaunchTube.isDestroyed == false && LaunchTube.loadTime == 0 && LaunchTube.loadedOrdnance != null) { if (FiredFrom.ShipOrdnance.ContainsKey(LaunchTube.loadedOrdnance) == true) { OrdnanceTN newMissile = new OrdnanceTN(this, LaunchTube.loadedOrdnance, FiredFrom); /// <summary> /// Create a new missile group /// </summary> if (LocalMissileGroups.Count == 0) { OrdnanceGroupTN newMissileGroup = new OrdnanceGroupTN(TG, newMissile); LocalMissileGroups.Add(newMissileGroup); TG.TaskGroupFaction.MissileGroups.Add(newMissileGroup); } /// <summary> /// An existing missile group may be useable. /// </summary> else { bool foundGroup = false; foreach (OrdnanceGroupTN OrdGroup in LocalMissileGroups) { /// <summary> /// All Missile groups should be composed of just 1 type of missile for convienence. if (OrdGroup.missiles[0].missileDef.Id == LaunchTube.loadedOrdnance.Id) { OrdGroup.AddMissile(newMissile); foundGroup = true; break; } } /// <summary> /// Have to create a new missile group after all. /// </summary> if (foundGroup == false) { OrdnanceGroupTN newMissileGroup = new OrdnanceGroupTN(TG, newMissile); LocalMissileGroups.Add(newMissileGroup); TG.TaskGroupFaction.MissileGroups.Add(newMissileGroup); } } /// <summary> /// Decrement the loaded ordnance count, and remove the type entirely if this was the last one. /// </summary> FiredFrom.ShipOrdnance[LaunchTube.loadedOrdnance] = FiredFrom.ShipOrdnance[LaunchTube.loadedOrdnance] - 1; if (FiredFrom.ShipOrdnance[LaunchTube.loadedOrdnance] == 0) { FiredFrom.ShipOrdnance.Remove(LaunchTube.loadedOrdnance); } /// <summary> /// Set the launch tube cooldown time as a missile was just fired from it. /// </summary> LaunchTube.loadTime = LaunchTube.missileLauncherDef.rateOfFire; /// <summary> /// return that a missile was launched. /// </summary> retv = true; } else { String Msg = String.Format("No ordnance {0} on ship {1} is available for Launch Tube {2}", LaunchTube.Name, FiredFrom.Name, LaunchTube.Name); MessageEntry newMessage = new MessageEntry(MessageEntry.MessageType.FiringNoAvailableOrdnance, TG.Contact.Position.System, TG.Contact, GameState.Instance.GameDateTime, GameState.Instance.LastTimestep, Msg); TG.TaskGroupFaction.MessageLog.Add(newMessage); } } else if (LaunchTube.isDestroyed == true) { String Msg = String.Format("Destroyed launch tube {0} is still attached to {1}'s MFC", LaunchTube.Name, FiredFrom.Name); MessageEntry newMessage = new MessageEntry(MessageEntry.MessageType.Error, TG.Contact.Position.System, TG.Contact, GameState.Instance.GameDateTime, GameState.Instance.LastTimestep, Msg); TG.TaskGroupFaction.MessageLog.Add(newMessage); } else if (LaunchTube.loadedOrdnance == null) { String Msg = String.Format("No loaded ordnance for launch tube {0} on ship {1}", LaunchTube.Name, FiredFrom.Name); MessageEntry newMessage = new MessageEntry(MessageEntry.MessageType.FiringNoLoadedOrdnance, TG.Contact.Position.System, TG.Contact, GameState.Instance.GameDateTime, GameState.Instance.LastTimestep, Msg); TG.TaskGroupFaction.MessageLog.Add(newMessage); } } return retv; } else { return false; } }
/// <summary> /// This "constructs" the wreck itself. Later component definitions, mineral counts, and wealth will be calculated here. /// </summary> /// <param name="Ship">Ship from which this wreck originated</param> public WreckTN(ShipTN Ship) { }
/// <summary> /// Constructor for ship targets. /// </summary> /// <param name="ShipTarget">Ship that will be the target</param> public TargetTN(ShipTN ShipTarget) { Id = Guid.NewGuid(); TargetType = ShipTarget.ShipsTaskGroup.SSEntity; Ship = ShipTarget; }
/// <summary> /// Constructor for ship targets. /// </summary> /// <param name="ShipTarget">Ship that will be the target</param> public TargetTN(ShipTN ShipTarget) : base() { TargetType = ShipTarget.ShipsTaskGroup.SSEntity; Ship = ShipTarget; }