/// <summary> /// ECCM needs to be handled eventually /// </summary> /// <summary> /// Constructor for Missile Fire Controls /// </summary> /// <param name="MFCDef">MFC definition.</param> public MissileFireControlTN(ActiveSensorDefTN MFCDef) { m_oMFCSensorDef = MFCDef; isDestroyed = false; m_lLinkedWeapons = new BindingList <MissileLauncherTN>(); m_lMissilesInFlight = new BindingList <OrdnanceGroupTN>(); m_oOpenFire = false; m_oTarget = null; m_oPDState = PointDefenseState.None; m_oPDRange = 0; }
/// <summary> /// Simple deassignment of target to this mfc. /// </summary> public void clearTarget() { m_oTarget = null; }
/// <summary> /// Target assignment of waypoints. /// </summary> /// <param name="WPTarget">Waypoint</param> public void assignTarget(Waypoint WPTarget) { m_oTarget = new TargetTN(WPTarget); }
/// <summary> /// Target assignment of populations /// </summary> /// <param name="PopTarget">Population</param> public void assignTarget(Population PopTarget) { m_oTarget = new TargetTN(PopTarget); }
/// <summary> /// Target assignment of planets. /// </summary> /// <param name="PlanetTarget">planet</param> public void assignTarget(SystemBody PlanetTarget) { m_oTarget = new TargetTN(PlanetTarget); }
/// <summary> /// Simple assignment of a missile group as the target of this MFC /// </summary> /// <param name="OrdnanceTarget">missile group to be targetted.</param> public void assignTarget(OrdnanceGroupTN OrdnanceTarget) { m_oTarget = new TargetTN(OrdnanceTarget); }
/// <summary> /// This function calculates whether a given BFC can intercept a missile /// </summary> /// <param name="RNG">RNG to use, should be the global one in _SE_</param> /// <param name="IncrementDistance">Range to the target missile</param> /// <param name="Ordnance">Ordnance we want to shoot at.</param> /// <param name="ShipFaction">Faction of the ship this BFC is on.</param> /// <param name="Contact">Contact of the taskgroup this BFC is in.</param> /// <param name="ShipOn">Ship this BFC is on.</param> /// <param name="WeaponsFired">Whether or not a weapon was fired. this is for the recharge list further up</param> /// <returns>whether the missile was intercepted.</returns> public bool InterceptTarget(Random RNG, int IncrementDistance, OrdnanceTN Ordnance, Faction ShipFaction, SystemContact Contact, ShipTN ShipOn, out bool WeaponsFired) { WeaponsFired = false; float ShipSpeed = ShipOn.CurrentSpeed; float track = (float)ShipFaction.BaseTracking; if (ShipSpeed > track) track = ShipSpeed; if (m_oBeamFireControlDef.tracking < track) track = m_oBeamFireControlDef.tracking; /// <summary> /// Throwaway target for point defense purposes. /// </summary> TargetTN OverrideTarget = new TargetTN(Ordnance.missileGroup); float Acc = GetFiringAccuracy(IncrementDistance, (int)track, OverrideTarget); int toHit = (int)Math.Floor(Acc * 100.0f); int range = (IncrementDistance + 1) * 10000; String Range = range.ToString("#,###0"); foreach (BeamTN LinkedWeapon in m_lLinkedWeapons) { /// <summary> /// Certain weapons will have already fired one or more of their shots, but may still have more available. /// </summary> bool AcceptPartialFire = (LinkedWeapon.beamDef.componentType == ComponentTypeTN.Rail || LinkedWeapon.beamDef.componentType == ComponentTypeTN.AdvRail || LinkedWeapon.beamDef.componentType == ComponentTypeTN.Gauss) && (LinkedWeapon.shotsExpended < LinkedWeapon.beamDef.shotCount); if (LinkedWeapon.readyToFire() == true || AcceptPartialFire == true) { if (LinkedWeapon.beamDef.componentType == ComponentTypeTN.Rail || LinkedWeapon.beamDef.componentType == ComponentTypeTN.AdvRail || LinkedWeapon.beamDef.componentType == ComponentTypeTN.Gauss) { WeaponsFired = LinkedWeapon.Fire(); /// <summary> /// multi-hit weapons will be a little wierd as far as PD goes. /// </summary> if (WeaponsFired == false && AcceptPartialFire == true) WeaponsFired = true; int expended = LinkedWeapon.shotsExpended; int ShotCount = LinkedWeapon.beamDef.shotCount; for (int BeamShotIterator = expended; BeamShotIterator < ShotCount; BeamShotIterator++) { ushort Hit = (ushort)RNG.Next(1, 100); LinkedWeapon.shotsExpended++; if (toHit >= Hit) { String Entry = String.Format("{0} Fired at {1} km and hit.", LinkedWeapon.Name, Range); MessageEntry Msg = new MessageEntry(MessageEntry.MessageType.FiringHit, Contact.Position.System, Contact, GameState.Instance.GameDateTime, GameState.Instance.LastTimestep, Entry); ShipFaction.MessageLog.Add(Msg); return true; } else { String Entry = String.Format("{0} Fired at {1} km and missed.", LinkedWeapon.Name, Range); MessageEntry Msg = new MessageEntry(MessageEntry.MessageType.FiringHit, Contact.Position.System, Contact, GameState.Instance.GameDateTime, GameState.Instance.LastTimestep, Entry); ShipFaction.MessageLog.Add(Msg); } } } else { ushort Hit = (ushort)RNG.Next(1, 100); WeaponsFired = LinkedWeapon.Fire(); if (toHit >= Hit) { String Entry = String.Format("{0} Fired at {1} km and hit.", LinkedWeapon.Name, Range); MessageEntry Msg = new MessageEntry(MessageEntry.MessageType.FiringHit, Contact.Position.System, Contact, GameState.Instance.GameDateTime, GameState.Instance.LastTimestep, Entry); ShipFaction.MessageLog.Add(Msg); return true; } else { String Entry = String.Format("{0} Fired at {1} km and missed.", LinkedWeapon.Name, Range); MessageEntry Msg = new MessageEntry(MessageEntry.MessageType.FiringHit, Contact.Position.System, Contact, GameState.Instance.GameDateTime, GameState.Instance.LastTimestep, Entry); ShipFaction.MessageLog.Add(Msg); } } } } foreach (TurretTN LinkedTurret in m_lLinkedTurrets) { /// <summary> /// Double, triple, and quad turrets have multiple shots. /// </summary> bool AcceptPartialFire = (LinkedTurret.shotsExpended < LinkedTurret.turretDef.totalShotCount); if (LinkedTurret.readyToFire() == true || AcceptPartialFire == true) { WeaponsFired = LinkedTurret.Fire(); /// <summary> /// multi-hit weapons will be a little wierd as far as PD goes. /// </summary> if (WeaponsFired == false && AcceptPartialFire == true) WeaponsFired = true; int expended = LinkedTurret.shotsExpended; int ShotCount = LinkedTurret.turretDef.totalShotCount; for (int TurretShotIterator = expended; TurretShotIterator < ShotCount; TurretShotIterator++) { ushort Hit = (ushort)RNG.Next(1, 100); LinkedTurret.shotsExpended++; if (toHit >= Hit) { String Entry = String.Format("{0} Fired at {1} km and hit.", LinkedTurret.Name, Range); MessageEntry Msg = new MessageEntry(MessageEntry.MessageType.FiringHit, Contact.Position.System, Contact, GameState.Instance.GameDateTime, GameState.Instance.LastTimestep, Entry); ShipFaction.MessageLog.Add(Msg); return true; } else { String Entry = String.Format("{0} Fired at {1} km and missed.", LinkedTurret.Name, Range); MessageEntry Msg = new MessageEntry(MessageEntry.MessageType.FiringHit, Contact.Position.System, Contact, GameState.Instance.GameDateTime, GameState.Instance.LastTimestep, Entry); ShipFaction.MessageLog.Add(Msg); } } } } return false; }
/// <summary> /// Searches for a new missile or ship target. /// </summary> private void SearchForNewTarget() { bool hasSystem = ordnanceGroupFaction.DetectedContactLists.ContainsKey(Contact.Position.System); if (hasSystem) { /// <summary> /// Search for missile targets. /// </summary> #warning magic number related to missile sensor resolution and target checking. Only res 1 sensors will go after missiles. if (Missiles[0].missileDef.aSD.resolution == 1) { foreach (KeyValuePair<OrdnanceGroupTN, FactionContact> pair in ordnanceGroupFaction.DetectedContactLists[Contact.Position.System].DetectedMissileContacts) { /// <summary> /// active detection exists for this missile group, and it hasn't been destroyed. /// </summary> if (pair.Value.active == true && pair.Key.missilesDestroyed != pair.Key.Missiles.Count) { float dist; Contact.DistTable.GetDistance(pair.Key.contact, out dist); int detection = missiles[0].missileDef.aSD.GetActiveDetectionRange(0, (int)Math.Ceiling(pair.Key.missiles[0].missileDef.size)); bool det = ordnanceGroupFaction.LargeDetection(dist, detection); if (det == true) { /// <summary> /// This is our new target. /// </summary> TargetTN newMissileTarget = new TargetTN(pair.Key); for (int loop = 0; loop < Missiles.Count; loop++) { Missiles[loop].target = newMissileTarget; } /// <summary> /// sensor missiles may as well be treated like point defense missiles here, since they aren't connected to an MFC. /// </summary> pair.Key.ordGroupsTargetting.Add(this); break; } } } } else { /// <summary> /// search for ship targets. /// </summary> foreach (KeyValuePair<ShipTN, FactionContact> pair in ordnanceGroupFaction.DetectedContactLists[Contact.Position.System].DetectedContacts) { /// <summary> /// Active tracking on this ship exists, and the ship itself hasn't been destroyed. If the ship is destroyed it will be cleaned up at the end of simEntity. /// </summary> if (pair.Value.active == true && pair.Key.IsDestroyed == false) { float dist; Contact.DistTable.GetDistance(pair.Key.ShipsTaskGroup.Contact, out dist); int detection = missiles[0].missileDef.aSD.GetActiveDetectionRange(Missiles[0].target.ship.TotalCrossSection, -1); bool det = ordnanceGroupFaction.LargeDetection(dist, detection); if (det == true) { /// <summary> /// This is our new target. /// </summary> TargetTN newShipTarget = new TargetTN(pair.Key); for (int loop = 0; loop < Missiles.Count; loop++) { Missiles[loop].target = newShipTarget; } break; } } } } } }
/// <summary> /// Get the accuracy at which this BFC can fire upon its target. /// </summary> /// <param name="RangeIncrement">distance to target</param> /// <param name="track">Tracking capability of beam weapon that accuracy is desired for.</param> /// <param name="Override">For FCs in PD mode, there will be no target, they should use override instead.</param> /// <returns>Firing accuracy.</returns> private float GetFiringAccuracy(int RangeIncrement, int track, TargetTN Override = null) { float FireAccuracy = m_oBeamFireControlDef.rangeAccuracyTable[RangeIncrement]; TargetTN MyTarget = m_oTarget; if (MyTarget == null && Override != null) { MyTarget = Override; } /// <summary> /// Get Target_CurrentSpeed for accuracy calculations. Planets do not move so this can remain at 0 for that. int Target_CurrentSpeed = 0; switch (MyTarget.targetType) { case StarSystemEntityType.TaskGroup: Target_CurrentSpeed = MyTarget.ship.CurrentSpeed; break; case StarSystemEntityType.Missile: Target_CurrentSpeed = (int)Math.Round(MyTarget.missileGroup.missiles[0].missileDef.maxSpeed); break; } /// <summary> /// 100% accuracy due to tracking at this speed if this condition fails and target speed is less than or equal to tracking[99] /// </summary> if ((float)Target_CurrentSpeed > m_oBeamFireControlDef.trackingAccuracyTable[99]) { /// <summary> /// 1% chance to hit thanks to tracking being totally out classed. /// </summary> if ((float)Target_CurrentSpeed >= m_oBeamFireControlDef.trackingAccuracyTable[0]) { FireAccuracy = FireAccuracy * 0.01f; } else { bool done = false; int Base = 50; int Cur = 50; /// <summary> /// Binary search through the tracking accuracy table. Base is base accuracy of 50, and Cur is where we are in the binary search. /// The tracking accuracy table has 100 entries. /// </summary> while (!done) { /// <summary> /// divide Cur by 2 as per binary search. /// </summary> Cur = Cur / 2; /// <summary> /// if the targets speed is greater than tracking at base go to the next condition. basically these two advance base forward by cur until Cur is reduced to 1 which /// indicates that there is no more granularity to be observed. /// </summary> if ((float)Target_CurrentSpeed > m_oBeamFireControlDef.trackingAccuracyTable[Base]) { /// <summary> /// If Cur is equal to one then either Base or Base - 1 is the accuracy we want. If its not one then it can be further subdivided. /// </summary> if (Cur == 1) { /// <summary> /// Is the speed of the target closer to tracking[base] or tracking[base-1]? /// </summary> float t1 = (float)Target_CurrentSpeed - m_oBeamFireControlDef.trackingAccuracyTable[Base]; float t2 = (float)Target_CurrentSpeed - m_oBeamFireControlDef.trackingAccuracyTable[Base - 1]; if (t1 <= t2) { FireAccuracy = FireAccuracy * ((float)Base / 100.0f); done = true; } else { FireAccuracy = FireAccuracy * ((float)(Base - 1) / 100.0f); done = true; } } Base = Base - Cur; } else if ((float)Target_CurrentSpeed < m_oBeamFireControlDef.trackingAccuracyTable[Base]) { if (Cur == 1) { float t1 = m_oBeamFireControlDef.trackingAccuracyTable[Base] - (float)Target_CurrentSpeed; float t2 = m_oBeamFireControlDef.trackingAccuracyTable[Base + 1] - (float)Target_CurrentSpeed; if (t1 <= t2) { FireAccuracy = FireAccuracy * ((float)Base / 100.0f); done = true; } else { FireAccuracy = FireAccuracy * ((float)(Base + 1) / 100.0f); done = true; } } Base = Base + Cur; } else { FireAccuracy = FireAccuracy * ((float)Base / 100.0f); done = true; } } } } if (track < m_oBeamFireControlDef.tracking) { float fireAccMod = (float)track / m_oBeamFireControlDef.tracking; FireAccuracy = FireAccuracy * fireAccMod; } return FireAccuracy; }
/// <summary> /// The Fire control itself must determine if the target is in range of both itself and its weapons. /// </summary> /// <param name="DistanceToTarget">distance in KM to target.</param> /// <param name="RNG">RNG passed to this function from source further up the chain.</param> /// <param name="track">Base empire tracking or ship speed ,whichever is higher. Turrets should set track to their tracking speed.</param> /// <returns>Whether or not a weapon was able to fire.</returns> public bool FireWeapons(float DistanceToTarget, Random RNG, int track, ShipTN FiringShip) { if (DistanceToTarget > m_oBeamFireControlDef.range || (m_lLinkedWeapons.Count == 0 && m_lLinkedTurrets.Count == 0) || isDestroyed == true) { if (DistanceToTarget > m_oBeamFireControlDef.range) { MessageEntry NMsg = new MessageEntry(MessageEntry.MessageType.FiringZeroHitChance, FiringShip.ShipsTaskGroup.Contact.Position.System, FiringShip.ShipsTaskGroup.Contact, GameState.Instance.GameDateTime, GameState.Instance.LastTimestep, (this.Name + " Zero % chance to hit.")); FiringShip.ShipsFaction.MessageLog.Add(NMsg); } return false; } else { /// <summary> /// Range * 2 / 10000.0; /// </summary> int RangeIncrement = (int)Math.Floor(DistanceToTarget / 5000.0f); float FireAccuracy = GetFiringAccuracy(RangeIncrement, track); /// <summary> /// Fire Accuracy is the likelyhood of a shot hitting from this FC at this point. /// ECM vs ECCM needs to be done around here as well. /// </summary> bool weaponFired = false; if (m_oTarget.targetType == StarSystemEntityType.TaskGroup) { int toHit = (int)Math.Floor(FireAccuracy * 100.0f); ushort Columns = m_oTarget.ship.ShipArmor.armorDef.cNum; foreach (BeamTN LinkedWeapon in m_lLinkedWeapons) { if (LinkedWeapon.beamDef.range > DistanceToTarget && LinkedWeapon.readyToFire() == true) { RangeIncrement = (int)Math.Floor(DistanceToTarget / 10000.0f); weaponFired = LinkedWeapon.Fire(); if (weaponFired == true) { for (int BeamShotIterator = 0; BeamShotIterator < LinkedWeapon.beamDef.shotCount; BeamShotIterator++) { int Hit = RNG.Next(1, 100); if (toHit >= Hit) { String WeaponFireS = String.Format("{0} hit {1} damage at {2}% tohit", LinkedWeapon.Name, LinkedWeapon.beamDef.damage[RangeIncrement], toHit); MessageEntry NMsg = new MessageEntry(MessageEntry.MessageType.FiringHit, FiringShip.ShipsTaskGroup.Contact.Position.System, FiringShip.ShipsTaskGroup.Contact, GameState.Instance.GameDateTime, GameState.Instance.LastTimestep, WeaponFireS); FiringShip.ShipsFaction.MessageLog.Add(NMsg); ushort location = (ushort)RNG.Next(0, Columns); bool ShipDest = m_oTarget.ship.OnDamaged(LinkedWeapon.beamDef.damageType, LinkedWeapon.beamDef.damage[RangeIncrement], location, FiringShip); if (ShipDest == true) { m_oTarget = null; m_oOpenFire = false; return weaponFired; } } else { String WeaponFireS = String.Format("{0} missed at {1}% tohit", LinkedWeapon.Name, toHit); MessageEntry NMsg = new MessageEntry(MessageEntry.MessageType.FiringMissed, FiringShip.ShipsTaskGroup.Contact.Position.System, FiringShip.ShipsTaskGroup.Contact, GameState.Instance.GameDateTime, GameState.Instance.LastTimestep, WeaponFireS); FiringShip.ShipsFaction.MessageLog.Add(NMsg); } } } else if (LinkedWeapon.isDestroyed == false) { String WeaponFireS = String.Format("{0} Recharging {1}/{2} Power", LinkedWeapon.Name, LinkedWeapon.currentCapacitor, LinkedWeapon.beamDef.weaponCapacitor); MessageEntry NMsg = new MessageEntry(MessageEntry.MessageType.FiringRecharging, FiringShip.ShipsTaskGroup.Contact.Position.System, FiringShip.ShipsTaskGroup.Contact, GameState.Instance.GameDateTime, GameState.Instance.LastTimestep, WeaponFireS); FiringShip.ShipsFaction.MessageLog.Add(NMsg); } } } foreach (TurretTN LinkedTurret in m_lLinkedTurrets) { /// <summary> /// turrets have changed tracking and therefore tohit from regular beams. /// </summary> FireAccuracy = GetFiringAccuracy(RangeIncrement, LinkedTurret.turretDef.tracking); toHit = (int)Math.Floor(FireAccuracy * 100.0f); if (LinkedTurret.turretDef.baseBeamWeapon.range > DistanceToTarget && LinkedTurret.readyToFire() == true) { RangeIncrement = (int)Math.Floor(DistanceToTarget / 10000.0f); weaponFired = LinkedTurret.Fire(); if (weaponFired == true) { for (int TurretShotIterator = 0; TurretShotIterator < LinkedTurret.turretDef.totalShotCount; TurretShotIterator++) { int Hit = RNG.Next(1, 100); if (toHit >= Hit) { String WeaponFireS = String.Format("{0} hit {1} damage at {2}% tohit", LinkedTurret.Name, LinkedTurret.turretDef.baseBeamWeapon.damage[RangeIncrement], toHit); MessageEntry NMsg = new MessageEntry(MessageEntry.MessageType.FiringHit, FiringShip.ShipsTaskGroup.Contact.Position.System, FiringShip.ShipsTaskGroup.Contact, GameState.Instance.GameDateTime, GameState.Instance.LastTimestep, WeaponFireS); FiringShip.ShipsFaction.MessageLog.Add(NMsg); ushort location = (ushort)RNG.Next(0, Columns); bool ShipDest = m_oTarget.ship.OnDamaged(LinkedTurret.turretDef.baseBeamWeapon.damageType, LinkedTurret.turretDef.baseBeamWeapon.damage[RangeIncrement], location, FiringShip); if (ShipDest == true) { m_oTarget = null; m_oOpenFire = false; return weaponFired; } } else { String WeaponFireS = String.Format("{0} missed at {1}% tohit", LinkedTurret.Name, toHit); MessageEntry NMsg = new MessageEntry(MessageEntry.MessageType.FiringMissed, FiringShip.ShipsTaskGroup.Contact.Position.System, FiringShip.ShipsTaskGroup.Contact, GameState.Instance.GameDateTime, GameState.Instance.LastTimestep, WeaponFireS); FiringShip.ShipsFaction.MessageLog.Add(NMsg); } } } else if (LinkedTurret.isDestroyed == false) { String WeaponFireS = String.Format("{0} Recharging {1}/{2} Power", LinkedTurret.Name, LinkedTurret.currentCapacitor, (LinkedTurret.turretDef.baseBeamWeapon.weaponCapacitor * LinkedTurret.turretDef.multiplier)); MessageEntry NMsg = new MessageEntry(MessageEntry.MessageType.FiringRecharging, FiringShip.ShipsTaskGroup.Contact.Position.System, FiringShip.ShipsTaskGroup.Contact, GameState.Instance.GameDateTime, GameState.Instance.LastTimestep, WeaponFireS); FiringShip.ShipsFaction.MessageLog.Add(NMsg); } } } return weaponFired; } else if (m_oTarget.targetType == StarSystemEntityType.Missile) { /// <summary> /// this is for beam targetting on missiles. /// </summary> int toHit = (int)Math.Floor(FireAccuracy * 100.0f); /// <summary> /// have all targeted missiles been destroyed. /// </summary> bool noMissilesLeft = false; /// <summary> /// For all weapons linked to this BFC /// </summary> foreach (BeamTN LinkedWeapon in m_lLinkedWeapons) { /// <summary> /// if range > distance and the weapon is ready to fire. /// </summary> if (LinkedWeapon.beamDef.range > DistanceToTarget && LinkedWeapon.readyToFire() == true) { RangeIncrement = (int)Math.Floor(DistanceToTarget / 10000.0f); weaponFired = LinkedWeapon.Fire(); if (weaponFired == true) { /// <summary> /// Some weapons have multiple shots, but most will have just 1. /// </summary> for (int BeamShotIterator = 0; BeamShotIterator < LinkedWeapon.beamDef.shotCount; BeamShotIterator++) { int Hit = RNG.Next(1, 100); /// <summary> /// Did the weapon hit? /// </summary> if (toHit >= Hit) { ushort ToDestroy; if (m_oTarget.missileGroup.missiles[0].missileDef.armor == 0) ToDestroy = 100; else ToDestroy = (ushort)(Math.Round((LinkedWeapon.beamDef.damage[RangeIncrement] / (m_oTarget.missileGroup.missiles[0].missileDef.armor + LinkedWeapon.beamDef.damage[RangeIncrement]))) * 100.0f); ushort DestChance = (ushort)RNG.Next(1, 100); /// <summary> /// Does the weapon have the power to make a kill? /// </summary> if (ToDestroy >= DestChance) { String WeaponFireS = String.Format("{0} and destroyed a missile at {1}% tohit", LinkedWeapon.Name, toHit); MessageEntry NMsg = new MessageEntry(MessageEntry.MessageType.FiringHit, FiringShip.ShipsTaskGroup.Contact.Position.System, FiringShip.ShipsTaskGroup.Contact, GameState.Instance.GameDateTime, GameState.Instance.LastTimestep, WeaponFireS); FiringShip.ShipsFaction.MessageLog.Add(NMsg); /// <summary> /// Set destruction of targeted missile here. This is used by sim entity to determine how to handle missile group cleanup. /// </summary> m_oTarget.missileGroup.missilesDestroyed = m_oTarget.missileGroup.missilesDestroyed + 1; if (m_oTarget.missileGroup.missilesDestroyed == m_oTarget.missileGroup.missiles.Count) { break; } } else { String WeaponFireS = String.Format("{0} and failed to destroyed a missile at {1}% tohit", LinkedWeapon.Name, toHit); MessageEntry NMsg = new MessageEntry(MessageEntry.MessageType.FiringHit, FiringShip.ShipsTaskGroup.Contact.Position.System, FiringShip.ShipsTaskGroup.Contact, GameState.Instance.GameDateTime, GameState.Instance.LastTimestep, WeaponFireS); FiringShip.ShipsFaction.MessageLog.Add(NMsg); } } else { String WeaponFireS = String.Format("{0} missed at {1}% tohit", LinkedWeapon.Name, toHit); MessageEntry NMsg = new MessageEntry(MessageEntry.MessageType.FiringMissed, FiringShip.ShipsTaskGroup.Contact.Position.System, FiringShip.ShipsTaskGroup.Contact, GameState.Instance.GameDateTime, GameState.Instance.LastTimestep, WeaponFireS); FiringShip.ShipsFaction.MessageLog.Add(NMsg); } }//end for shot count } else if (LinkedWeapon.isDestroyed == false) { String WeaponFireS = String.Format("{0} Recharging {1}/{2} Power", LinkedWeapon.Name, LinkedWeapon.currentCapacitor, LinkedWeapon.beamDef.weaponCapacitor); MessageEntry NMsg = new MessageEntry(MessageEntry.MessageType.FiringRecharging, FiringShip.ShipsTaskGroup.Contact.Position.System, FiringShip.ShipsTaskGroup.Contact, GameState.Instance.GameDateTime, GameState.Instance.LastTimestep, WeaponFireS); FiringShip.ShipsFaction.MessageLog.Add(NMsg); } }//end if in range and weapon can fire if (m_oTarget.missileGroup.missilesDestroyed == m_oTarget.missileGroup.missiles.Count) { noMissilesLeft = true; break; } }// end for linked weapons if (noMissilesLeft == false) { foreach (TurretTN LinkedTurret in m_lLinkedTurrets) //(int loop = 0; loop < LinkedTurrets.Count; loop++) { FireAccuracy = GetFiringAccuracy(RangeIncrement, LinkedTurret.turretDef.tracking); toHit = (int)Math.Floor(FireAccuracy * 100.0f); if (LinkedTurret.turretDef.baseBeamWeapon.range > DistanceToTarget && LinkedTurret.readyToFire() == true) { RangeIncrement = (int)Math.Floor(DistanceToTarget / 10000.0f); weaponFired = LinkedTurret.Fire(); if (weaponFired == true) { /// <summary> /// Some weapons have multiple shots, but most will have just 1. /// </summary> for (int TurretShotIterator = 0; TurretShotIterator < LinkedTurret.turretDef.totalShotCount; TurretShotIterator++) { int Hit = RNG.Next(1, 100); /// <summary> /// Did the weapon hit? /// </summary> if (toHit >= Hit) { /// <summary> /// Did the weapon destroy its target? /// </summary> ushort ToDestroy; if (m_oTarget.missileGroup.missiles[0].missileDef.armor == 0) ToDestroy = 100; else ToDestroy = (ushort)(Math.Round((LinkedTurret.turretDef.baseBeamWeapon.damage[RangeIncrement] / (m_oTarget.missileGroup.missiles[0].missileDef.armor + LinkedTurret.turretDef.baseBeamWeapon.damage[RangeIncrement]))) * 100.0f); ushort DestChance = (ushort)RNG.Next(1, 100); /// <summary> /// Does the weapon have the power to make a kill? /// </summary> if (ToDestroy >= DestChance) { String WeaponFireS = String.Format("{0} and destroyed a missile at {1}% tohit", LinkedTurret.Name, toHit); MessageEntry NMsg = new MessageEntry(MessageEntry.MessageType.FiringHit, FiringShip.ShipsTaskGroup.Contact.Position.System, FiringShip.ShipsTaskGroup.Contact, GameState.Instance.GameDateTime, GameState.Instance.LastTimestep, WeaponFireS); FiringShip.ShipsFaction.MessageLog.Add(NMsg); /// <summary> /// Set destruction of targeted missile here. This is used by sim entity to determine how to handle missile group cleanup. /// </summary> m_oTarget.missileGroup.missilesDestroyed = m_oTarget.missileGroup.missilesDestroyed + 1; if (m_oTarget.missileGroup.missilesDestroyed == m_oTarget.missileGroup.missiles.Count) { break; } } else { String WeaponFireS = String.Format("{0} and failed to destroyed a missile at {1}% tohit", LinkedTurret.Name, toHit); MessageEntry NMsg = new MessageEntry(MessageEntry.MessageType.FiringHit, FiringShip.ShipsTaskGroup.Contact.Position.System, FiringShip.ShipsTaskGroup.Contact, GameState.Instance.GameDateTime, GameState.Instance.LastTimestep, WeaponFireS); FiringShip.ShipsFaction.MessageLog.Add(NMsg); } } else { String WeaponFireS = String.Format("{0} missed at {1}% tohit", LinkedTurret.Name, toHit); MessageEntry NMsg = new MessageEntry(MessageEntry.MessageType.FiringMissed, FiringShip.ShipsTaskGroup.Contact.Position.System, FiringShip.ShipsTaskGroup.Contact, GameState.Instance.GameDateTime, GameState.Instance.LastTimestep, WeaponFireS); FiringShip.ShipsFaction.MessageLog.Add(NMsg); } } }//end if weapon fired }//end if in range and can fire if (m_oTarget.missileGroup.missilesDestroyed == m_oTarget.missileGroup.missiles.Count) { /// <summary> /// This is cargo culting and this variable does not need to be set here, but for completeness sake I'll include it. /// </summary> noMissilesLeft = true; break; } }//end for linkedturrets. }//end if noMissilesLeft = true return weaponFired; } else if(m_oTarget.targetType == StarSystemEntityType.Population) { /// <summary> /// Planets can't dodge and will always be hit. /// </summary> foreach (BeamTN LinkedWeapon in m_lLinkedWeapons) { if (LinkedWeapon.beamDef.range > DistanceToTarget && LinkedWeapon.readyToFire() == true) { RangeIncrement = (int)Math.Floor(DistanceToTarget / 10000.0f); weaponFired = LinkedWeapon.Fire(); if (weaponFired == true) { for (int BeamShotIterator = 0; BeamShotIterator < LinkedWeapon.beamDef.shotCount; BeamShotIterator++) { bool PopDamaged = m_oTarget.pop.OnDamaged(LinkedWeapon.beamDef.damageType, LinkedWeapon.beamDef.damage[RangeIncrement], FiringShip); } } } else if (LinkedWeapon.isDestroyed == false) { String WeaponFireS = String.Format("{0} Recharging {1}/{2} Power", LinkedWeapon.Name, LinkedWeapon.currentCapacitor, LinkedWeapon.beamDef.weaponCapacitor); MessageEntry NMsg = new MessageEntry(MessageEntry.MessageType.FiringRecharging, FiringShip.ShipsTaskGroup.Contact.Position.System, FiringShip.ShipsTaskGroup.Contact, GameState.Instance.GameDateTime, GameState.Instance.LastTimestep, WeaponFireS); FiringShip.ShipsFaction.MessageLog.Add(NMsg); } } foreach (TurretTN LinkedTurret in m_lLinkedTurrets) { if (LinkedTurret.turretDef.baseBeamWeapon.range > DistanceToTarget && LinkedTurret.readyToFire() == true) { RangeIncrement = (int)Math.Floor(DistanceToTarget / 10000.0f); weaponFired = LinkedTurret.Fire(); if (weaponFired == true) { for (int TurretShotIterator = 0; TurretShotIterator < LinkedTurret.turretDef.totalShotCount; TurretShotIterator++) { bool ShipDest = m_oTarget.pop.OnDamaged(LinkedTurret.turretDef.baseBeamWeapon.damageType, LinkedTurret.turretDef.baseBeamWeapon.damage[RangeIncrement], FiringShip); } } else if (LinkedTurret.isDestroyed == false) { String WeaponFireS = String.Format("{0} Recharging {1}/{2} Power", LinkedTurret.Name, LinkedTurret.currentCapacitor, (LinkedTurret.turretDef.baseBeamWeapon.weaponCapacitor * LinkedTurret.turretDef.multiplier)); MessageEntry NMsg = new MessageEntry(MessageEntry.MessageType.FiringRecharging, FiringShip.ShipsTaskGroup.Contact.Position.System, FiringShip.ShipsTaskGroup.Contact, GameState.Instance.GameDateTime, GameState.Instance.LastTimestep, WeaponFireS); FiringShip.ShipsFaction.MessageLog.Add(NMsg); } } } return weaponFired; } /// <summary> /// If I am targetting something that BFCs can't handle yet or shouldn't be able to handle just return false for now. /// </summary> return false; } }
/// <summary> /// assignment of a population as the target /// </summary> /// <param name="PopTarget">Population to be targetted</param> public void assignTarget(Population PopTarget) { TargetTN NewPopTarget = new TargetTN(PopTarget); m_oTarget = NewPopTarget; }
/// <summary> /// Assignment of a missile group as a target. /// </summary> /// <param name="OrdGroupTarget">ordnance group to be targetted</param> public void assignTarget(OrdnanceGroupTN OrdGroupTarget) { TargetTN NewOrdTarget = new TargetTN(OrdGroupTarget); m_oTarget = NewOrdTarget; }
/// <summary> /// Simple assignment of a ship as a target to this bfc. /// </summary> /// <param name="ShipTarget">Ship to be targeted.</param> public void assignTarget(ShipTN ShipTarget) { TargetTN NewShipTarget = new TargetTN(ShipTarget); m_oTarget = NewShipTarget; }
/// <summary> /// Constructor for BFC components. /// </summary> /// <param name="definition">Definition of this component</param> public BeamFireControlTN(BeamFireControlDefTN definition) { m_oBeamFireControlDef = definition; isDestroyed = false; m_lLinkedWeapons = new BindingList<BeamTN>(); m_lLinkedTurrets = new BindingList<TurretTN>(); m_oTarget = null; m_oOpenFire = false; m_oPDState = PointDefenseState.None; m_oPDRange = 0; }
/// <summary> /// ECCM needs to be handled eventually /// </summary> /// <summary> /// Constructor for Missile Fire Controls /// </summary> /// <param name="MFCDef">MFC definition.</param> public MissileFireControlTN(ActiveSensorDefTN MFCDef) { m_oMFCSensorDef = MFCDef; isDestroyed = false; m_lLinkedWeapons = new BindingList<MissileLauncherTN>(); m_lMissilesInFlight = new BindingList<OrdnanceGroupTN>(); m_oOpenFire = false; m_oTarget = null; m_oPDState = PointDefenseState.None; m_oPDRange = 0; }
/// <summary> /// Method to create a waypoint target for a missile that has lost tracking to its target. /// </summary> /// <param name="loop">index of missile that needs a waypoint target, they will all be called should this be needed however.</param> private void CreateWaypointTarget() { /// <summary> /// Create new WP Target Here: /// </summary> double X = 0.0, Y = 0.0; switch (missiles[0].target.targetType) { case StarSystemEntityType.TaskGroup: X = missiles[0].target.ship.ShipsTaskGroup.Contact.Position.X; Y = missiles[0].target.ship.ShipsTaskGroup.Contact.Position.Y; break; case StarSystemEntityType.Missile: X = missiles[0].target.missileGroup.contact.Position.X; Y = missiles[0].target.missileGroup.contact.Position.Y; break; } Waypoint NewTarget = new Waypoint("Internal Missile Target, Do Not Display", Contact.Position.System, X, Y, OrdnanceGroupFaction.FactionID); TargetTN newTargetTN = new TargetTN(NewTarget); for (int loop = 0; loop < Missiles.Count; loop++) missiles[loop].target = newTargetTN; }
/// <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> /// 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> /// Target assignment of planets. /// </summary> /// <param name="PlanetTarget">planet</param> public void assignTarget(Planet PlanetTarget) { m_oTarget = new TargetTN(PlanetTarget); }