Beispiel #1
0
        /// <summary>
        /// Constructor for all beam weapon types.
        /// </summary>
        /// <param name="Title">Name of the beam weapon, user entered string, or default string.</param>
        /// <param name="Type">What type of beam weapon this is, note that componentTypeTN encompasses much more than beam weapon types, don't give those values to this function.</param>
        /// <param name="SizeTech">Every beam weapon either has a calibre size, except for particle beams, which use warhead strength, and gauss which give a rate of fire. All use this variable.</param>
        /// <param name="RangeTech">Every beam weapon has a range tech except for plasma carronades which do not have any way to increase range or decrease damage falloff.</param>
        /// <param name="CapacitorTech">Every beam weapon has a capacitor tech associated with it except gauss. Shotcount tech for gauss.</param>
        /// <param name="Reduction">Lasers and Gauss both have size reduction capabilities, though with drawbacks for both types: recharge rate and accuracy respectively.</param>
        public BeamDefTN(String Title, ComponentTypeTN Type, byte SizeTech, byte RangeTech, byte CapacitorTech, float Reduction, MountType MType = MountType.Standard)
        {
#warning function has beam weapon range related magic numbers and others
            if (Type < ComponentTypeTN.Rail || Type > ComponentTypeTN.AdvParticle)
            {
                /// <summary>
                /// Error, bad ID passed to BeamDefTN.
                /// </summary>
                return;
            }
            Id = Guid.NewGuid();
            componentType = Type;

            Name = Title;
            m_oWeaponSizeTech = SizeTech;
            m_oWeaponRangeTech = RangeTech;
            m_oWeaponCapacitorTech = CapacitorTech;
            m_oWeaponCapacitor = Constants.BeamWeaponTN.Capacitor[CapacitorTech];
            m_oWMType = MType;

            m_oShotCount = 1;
            m_oBaseAccuracy = 1.0f;

            m_lDamage = new BindingList<ushort>();

            int RangeIncrement;

            switch (componentType)
            {
                /// <summary>
                /// Laser is the the most basic jack of all trade beam weapon.
                /// </summary>
                case ComponentTypeTN.Laser:

                    /// <summary>
                    /// I Suspect that size is 3.2cm per HS but am just using a table for now.
                    /// </summary>
                    size = (float)Math.Round(Constants.BeamWeaponTN.LaserSize[m_oWeaponSizeTech] * Reduction);

                    /// <summary>
                    /// The first entry in the damage table is max damage at point blank(0-10k range) damage.
                    /// </summary>
                    m_lDamage.Add((ushort)Constants.BeamWeaponTN.LaserDamage[m_oWeaponSizeTech]);

                    /// <summary>
                    /// Have to modify capacitor by size reduction values.
                    /// </summary>
                    if (Reduction == 0.75f)
                        m_oWeaponCapacitor = m_oWeaponCapacitor / 4.0f;
                    else if (Reduction == 0.5f)
                        m_oWeaponCapacitor = m_oWeaponCapacitor / 20.0f;

                    /// <summary>
                    /// Damage, Size, and Range are all modified by spinal mounting:
                    /// </summary>
                    switch (m_oWMType)
                    {
                        case MountType.Spinal:
                            size = (float)Math.Round(size * 1.25f);
                            m_lDamage[0] = (ushort)Math.Round((float)m_lDamage[0] * 1.5f);
                            break;
                        case MountType.AdvancedSpinal:
                            size = (float)Math.Round(size * 1.5f);
                            m_lDamage[0] = (ushort)Math.Round((float)m_lDamage[0] * 2.0f);
                            break;
                    }

                    /// <summary>
                    /// Lasers have the longest range of all beam weapons due to their high damage, normal 10,000km factor and weapon range tech.
                    /// </summary>
                    m_oRange = (float)m_lDamage[0] * 10000.0f * (float)(m_oWeaponRangeTech + 1);

                    /// <summary>
                    /// Lasers require 1 unit of power for every unit of damage that they do.
                    /// </summary>
                    m_oPowerRequirement = m_lDamage[0];

                    /// <summary>
                    /// Subsequent entries up to Wavelength * 10k do full damage, after that the value is:
                    /// FullDamage * ( Wavelength / RangeIncrement Tick) with a minimum of 1 over range.
                    /// </summary>
                    /// 
                    RangeIncrement = (m_oWeaponRangeTech + 1) * m_lDamage[0];
                    CalcDamageTable(RangeIncrement);

                    m_oDamageType = DamageTypeTN.Beam;
                    break;

                case ComponentTypeTN.AdvLaser:
                    size = (float)Math.Round(Constants.BeamWeaponTN.LaserSize[m_oWeaponSizeTech] * Reduction);
                    m_lDamage.Add((ushort)Constants.BeamWeaponTN.AdvancedLaserDamage[m_oWeaponSizeTech]);

                    /// <summary>
                    /// Advanced lasers do more damage per unit of power than regular lasers.
                    /// </summary>
                    m_oPowerRequirement = Constants.BeamWeaponTN.LaserDamage[m_oWeaponSizeTech];

                    /// <summary>
                    /// Have to modify capacitor by size reduction values.
                    /// </summary>
                    if (Reduction == 0.75f)
                        m_oWeaponCapacitor = m_oWeaponCapacitor / 4.0f;
                    else if (Reduction == 0.5f)
                        m_oWeaponCapacitor = m_oWeaponCapacitor / 20.0f;

                    /// <summary>
                    /// Damage, Size, and Range are all modified by spinal mounting:
                    /// </summary>
                    switch (MType)
                    {
                        case MountType.Spinal:
                            size = (float)Math.Round(size * 1.25f);
                            m_lDamage[0] = (ushort)Math.Round((float)m_lDamage[0] * 1.5f);
                            m_oPowerRequirement = (ushort)Math.Round((float)m_oPowerRequirement * 1.5f);
                            break;
                        case MountType.AdvancedSpinal:
                            size = (float)Math.Round(size * 1.5f);
                            m_lDamage[0] = (ushort)Math.Round((float)m_lDamage[0] * 2.0f);
                            m_oPowerRequirement = (ushort)Math.Round((float)m_oPowerRequirement * 2.0f);
                            break;
                    }

                    m_oRange = (float)m_lDamage[0] * 10000.0f * (float)(m_oWeaponRangeTech + 1);

                    RangeIncrement = (m_oWeaponRangeTech + 1) * m_lDamage[0];
                    CalcDamageTable(RangeIncrement);

                    m_oDamageType = DamageTypeTN.Beam;
                    break;

                /// <summary>
                /// Plasmas are essentially cheaper infared lasers.
                /// </summary>
                case ComponentTypeTN.Plasma:
                    m_oWeaponRangeTech = 0;

                    /// <summary>
                    /// I Suspect that size is 3.2cm per HS but am just using a table for now. No reductions for plasma.
                    /// </summary>
                    size = (float)Constants.BeamWeaponTN.LaserSize[m_oWeaponSizeTech];

                    /// <summary>
                    /// Plasma carronades have the same range as an infared laser of equal size.
                    /// </summary>
                    m_oRange = (float)Constants.BeamWeaponTN.LaserDamage[m_oWeaponSizeTech] * 10000.0f * (float)(m_oWeaponRangeTech + 1);

                    /// <summary>
                    /// The first entry in the damage table is max damage at point blank(0-10k range) damage.
                    /// </summary>
                    m_lDamage.Add((ushort)Constants.BeamWeaponTN.LaserDamage[m_oWeaponSizeTech]);

                    /// <summary>
                    /// Plasmas require 1 unit of power for every unit of damage that they do.
                    /// </summary>
                    m_oPowerRequirement = m_lDamage[0];

                    /// <summary>
                    /// Subsequent entries up to Wavelength * 10k do full damage, after that the value is:
                    /// FullDamage * ( Wavelength / RangeIncrement Tick) with a minimum of 1 over range.
                    /// </summary>
                    /// 
                    RangeIncrement = (m_oWeaponRangeTech + 1) * Constants.BeamWeaponTN.LaserDamage[m_oWeaponSizeTech];
                    CalcDamageTable(RangeIncrement);

                    m_oDamageType = DamageTypeTN.Plasma;
                    break;

                case ComponentTypeTN.AdvPlasma:
                    m_oWeaponRangeTech = 0;
                    size = (float)Constants.BeamWeaponTN.LaserSize[m_oWeaponSizeTech];
                    m_oRange = (float)Constants.BeamWeaponTN.AdvancedLaserDamage[m_oWeaponSizeTech] * 10000.0f * (float)(m_oWeaponRangeTech + 1);
                    m_lDamage.Add((ushort)Constants.BeamWeaponTN.AdvancedLaserDamage[m_oWeaponSizeTech]);
                    m_oPowerRequirement = (ushort)Constants.BeamWeaponTN.LaserDamage[m_oWeaponSizeTech];
                    RangeIncrement = (m_oWeaponRangeTech + 1) * Constants.BeamWeaponTN.AdvancedLaserDamage[m_oWeaponSizeTech];
                    CalcDamageTable(RangeIncrement);

                    m_oDamageType = DamageTypeTN.Plasma;
                    break;

                /// <summary>
                /// Railguns have a higher damage than lasers of equal size, though it is spread out over many hits.
                /// Likewise railguns are not suitable for turrets, lastly railguns don't have the full tech progression that lasers have.
                /// Railguns and especially advanced railguns are also power efficient as far as the damage that they do.
                /// </summary>
                case ComponentTypeTN.Rail:
                    m_oShotCount = 4;

                    size = (float)Constants.BeamWeaponTN.RailGunSize[m_oWeaponSizeTech];
                    m_oRange = (float)Constants.BeamWeaponTN.RailGunDamage[m_oWeaponSizeTech] * 10000.0f * (m_oWeaponRangeTech + 1);
                    m_lDamage.Add((ushort)Constants.BeamWeaponTN.RailGunDamage[m_oWeaponSizeTech]);
                    m_oPowerRequirement = (ushort)(Constants.BeamWeaponTN.RailGunDamage[m_oWeaponSizeTech] * 3);
                    RangeIncrement = (m_oWeaponRangeTech + 1) * Constants.BeamWeaponTN.RailGunDamage[m_oWeaponSizeTech];
                    CalcDamageTable(RangeIncrement);

                    m_oDamageType = DamageTypeTN.Kinetic;
                    break;

                /// <summary>
                /// Only difference here is 1 more shot.
                /// </summary>
                case ComponentTypeTN.AdvRail:
                    m_oShotCount = 5;

                    size = (float)Constants.BeamWeaponTN.RailGunSize[m_oWeaponSizeTech];
                    m_oRange = (float)Constants.BeamWeaponTN.RailGunDamage[m_oWeaponSizeTech] * 10000.0f * (m_oWeaponRangeTech + 1);
                    m_lDamage.Add((ushort)Constants.BeamWeaponTN.RailGunDamage[m_oWeaponSizeTech]);
                    m_oPowerRequirement = (ushort)(Constants.BeamWeaponTN.RailGunDamage[m_oWeaponSizeTech] * 3);
                    RangeIncrement = (m_oWeaponRangeTech + 1) * Constants.BeamWeaponTN.RailGunDamage[m_oWeaponSizeTech];
                    CalcDamageTable(RangeIncrement);

                    m_oDamageType = DamageTypeTN.Kinetic;
                    break;

                /// <summary>
                /// Mesons have half the range that lasers have, and only do 1 damage, but always pass through armor and shields.
                /// </summary>
                case ComponentTypeTN.Meson:

                    size = (float)Constants.BeamWeaponTN.LaserSize[m_oWeaponSizeTech];
                    m_oRange = (float)Constants.BeamWeaponTN.LaserDamage[m_oWeaponSizeTech] * 5000.0f * (float)(m_oWeaponRangeTech + 1);

                    m_lDamage.Add(1);
                    m_oPowerRequirement = (ushort)Constants.BeamWeaponTN.LaserDamage[m_oWeaponSizeTech];
                    RangeIncrement = (((m_oWeaponRangeTech + 1) * Constants.BeamWeaponTN.LaserDamage[m_oWeaponSizeTech]) / 2);
                    for (int loop = 1; loop < RangeIncrement; loop++)
                    {
                        m_lDamage.Add(1);
                    }
                    m_lDamage.Add(0);

                    m_oDamageType = DamageTypeTN.Meson;
                    break;

                /// <summary>
                /// Microwaves do electronic only damage, though they do triple against shields. this isn't very useful though as they don't do triple normal laser damage vs shields, just 3.
                /// They share 1/2 range with mesons, but can't be turreted.
                /// </summary>
                case ComponentTypeTN.Microwave:

                    size = (float)Constants.BeamWeaponTN.LaserSize[m_oWeaponSizeTech];
                    m_oRange = (float)Constants.BeamWeaponTN.LaserDamage[m_oWeaponSizeTech] * 5000.0f * (float)(m_oWeaponRangeTech + 1);

                    m_lDamage.Add(1);
                    m_oPowerRequirement = (ushort)Constants.BeamWeaponTN.LaserDamage[m_oWeaponSizeTech];

                    RangeIncrement = (((m_oWeaponRangeTech + 1) * Constants.BeamWeaponTN.LaserDamage[m_oWeaponSizeTech]) / 2);
                    for (int loop = 1; loop < RangeIncrement; loop++)
                    {
                        m_lDamage.Add(1);
                    }
                    m_lDamage.Add(0);

                    m_oDamageType = DamageTypeTN.Microwave;
                    break;

                /// <summary>
                /// Particle Beams suffer no range dissipation so will out damage lasers at their maximum range, but are shorter ranged than lasers.
                /// WeaponSizeTech for particle beams is their warhead strength, not any focal lense size as with lasers.
                /// </summary>
                case ComponentTypeTN.Particle:

                    size = (float)Constants.BeamWeaponTN.ParticleSize[m_oWeaponSizeTech];
                    m_oRange = (float)Constants.BeamWeaponTN.ParticleRange[m_oWeaponRangeTech] * 10000.0f;
                    m_oPowerRequirement = (ushort)Constants.BeamWeaponTN.ParticlePower[m_oWeaponSizeTech];

                    m_lDamage.Add(Constants.BeamWeaponTN.ParticleDamage[m_oWeaponSizeTech]);
                    RangeIncrement = Constants.BeamWeaponTN.ParticleRange[m_oWeaponRangeTech];
                    for (int loop = 1; loop < RangeIncrement; loop++)
                    {
                        m_lDamage.Add(Constants.BeamWeaponTN.ParticleDamage[m_oWeaponSizeTech]);
                    }
                    m_lDamage.Add(0);

                    m_oDamageType = DamageTypeTN.Kinetic;
                    break;

                /// <summary>
                /// More damage is the only change for advanced particle beams.
                /// </summary>
                case ComponentTypeTN.AdvParticle:

                    size = (float)Constants.BeamWeaponTN.ParticleSize[m_oWeaponSizeTech];
                    m_oRange = (float)Constants.BeamWeaponTN.ParticleRange[m_oWeaponRangeTech] * 10000.0f;
                    m_oPowerRequirement = (ushort)Constants.BeamWeaponTN.ParticlePower[m_oWeaponSizeTech];

                    m_lDamage.Add(Constants.BeamWeaponTN.AdvancedParticleDamage[m_oWeaponSizeTech]);
                    RangeIncrement = Constants.BeamWeaponTN.ParticleRange[m_oWeaponRangeTech];
                    for (int loop = 1; loop < RangeIncrement; loop++)
                    {
                        m_lDamage.Add(Constants.BeamWeaponTN.AdvancedParticleDamage[m_oWeaponSizeTech]);
                    }
                    m_lDamage.Add(0);

                    m_oDamageType = DamageTypeTN.Kinetic;
                    break;

                /// <summary>
                /// Gauss Cannons differ substantially from other beam weapons. Size is determined directly from a size vs accuracy choice.
                /// Likewise capacitor refers to shotcount rather than any capacitor technology.
                /// </summary>
                case ComponentTypeTN.Gauss:
                    size = Constants.BeamWeaponTN.GaussSize[m_oWeaponSizeTech];
                    m_oRange = (m_oWeaponRangeTech + 1) * 10000.0f;
                    m_oShotCount = Constants.BeamWeaponTN.GaussShots[CapacitorTech];
                    m_oBaseAccuracy = Constants.BeamWeaponTN.GaussAccuracy[m_oWeaponSizeTech];
                    m_oPowerRequirement = 0;
                    m_lDamage.Add(1);
                    RangeIncrement = (m_oWeaponRangeTech + 1);
                    for (int loop = 1; loop < RangeIncrement; loop++)
                    {
                        m_lDamage.Add(1);
                    }
                    m_lDamage.Add(0);

                    m_oDamageType = DamageTypeTN.Kinetic;
                    break;
            }

            /// <summary>
            /// Gauss cannons just have to be different.
            /// </summary>
            if (componentType != ComponentTypeTN.Gauss)
            {
                htk = (byte)(size / 2.0f);
                crew = (byte)(size * 2.0f);

                /// <summary>
                /// This isn't how aurora does cost, I couldn't quite figure that out. seems like it might be a table.
                /// well in any event cost is simply the hit to kill * weapon tech level + 1 * weapon capacitor tech level + 1.
                /// </summary>
                cost = (decimal)((int)htk * (int)(m_oWeaponRangeTech + 1) * (int)(m_oWeaponCapacitor + 1));

                m_oROF = (ushort)((ushort)Math.Ceiling((float)((float)m_oPowerRequirement / (float)m_oWeaponCapacitor)) * 5);
            }
            else
            {
                /// <summary>
                /// Gauss data here.
                /// </summary>
                if (size == 6.0 || size == 5.0 || size == 4.0)
                    htk = 2;
                else if (size >= 1.0)
                    htk = 1;
                else
                    htk = 0;

                crew = (byte)(size * 2.0f);
                cost = (decimal)((size * 2.0f) * (float)(m_oWeaponRangeTech + 1) * (float)(m_oWeaponCapacitor + 1));

                m_oROF = 5;
            }

            minerialsCost = new decimal[Constants.Minerals.NO_OF_MINERIALS];
            for (int mineralIterator = 0; mineralIterator < (int)Constants.Minerals.MinerialNames.MinerialCount; mineralIterator++)
            {
                minerialsCost[mineralIterator] = 0;
            }
            switch (componentType)
            {
                case ComponentTypeTN.Laser:
                case ComponentTypeTN.AdvLaser:
                case ComponentTypeTN.Plasma:
                case ComponentTypeTN.AdvPlasma:
                case ComponentTypeTN.Particle:
                case ComponentTypeTN.AdvParticle:
                case ComponentTypeTN.Meson:
                case ComponentTypeTN.Microwave: //20%D 20%B 60%C
                    minerialsCost[(int)Constants.Minerals.MinerialNames.Duranium] = cost * 0.2m;
                    minerialsCost[(int)Constants.Minerals.MinerialNames.Boronide] = cost * 0.2m;
                    minerialsCost[(int)Constants.Minerals.MinerialNames.Corundium] = cost * 0.6m;
                    break;

                case ComponentTypeTN.Rail:
                case ComponentTypeTN.AdvRail: //20%D 20%B 60%N
                    minerialsCost[(int)Constants.Minerals.MinerialNames.Duranium] = cost * 0.2m;
                    minerialsCost[(int)Constants.Minerals.MinerialNames.Boronide] = cost * 0.2m;
                    minerialsCost[(int)Constants.Minerals.MinerialNames.Neutronium] = cost * 0.6m;
                    break;

                case ComponentTypeTN.Gauss: //100%V
                    minerialsCost[(int)Constants.Minerals.MinerialNames.Vendarite] = cost;
                    break;
            }


            isMilitary = true;
            isObsolete = false;
            isDivisible = false;
            isSalvaged = false;
            isElectronic = false;
        }
Beispiel #2
0
        public DamageTableTN(DamageTypeTN DamageType, ushort Damage)
            : base()
        {
            Type        = DamageType;
            DamageTotal = Damage;
            Spread      = 1;

            switch (Type)
            {
            /// <summary>
            /// Beams are the best at penetrating armor.
            /// </summary>
            case DamageTypeTN.Beam:

                /// <summary>
                /// As near as I can tell higher power beams are better at penetration overall than lower power beams.
                /// </summary>
                if (DamageTotal > 128)
                {
                    Penetration = 5;
                }
                else if (DamageTotal > 64)
                {
                    Penetration = 4;
                }
                else
                {
                    Penetration = 3;
                }
                break;

            /// <summary>
            /// Railguns and particle beams are not as good at penetrating armor, but have other characteristics that are valuable.
            /// </summary>
            case DamageTypeTN.Kinetic:
                Penetration = 2;
                break;

            /// <summary>
            /// Plasma likewise roils over armor, but is cheap and does plenty of damage.
            /// Actual penetration is in effect 1/2.
            /// </summary>
            case DamageTypeTN.Plasma:
                Penetration = 1;
                break;

            /// <summary>
            /// Missiles are the premier weapon of the game, and have the weakest penetration overall.
            /// </summary>
            case DamageTypeTN.Missile:
                Penetration = 1;
                break;
            }

            /// <summary>
            /// Initialize the damage template.
            /// </summary>
            DamageTemplate = new BindingList <ushort>();
            for (int loop = 0; loop < 200; loop++)
            {
                DamageTemplate.Add(0);
            }

            HitPoint = 100;

            /// <summary>
            /// Plasmas actually have what is effectively 1/2 penetration.
            if (Type != DamageTypeTN.Plasma)
            {
                int RemainingDamage = DamageTotal;

                if (RemainingDamage > Penetration)
                {
                    DamageTemplate[HitPoint] = Penetration;
                    RemainingDamage          = RemainingDamage - Penetration;
                }
                else
                {
                    DamageTemplate[HitPoint] = (ushort)RemainingDamage;
                    RemainingDamage          = 0;
                }

                /// <summary>
                /// Do damage spread.
                /// </summary>
                while (RemainingDamage > 0)
                {
                    float DamagePerColumn = (float)((float)RemainingDamage / (float)(Spread + 2));
                    if (DamagePerColumn >= Penetration)
                    {
                        HalfSpread = (int)((float)(Spread + 1) / 2.0f);
                        /// <summary>
                        /// 100 is the arbitrary midpoint for the damage template for the time being, and two is added to spread value every iteration of this
                        /// while loop.
                        /// </summary>
                        for (int loop = (HitPoint - HalfSpread); loop <= (HitPoint + HalfSpread); loop++)
                        {
                            DamageTemplate[loop] = (ushort)(DamageTemplate[loop] + (ushort)Penetration);
                            RemainingDamage      = RemainingDamage - Penetration;
                        }

                        Spread = Spread + 2;
                    }
                    else
                    {
                        int BasePerColumn = (int)Math.Floor(DamagePerColumn);
                        HalfSpread = (int)((float)(Spread + 1) / 2.0f);
                        if (BasePerColumn > 0)
                        {
                            for (int loop = (HitPoint - HalfSpread); loop <= (HitPoint + HalfSpread); loop++)
                            {
                                DamageTemplate[loop] = (ushort)(DamageTemplate[loop] + (ushort)BasePerColumn);
                                RemainingDamage      = RemainingDamage - BasePerColumn;
                            }
                        }

                        for (int loop = (HitPoint - HalfSpread); loop <= (HitPoint + HalfSpread); loop++)
                        {
                            DamageTemplate[loop] = (ushort)(DamageTemplate[loop] + 1);
                            RemainingDamage      = RemainingDamage - 1;

                            if (RemainingDamage == 0)
                            {
                                break;
                            }
                        }
                    }
                }
            }
            else
            {
                /// <summary>
                /// Plasma damage has to be handled a little differently from beams,particle weapons, and missiles. Penetration value is effectively 1/2, and damage to armor spreads out more.
                /// </summary>

                int RemainingDamage = DamageTotal;

                if (RemainingDamage == 1)
                {
                    DamageTemplate[HitPoint] = 1;
                    RemainingDamage          = 0;
                }
                else
                {
                    DamageTemplate[HitPoint]     = 1;
                    DamageTemplate[HitPoint + 1] = 1;
                    RemainingDamage = RemainingDamage - 2;

                    Spread = 2;

                    while (RemainingDamage != 0)
                    {
                        HalfSpread = Spread / 2;

                        for (int loop = HalfSpread; loop >= 0; loop--)
                        {
                            DamageTemplate[HitPoint - loop] = (ushort)(DamageTemplate[HitPoint - loop] + (ushort)1);

                            RemainingDamage = RemainingDamage - 1;
                            if (RemainingDamage == 0)
                            {
                                break;
                            }

                            DamageTemplate[HitPoint + loop + 1] = (ushort)(DamageTemplate[HitPoint + loop + 1] + (ushort)1);

                            RemainingDamage = RemainingDamage - 1;
                            if (RemainingDamage == 0)
                            {
                                break;
                            }
                        }

                        Spread = Spread + 2;
                    }
                }
            }

            /// <summary>
            /// Remove the excess 0s from the template.
            /// </summary>

            int limit = DamageTemplate.Count;

            for (int loop = limit - 1; loop >= 0; loop--)
            {
                if (DamageTemplate[loop] == 0)
                {
                    DamageTemplate.RemoveAt(loop);

                    if (loop < HitPoint)
                    {
                        HitPoint--;
                    }
                }
            }
        }
Beispiel #3
0
        /// <summary>
        /// Constructor for all beam weapon types.
        /// </summary>
        /// <param name="Title">Name of the beam weapon, user entered string, or default string.</param>
        /// <param name="Type">What type of beam weapon this is, note that componentTypeTN encompasses much more than beam weapon types, don't give those values to this function.</param>
        /// <param name="SizeTech">Every beam weapon either has a calibre size, except for particle beams, which use warhead strength, and gauss which give a rate of fire. All use this variable.</param>
        /// <param name="RangeTech">Every beam weapon has a range tech except for plasma carronades which do not have any way to increase range or decrease damage falloff.</param>
        /// <param name="CapacitorTech">Every beam weapon has a capacitor tech associated with it except gauss. Shotcount tech for gauss.</param>
        /// <param name="Reduction">Lasers and Gauss both have size reduction capabilities, though with drawbacks for both types: recharge rate and accuracy respectively.</param>
        public BeamDefTN(String Title, ComponentTypeTN Type, byte SizeTech, byte RangeTech, byte CapacitorTech, float Reduction, MountType MType = MountType.Standard)
        {
#warning function has beam weapon range related magic numbers and others
            if (Type < ComponentTypeTN.Rail || Type > ComponentTypeTN.AdvParticle)
            {
                /// <summary>
                /// Error, bad ID passed to BeamDefTN.
                /// </summary>
                return;
            }
            Id            = Guid.NewGuid();
            componentType = Type;

            Name = Title;
            m_oWeaponSizeTech      = SizeTech;
            m_oWeaponRangeTech     = RangeTech;
            m_oWeaponCapacitorTech = CapacitorTech;
            m_oWeaponCapacitor     = Constants.BeamWeaponTN.Capacitor[CapacitorTech];
            m_oWMType = MType;

            m_oShotCount    = 1;
            m_oBaseAccuracy = 1.0f;

            m_lDamage = new BindingList <ushort>();

            int RangeIncrement;

            switch (componentType)
            {
            /// <summary>
            /// Laser is the the most basic jack of all trade beam weapon.
            /// </summary>
            case ComponentTypeTN.Laser:

                /// <summary>
                /// I Suspect that size is 3.2cm per HS but am just using a table for now.
                /// </summary>
                size = (float)Math.Round(Constants.BeamWeaponTN.LaserSize[m_oWeaponSizeTech] * Reduction);

                /// <summary>
                /// The first entry in the damage table is max damage at point blank(0-10k range) damage.
                /// </summary>
                m_lDamage.Add((ushort)Constants.BeamWeaponTN.LaserDamage[m_oWeaponSizeTech]);

                /// <summary>
                /// Have to modify capacitor by size reduction values.
                /// </summary>
                if (Reduction == 0.75f)
                {
                    m_oWeaponCapacitor = m_oWeaponCapacitor / 4.0f;
                }
                else if (Reduction == 0.5f)
                {
                    m_oWeaponCapacitor = m_oWeaponCapacitor / 20.0f;
                }

                /// <summary>
                /// Damage, Size, and Range are all modified by spinal mounting:
                /// </summary>
                switch (m_oWMType)
                {
                case MountType.Spinal:
                    size         = (float)Math.Round(size * 1.25f);
                    m_lDamage[0] = (ushort)Math.Round((float)m_lDamage[0] * 1.5f);
                    break;

                case MountType.AdvancedSpinal:
                    size         = (float)Math.Round(size * 1.5f);
                    m_lDamage[0] = (ushort)Math.Round((float)m_lDamage[0] * 2.0f);
                    break;
                }

                /// <summary>
                /// Lasers have the longest range of all beam weapons due to their high damage, normal 10,000km factor and weapon range tech.
                /// </summary>
                m_oRange = (float)m_lDamage[0] * 10000.0f * (float)(m_oWeaponRangeTech + 1);

                /// <summary>
                /// Lasers require 1 unit of power for every unit of damage that they do.
                /// </summary>
                m_oPowerRequirement = m_lDamage[0];

                /// <summary>
                /// Subsequent entries up to Wavelength * 10k do full damage, after that the value is:
                /// FullDamage * ( Wavelength / RangeIncrement Tick) with a minimum of 1 over range.
                /// </summary>
                ///
                RangeIncrement = (m_oWeaponRangeTech + 1) * m_lDamage[0];
                CalcDamageTable(RangeIncrement);

                m_oDamageType = DamageTypeTN.Beam;
                break;

            case ComponentTypeTN.AdvLaser:
                size = (float)Math.Round(Constants.BeamWeaponTN.LaserSize[m_oWeaponSizeTech] * Reduction);
                m_lDamage.Add((ushort)Constants.BeamWeaponTN.AdvancedLaserDamage[m_oWeaponSizeTech]);

                /// <summary>
                /// Advanced lasers do more damage per unit of power than regular lasers.
                /// </summary>
                m_oPowerRequirement = Constants.BeamWeaponTN.LaserDamage[m_oWeaponSizeTech];

                /// <summary>
                /// Have to modify capacitor by size reduction values.
                /// </summary>
                if (Reduction == 0.75f)
                {
                    m_oWeaponCapacitor = m_oWeaponCapacitor / 4.0f;
                }
                else if (Reduction == 0.5f)
                {
                    m_oWeaponCapacitor = m_oWeaponCapacitor / 20.0f;
                }

                /// <summary>
                /// Damage, Size, and Range are all modified by spinal mounting:
                /// </summary>
                switch (MType)
                {
                case MountType.Spinal:
                    size                = (float)Math.Round(size * 1.25f);
                    m_lDamage[0]        = (ushort)Math.Round((float)m_lDamage[0] * 1.5f);
                    m_oPowerRequirement = (ushort)Math.Round((float)m_oPowerRequirement * 1.5f);
                    break;

                case MountType.AdvancedSpinal:
                    size                = (float)Math.Round(size * 1.5f);
                    m_lDamage[0]        = (ushort)Math.Round((float)m_lDamage[0] * 2.0f);
                    m_oPowerRequirement = (ushort)Math.Round((float)m_oPowerRequirement * 2.0f);
                    break;
                }

                m_oRange = (float)m_lDamage[0] * 10000.0f * (float)(m_oWeaponRangeTech + 1);

                RangeIncrement = (m_oWeaponRangeTech + 1) * m_lDamage[0];
                CalcDamageTable(RangeIncrement);

                m_oDamageType = DamageTypeTN.Beam;
                break;

            /// <summary>
            /// Plasmas are essentially cheaper infared lasers.
            /// </summary>
            case ComponentTypeTN.Plasma:
                m_oWeaponRangeTech = 0;

                /// <summary>
                /// I Suspect that size is 3.2cm per HS but am just using a table for now. No reductions for plasma.
                /// </summary>
                size = (float)Constants.BeamWeaponTN.LaserSize[m_oWeaponSizeTech];

                /// <summary>
                /// Plasma carronades have the same range as an infared laser of equal size.
                /// </summary>
                m_oRange = (float)Constants.BeamWeaponTN.LaserDamage[m_oWeaponSizeTech] * 10000.0f * (float)(m_oWeaponRangeTech + 1);

                /// <summary>
                /// The first entry in the damage table is max damage at point blank(0-10k range) damage.
                /// </summary>
                m_lDamage.Add((ushort)Constants.BeamWeaponTN.LaserDamage[m_oWeaponSizeTech]);

                /// <summary>
                /// Plasmas require 1 unit of power for every unit of damage that they do.
                /// </summary>
                m_oPowerRequirement = m_lDamage[0];

                /// <summary>
                /// Subsequent entries up to Wavelength * 10k do full damage, after that the value is:
                /// FullDamage * ( Wavelength / RangeIncrement Tick) with a minimum of 1 over range.
                /// </summary>
                ///
                RangeIncrement = (m_oWeaponRangeTech + 1) * Constants.BeamWeaponTN.LaserDamage[m_oWeaponSizeTech];
                CalcDamageTable(RangeIncrement);

                m_oDamageType = DamageTypeTN.Plasma;
                break;

            case ComponentTypeTN.AdvPlasma:
                m_oWeaponRangeTech = 0;
                size     = (float)Constants.BeamWeaponTN.LaserSize[m_oWeaponSizeTech];
                m_oRange = (float)Constants.BeamWeaponTN.AdvancedLaserDamage[m_oWeaponSizeTech] * 10000.0f * (float)(m_oWeaponRangeTech + 1);
                m_lDamage.Add((ushort)Constants.BeamWeaponTN.AdvancedLaserDamage[m_oWeaponSizeTech]);
                m_oPowerRequirement = (ushort)Constants.BeamWeaponTN.LaserDamage[m_oWeaponSizeTech];
                RangeIncrement      = (m_oWeaponRangeTech + 1) * Constants.BeamWeaponTN.AdvancedLaserDamage[m_oWeaponSizeTech];
                CalcDamageTable(RangeIncrement);

                m_oDamageType = DamageTypeTN.Plasma;
                break;

            /// <summary>
            /// Railguns have a higher damage than lasers of equal size, though it is spread out over many hits.
            /// Likewise railguns are not suitable for turrets, lastly railguns don't have the full tech progression that lasers have.
            /// Railguns and especially advanced railguns are also power efficient as far as the damage that they do.
            /// </summary>
            case ComponentTypeTN.Rail:
                m_oShotCount = 4;

                size     = (float)Constants.BeamWeaponTN.RailGunSize[m_oWeaponSizeTech];
                m_oRange = (float)Constants.BeamWeaponTN.RailGunDamage[m_oWeaponSizeTech] * 10000.0f * (m_oWeaponRangeTech + 1);
                m_lDamage.Add((ushort)Constants.BeamWeaponTN.RailGunDamage[m_oWeaponSizeTech]);
                m_oPowerRequirement = (ushort)(Constants.BeamWeaponTN.RailGunDamage[m_oWeaponSizeTech] * 3);
                RangeIncrement      = (m_oWeaponRangeTech + 1) * Constants.BeamWeaponTN.RailGunDamage[m_oWeaponSizeTech];
                CalcDamageTable(RangeIncrement);

                m_oDamageType = DamageTypeTN.Kinetic;
                break;

            /// <summary>
            /// Only difference here is 1 more shot.
            /// </summary>
            case ComponentTypeTN.AdvRail:
                m_oShotCount = 5;

                size     = (float)Constants.BeamWeaponTN.RailGunSize[m_oWeaponSizeTech];
                m_oRange = (float)Constants.BeamWeaponTN.RailGunDamage[m_oWeaponSizeTech] * 10000.0f * (m_oWeaponRangeTech + 1);
                m_lDamage.Add((ushort)Constants.BeamWeaponTN.RailGunDamage[m_oWeaponSizeTech]);
                m_oPowerRequirement = (ushort)(Constants.BeamWeaponTN.RailGunDamage[m_oWeaponSizeTech] * 3);
                RangeIncrement      = (m_oWeaponRangeTech + 1) * Constants.BeamWeaponTN.RailGunDamage[m_oWeaponSizeTech];
                CalcDamageTable(RangeIncrement);

                m_oDamageType = DamageTypeTN.Kinetic;
                break;

            /// <summary>
            /// Mesons have half the range that lasers have, and only do 1 damage, but always pass through armor and shields.
            /// </summary>
            case ComponentTypeTN.Meson:

                size     = (float)Constants.BeamWeaponTN.LaserSize[m_oWeaponSizeTech];
                m_oRange = (float)Constants.BeamWeaponTN.LaserDamage[m_oWeaponSizeTech] * 5000.0f * (float)(m_oWeaponRangeTech + 1);

                m_lDamage.Add(1);
                m_oPowerRequirement = (ushort)Constants.BeamWeaponTN.LaserDamage[m_oWeaponSizeTech];
                RangeIncrement      = (((m_oWeaponRangeTech + 1) * Constants.BeamWeaponTN.LaserDamage[m_oWeaponSizeTech]) / 2);
                for (int loop = 1; loop < RangeIncrement; loop++)
                {
                    m_lDamage.Add(1);
                }
                m_lDamage.Add(0);

                m_oDamageType = DamageTypeTN.Meson;
                break;

            /// <summary>
            /// Microwaves do electronic only damage, though they do triple against shields. this isn't very useful though as they don't do triple normal laser damage vs shields, just 3.
            /// They share 1/2 range with mesons, but can't be turreted.
            /// </summary>
            case ComponentTypeTN.Microwave:

                size     = (float)Constants.BeamWeaponTN.LaserSize[m_oWeaponSizeTech];
                m_oRange = (float)Constants.BeamWeaponTN.LaserDamage[m_oWeaponSizeTech] * 5000.0f * (float)(m_oWeaponRangeTech + 1);

                m_lDamage.Add(1);
                m_oPowerRequirement = (ushort)Constants.BeamWeaponTN.LaserDamage[m_oWeaponSizeTech];

                RangeIncrement = (((m_oWeaponRangeTech + 1) * Constants.BeamWeaponTN.LaserDamage[m_oWeaponSizeTech]) / 2);
                for (int loop = 1; loop < RangeIncrement; loop++)
                {
                    m_lDamage.Add(1);
                }
                m_lDamage.Add(0);

                m_oDamageType = DamageTypeTN.Microwave;
                break;

            /// <summary>
            /// Particle Beams suffer no range dissipation so will out damage lasers at their maximum range, but are shorter ranged than lasers.
            /// WeaponSizeTech for particle beams is their warhead strength, not any focal lense size as with lasers.
            /// </summary>
            case ComponentTypeTN.Particle:

                size                = (float)Constants.BeamWeaponTN.ParticleSize[m_oWeaponSizeTech];
                m_oRange            = (float)Constants.BeamWeaponTN.ParticleRange[m_oWeaponRangeTech] * 10000.0f;
                m_oPowerRequirement = (ushort)Constants.BeamWeaponTN.ParticlePower[m_oWeaponSizeTech];

                m_lDamage.Add(Constants.BeamWeaponTN.ParticleDamage[m_oWeaponSizeTech]);
                RangeIncrement = Constants.BeamWeaponTN.ParticleRange[m_oWeaponRangeTech];
                for (int loop = 1; loop < RangeIncrement; loop++)
                {
                    m_lDamage.Add(Constants.BeamWeaponTN.ParticleDamage[m_oWeaponSizeTech]);
                }
                m_lDamage.Add(0);

                m_oDamageType = DamageTypeTN.Kinetic;
                break;

            /// <summary>
            /// More damage is the only change for advanced particle beams.
            /// </summary>
            case ComponentTypeTN.AdvParticle:

                size                = (float)Constants.BeamWeaponTN.ParticleSize[m_oWeaponSizeTech];
                m_oRange            = (float)Constants.BeamWeaponTN.ParticleRange[m_oWeaponRangeTech] * 10000.0f;
                m_oPowerRequirement = (ushort)Constants.BeamWeaponTN.ParticlePower[m_oWeaponSizeTech];

                m_lDamage.Add(Constants.BeamWeaponTN.AdvancedParticleDamage[m_oWeaponSizeTech]);
                RangeIncrement = Constants.BeamWeaponTN.ParticleRange[m_oWeaponRangeTech];
                for (int loop = 1; loop < RangeIncrement; loop++)
                {
                    m_lDamage.Add(Constants.BeamWeaponTN.AdvancedParticleDamage[m_oWeaponSizeTech]);
                }
                m_lDamage.Add(0);

                m_oDamageType = DamageTypeTN.Kinetic;
                break;

            /// <summary>
            /// Gauss Cannons differ substantially from other beam weapons. Size is determined directly from a size vs accuracy choice.
            /// Likewise capacitor refers to shotcount rather than any capacitor technology.
            /// </summary>
            case ComponentTypeTN.Gauss:
                size                = Constants.BeamWeaponTN.GaussSize[m_oWeaponSizeTech];
                m_oRange            = (m_oWeaponRangeTech + 1) * 10000.0f;
                m_oShotCount        = Constants.BeamWeaponTN.GaussShots[CapacitorTech];
                m_oBaseAccuracy     = Constants.BeamWeaponTN.GaussAccuracy[m_oWeaponSizeTech];
                m_oPowerRequirement = 0;
                m_lDamage.Add(1);
                RangeIncrement = (m_oWeaponRangeTech + 1);
                for (int loop = 1; loop < RangeIncrement; loop++)
                {
                    m_lDamage.Add(1);
                }
                m_lDamage.Add(0);

                m_oDamageType = DamageTypeTN.Kinetic;
                break;
            }

            /// <summary>
            /// Gauss cannons just have to be different.
            /// </summary>
            if (componentType != ComponentTypeTN.Gauss)
            {
                htk  = (byte)(size / 2.0f);
                crew = (byte)(size * 2.0f);

                /// <summary>
                /// This isn't how aurora does cost, I couldn't quite figure that out. seems like it might be a table.
                /// well in any event cost is simply the hit to kill * weapon tech level + 1 * weapon capacitor tech level + 1.
                /// </summary>
                cost = (decimal)((int)htk * (int)(m_oWeaponRangeTech + 1) * (int)(m_oWeaponCapacitor + 1));

                m_oROF = (ushort)((ushort)Math.Ceiling((float)((float)m_oPowerRequirement / (float)m_oWeaponCapacitor)) * 5);
            }
            else
            {
                /// <summary>
                /// Gauss data here.
                /// </summary>
                if (size == 6.0 || size == 5.0 || size == 4.0)
                {
                    htk = 2;
                }
                else if (size >= 1.0)
                {
                    htk = 1;
                }
                else
                {
                    htk = 0;
                }

                crew = (byte)(size * 2.0f);
                cost = (decimal)((size * 2.0f) * (float)(m_oWeaponRangeTech + 1) * (float)(m_oWeaponCapacitor + 1));

                m_oROF = 5;
            }

            minerialsCost = new decimal[Constants.Minerals.NO_OF_MINERIALS];
            for (int mineralIterator = 0; mineralIterator < (int)Constants.Minerals.MinerialNames.MinerialCount; mineralIterator++)
            {
                minerialsCost[mineralIterator] = 0;
            }
            switch (componentType)
            {
            case ComponentTypeTN.Laser:
            case ComponentTypeTN.AdvLaser:
            case ComponentTypeTN.Plasma:
            case ComponentTypeTN.AdvPlasma:
            case ComponentTypeTN.Particle:
            case ComponentTypeTN.AdvParticle:
            case ComponentTypeTN.Meson:
            case ComponentTypeTN.Microwave:     //20%D 20%B 60%C
                minerialsCost[(int)Constants.Minerals.MinerialNames.Duranium]  = cost * 0.2m;
                minerialsCost[(int)Constants.Minerals.MinerialNames.Boronide]  = cost * 0.2m;
                minerialsCost[(int)Constants.Minerals.MinerialNames.Corundium] = cost * 0.6m;
                break;

            case ComponentTypeTN.Rail:
            case ComponentTypeTN.AdvRail:     //20%D 20%B 60%N
                minerialsCost[(int)Constants.Minerals.MinerialNames.Duranium]   = cost * 0.2m;
                minerialsCost[(int)Constants.Minerals.MinerialNames.Boronide]   = cost * 0.2m;
                minerialsCost[(int)Constants.Minerals.MinerialNames.Neutronium] = cost * 0.6m;
                break;

            case ComponentTypeTN.Gauss:     //100%V
                minerialsCost[(int)Constants.Minerals.MinerialNames.Vendarite] = cost;
                break;
            }


            isMilitary   = true;
            isObsolete   = false;
            isDivisible  = false;
            isSalvaged   = false;
            isElectronic = false;
        }
Beispiel #4
0
        /// <summary>
        /// Damage goes through a 3 part process, 1st shields subtract damage, then armor blocks damage, then internals take the hits.
        /// if 20 rolls happen without an internal in the list being targeted then call OnDestroyed(); Mesons skip to the internal damage section.
        /// Microwaves do shield damage, then move to the special electronic only DAC.
        /// </summary>
        /// <param name="Type">Type of damage, for armor penetration.</param>
        /// <param name="Value">How much damage is being done.</param>
        /// <param name="HitLocation">Where Armor damage is inflicted. Temporary argument for the time being. remove these when rngs are resolved.</param>
        /// <returns>Whether or not the ship was destroyed as a result of this action.</returns>
        public bool OnDamaged(DamageTypeTN Type, ushort Value, ushort HitLocation, ShipTN FiringShip)
        {
            ushort Damage = Value;
            ushort internalDamage = 0;
            ushort startDamage = Value;
            bool ColumnPenetration = false;
            int LastColumnValue = ShipArmor.armorDef.depth;

            if (Type != DamageTypeTN.Meson)
            {

                /// <summary>
                /// Handle Shield Damage.
                /// Microwaves do 3 damage to shields. Make them do 3xPowerReq?
                /// </summary>

                if (Type == DamageTypeTN.Microwave)
                {
                    if (CurrentShieldPool >= 3.0f)
                    {
                        CurrentShieldPool = CurrentShieldPool - 3.0f;
                        Damage = 0;
                    }
                    else if (CurrentShieldPool < 1.0f)
                    {
                        CurrentShieldPool = 0.0f;
                    }
                    else
                    {
                        /// <summary>
                        /// Microwaves only do 1 damage to internals, so take away the bonus damage to shields here.
                        /// </summary>
                        Damage = 1;
                        CurrentShieldPool = 0.0f;
                    }
                }
                else
                {
                    if (CurrentShieldPool >= Damage)
                    {
                        CurrentShieldPool = CurrentShieldPool - Damage;
                        Damage = 0;
                    }
                    else if (CurrentShieldPool < 1.0f)
                    {
                        CurrentShieldPool = 0.0f;
                    }
                    else
                    {
                        Damage = (ushort)(Damage - (ushort)Math.Floor(CurrentShieldPool));

                        CurrentShieldPool = 0.0f;
                    }
                }

                /// <summary>
                /// Shields absorbed all damage.
                /// </summary>
                if (Damage == 0)
                {
                    String DamageString = String.Format("All damage to {0} absorbed by shields", Name);
                    MessageEntry NMsg = new MessageEntry(MessageEntry.MessageType.ShipDamage, ShipsTaskGroup.Contact.Position.System, ShipsTaskGroup.Contact,
                                                         GameState.Instance.GameDateTime, GameState.Instance.LastTimestep, DamageString);

                    ShipsFaction.MessageLog.Add(NMsg);

                    return false;
                }
                else
                {

                    if ((startDamage - Damage) > 0)
                    {
                        String DamageString = String.Format("{0} damage to {1} absorbed by shields", (startDamage - Damage), Name);
                        MessageEntry NMsg = new MessageEntry(MessageEntry.MessageType.ShipDamage, ShipsTaskGroup.Contact.Position.System, ShipsTaskGroup.Contact,
                                                             GameState.Instance.GameDateTime, GameState.Instance.LastTimestep, DamageString);

                        ShipsFaction.MessageLog.Add(NMsg);
                    }
                }

                startDamage = Damage;

                if (Type != DamageTypeTN.Microwave)
                {
                    /// <summary>
                    /// Shock Damage:
                    /// </summary>
                    Random ShockRand = new Random((int)startDamage);
                    float ShockChance = (float)Math.Floor(Math.Pow(startDamage, 1.3));
                    int shockTest = ShockRand.Next(0, 100);

                    /// <summary>
                    /// There is a chance for shock damage to occur
                    /// </summary>
                    if (shockTest > ShockChance)
                    {
                        float sTest = (float)ShockRand.Next(0, 100) / 100.0f;
                        internalDamage = (ushort)Math.Floor(((startDamage / 3.0f) * sTest));

                        if (internalDamage != 0)
                        {
                            String DamageString = String.Format("{0} Shock Damage to {1}", (internalDamage), Name);
                            MessageEntry NMsg = new MessageEntry(MessageEntry.MessageType.ShipDamage, ShipsTaskGroup.Contact.Position.System, ShipsTaskGroup.Contact,
                                                                 GameState.Instance.GameDateTime, GameState.Instance.LastTimestep, DamageString);

                            ShipsFaction.MessageLog.Add(NMsg);
                        }
                    }

                    /// <summary>
                    /// Armor Penetration.
                    /// </summary>
                    ushort Columns = ShipArmor.armorDef.cNum;
                    short left, right;

                    ushort ImpactLevel = ShipArmor.armorDef.depth;
                    if (ShipArmor.isDamaged == true)
                        ImpactLevel = ShipArmor.armorColumns[HitLocation];

                    DamageTableTN Table;
                    switch (Type)
                    {
                        case DamageTypeTN.Beam: Table = DamageValuesTN.EnergyTable[Damage - 1];
                            break;
                        case DamageTypeTN.Kinetic: Table = DamageValuesTN.KineticTable[Damage - 1];
                            break;
                        case DamageTypeTN.Missile: Table = DamageValuesTN.MissileTable[Damage - 1];
                            break;
                        case DamageTypeTN.Plasma: Table = DamageValuesTN.PlasmaTable[Damage - 1];
                            break;
                        default:
                            Table = DamageValuesTN.MissileTable[Damage - 1];
                            break;
                    }
                    left = (short)(HitLocation - 1);
                    right = (short)(HitLocation + 1);

                    /// <summary>
                    /// What is the column damage level at Hit Location?
                    /// </summary>
                    if (ShipArmor.isDamaged == true)
                    {
                        LastColumnValue = ShipArmor.armorColumns[HitLocation];
                    }

                    /// <summary>
                    /// internalDamage is all damage that passed through the armour.
                    /// </summary>
                    internalDamage = (ushort)ShipArmor.SetDamage(Columns, ShipArmor.armorDef.depth, HitLocation, Table.damageTemplate[Table.hitPoint]);

                    /// <summary>
                    /// If this is a new penetration note this fact.
                    /// </summary>
                    if (LastColumnValue != 0 && internalDamage != 0)
                    {
                        ColumnPenetration = true;
                    }

                    /// <summary>
                    /// The plasma template is a little wierd and requires handling this condition. basically it has two maximum strength penetration attacks.
                    /// </summary>
                    if (Type == DamageTypeTN.Plasma && Table.hitPoint + 1 < Table.damageTemplate.Count)
                    {

                        if (ShipArmor.isDamaged == true)
                        {
                            LastColumnValue = ShipArmor.armorColumns[(HitLocation + 1)];
                        }

                        internalDamage = (ushort)((ushort)internalDamage + (ushort)ShipArmor.SetDamage(Columns, ShipArmor.armorDef.depth, (ushort)(HitLocation + 1), Table.damageTemplate[Table.hitPoint + 1]));


                        if (LastColumnValue != 0 && internalDamage != 0)
                        {
                            ColumnPenetration = true;
                        }

                        right++;
                    }

                    /// <summary>
                    /// Calculate the armour damage to the left and right of the hitLocation.
                    /// </summary>
                    for (int loop = 1; loop <= Table.halfSpread; loop++)
                    {
                        if (left < 0)
                        {
                            left = (short)(Columns - 1);
                        }
                        if (right >= Columns)
                        {
                            right = 0;
                        }

                        /// <summary>
                        /// side impact damage doesn't always reduce armor, the principle hitpoint should be the site of the deepest armor penetration. Damage can be wasted in this manner.
                        /// </summary>
                        if (Table.hitPoint - loop >= 0)
                        {
                            if (ShipArmor.isDamaged == true)
                            {
                                LastColumnValue = ShipArmor.armorColumns[left];
                            }

                            if (ImpactLevel - Table.damageTemplate[Table.hitPoint - loop] < ShipArmor.armorColumns[left])
                                internalDamage = (ushort)((ushort)internalDamage + (ushort)ShipArmor.SetDamage(Columns, ShipArmor.armorDef.depth, (ushort)left, Table.damageTemplate[Table.hitPoint - loop]));

                            if (LastColumnValue != 0 && internalDamage != 0)
                            {
                                ColumnPenetration = true;
                            }

                        }

                        if (Table.hitPoint + loop < Table.damageTemplate.Count)
                        {
                            if (ShipArmor.isDamaged == true)
                            {
                                LastColumnValue = ShipArmor.armorColumns[right];
                            }

                            if (ImpactLevel - Table.damageTemplate[Table.hitPoint + loop] < ShipArmor.armorColumns[right])
                                internalDamage = (ushort)((ushort)internalDamage + (ushort)ShipArmor.SetDamage(Columns, ShipArmor.armorDef.depth, (ushort)right, Table.damageTemplate[Table.hitPoint + loop]));

                            if (LastColumnValue != 0 && internalDamage != 0)
                            {
                                ColumnPenetration = true;
                            }

                        }

                        left--;
                        right++;
                    }

                    if ((startDamage - internalDamage) > 0)
                    {

                        String DamageString = String.Format("{0} damage to {1} absorbed by Armour", (startDamage - internalDamage), Name);
                        MessageEntry NMsg = new MessageEntry(MessageEntry.MessageType.ShipDamage, ShipsTaskGroup.Contact.Position.System, ShipsTaskGroup.Contact,
                                                             GameState.Instance.GameDateTime, GameState.Instance.LastTimestep, DamageString);

                        ShipsFaction.MessageLog.Add(NMsg);
                    }

                    if (ColumnPenetration == true)
                    {

                        String DamageString = "N/A";

                        /// <summary>
                        /// Need a switch here for organic or solid state ships to change or remove this message.
                        /// </summary>
                        switch (TypeOf)
                        {
                            case ShipType.Standard:
                                DamageString = String.Format("{0} is streaming atmosphere", Name);
                                break;
                            case ShipType.Organic:
                                DamageString = String.Format("{0} is streaming fluid", Name);
                                break;
                        }

                        if (TypeOf == ShipType.Standard || TypeOf == ShipType.Organic)
                        {

                            MessageEntry NMsg = new MessageEntry(MessageEntry.MessageType.ShipDamageReport, FiringShip.ShipsTaskGroup.Contact.Position.System, ShipsTaskGroup.Contact,
                                                                 GameState.Instance.GameDateTime, GameState.Instance.LastTimestep, DamageString);

                            FiringShip.ShipsFaction.MessageLog.Add(NMsg);
                        }
                    }

                }
                else
                {
                    /// <summary>
                    /// This is a microwave strike.
                    /// </summary>
                    internalDamage = 1;
                }
            }
            else
            {
                /// <summary>
                /// This is a meson strike.
                /// </summary>
                internalDamage = 1;
            }

            /// <summary>
            /// Internal Component Damage. Each component with an HTK >0 can take atleast 1 hit. a random number is rolled over the entire dac. the selected component's HTK
            /// is tested against the internal damage value, and if greater than the damage value the component has a chance of surviving. otherwise, the component is destroyed, damage
            /// is reduced, and the next component is chosen.
            /// DAC Should be redone as a binary tree at some later date.
            /// 
            /// The Electronic DAC should be used for microwave hits, ships can't be destroyed due to microwave strikes however.
            /// </summary>
            int Attempts = 0;
            Random DacRNG = new Random(HitLocation);

            if (Type != DamageTypeTN.Microwave)
            {
                /// <summary>
                /// If 20 attempts to damage a component are made unsuccessfully the ship is considered destroyed. Does this scale well with larger ships?
                /// </summary>
                while (Attempts < 20 && internalDamage > 0)
                {
                    int DACHit = DacRNG.Next(1, ShipClass.DamageAllocationChart[ShipClass.ListOfComponentDefs[ShipClass.ListOfComponentDefs.Count - 1]]);

                    int localDAC = 1;
                    int previousDAC = 1;
                    int destroy = -1;
                    for (int loop = 0; loop < ShipClass.ListOfComponentDefs.Count; loop++)
                    {
                        localDAC = ShipClass.DamageAllocationChart[ShipClass.ListOfComponentDefs[loop]];
                        if (DACHit <= localDAC)
                        {
                            float size = ShipClass.ListOfComponentDefs[loop].size;
                            if (size < 1.0)
                                size = 1.0f;

                            destroy = (int)Math.Floor(((float)(DACHit - previousDAC) / (float)size));

                            /// <summary>
                            /// By this point total should definitely be >= destroy. destroy is the HS of the group being hit.
                            /// Should I try to find the exact component hit, or merely loop through all of them?
                            /// internalDamage: Damage done to all internals
                            /// destroy: component to destroy from shipClass.ListOfComponentDefs
                            /// ComponentDefIndex[loop] where in ShipComponents this definition group is.
                            /// </summary>

                            int DamageDone = DestroyComponent(ShipClass.ListOfComponentDefs[loop].componentType, loop, internalDamage, destroy, DacRNG);

                            if (DamageDone != -1)
                            {
                                int ID = ComponentDefIndex[loop] + destroy;

                                if (ShipComponents[ID].isDestroyed == true)
                                {
                                    String DamageString = String.Format("{0} hit by {1} damage and was destroyed", ShipComponents[ID].Name, DamageDone);
                                    MessageEntry NMsg = new MessageEntry(MessageEntry.MessageType.ShipDamage, ShipsTaskGroup.Contact.Position.System, ShipsTaskGroup.Contact,
                                                                         GameState.Instance.GameDateTime, GameState.Instance.LastTimestep, DamageString);

                                    ShipsFaction.MessageLog.Add(NMsg);
                                }
                                else
                                {
                                    String DamageString = String.Format("{0} Absorbed {1} damage", ShipComponents[ID].Name, DamageDone);
                                    MessageEntry NMsg = new MessageEntry(MessageEntry.MessageType.ShipDamage, ShipsTaskGroup.Contact.Position.System, ShipsTaskGroup.Contact,
                                                                         GameState.Instance.GameDateTime, GameState.Instance.LastTimestep, DamageString);

                                    ShipsFaction.MessageLog.Add(NMsg);
                                }
                            }

                            /// <summary>
                            /// No components are left to destroy, so short circuit the loops,destroy the ship, and create a wreck.
                            /// </summary>
                            if (DestroyedComponents.Count == ShipComponents.Count)
                            {
                                Attempts = 20;
                                internalDamage = 0;
                                break;
                            }


                            if (DamageDone == -1)
                            {
                                Attempts++;
                                if (Attempts == 20)
                                {
                                    internalDamage = 0;
                                }
                                break;
                            }
                            else if (DamageDone == -2)
                            {
                                Attempts = 20;
                                break;
                            }
                            else
                            {
                                internalDamage = (ushort)(internalDamage - (ushort)DamageDone);
                                break;
                            }
                        }
                        previousDAC = localDAC + 1;
                    }
                }

                if (Attempts == 20)
                {
                    String DamageString = String.Format("{0} Destroyed", Name);
                    MessageEntry NMsg = new MessageEntry(MessageEntry.MessageType.ShipDamage, ShipsTaskGroup.Contact.Position.System, ShipsTaskGroup.Contact,
                                                         GameState.Instance.GameDateTime, GameState.Instance.LastTimestep, DamageString);

                    ShipsFaction.MessageLog.Add(NMsg);
                    FiringShip.ShipsFaction.MessageLog.Add(NMsg);


                    IsDestroyed = true;
                    return true;
                }
            }
            else
            {
                /// <summary>
                /// Electronic damage can never destroy a craft, only wreck its sensors, so we'll cut short the attempts to damage components to only 5.
                /// There is no list of only electronic components, and only destroyed electronic components so this will have to do for now.
                /// Having those would improve performance slightly however.
                /// </summary>
                while (Attempts < 5 && internalDamage > 0)
                {
                    ComponentDefTN last = ShipClass.ElectronicDamageAllocationChart.Keys.Last();
                    int DACHit = DacRNG.Next(1, ShipClass.ElectronicDamageAllocationChart[last]);

                    int localDAC = 1;
                    int previousDAC = 1;
                    int destroy = -1;

                    foreach (KeyValuePair<ComponentDefTN, int> list in ShipClass.ElectronicDamageAllocationChart)
                    {
                        localDAC = ShipClass.ElectronicDamageAllocationChart[list.Key];

                        if (DACHit <= localDAC)
                        {
                            float size = list.Key.size;
                            if (size < 1.0)
                                size = 1.0f;

                            /// <summary>
                            /// Electronic component to attempt to destroy:
                            /// </summary>
                            destroy = (int)Math.Floor(((float)(DACHit - previousDAC) / (float)size));

                            /// <summary>
                            /// Actually destroy the component.
                            /// Store EDAC index values somewhere for speed?
                            /// </summary>

                            int CI = ShipClass.ListOfComponentDefs.IndexOf(list.Key);

                            int ComponentIndex = ShipComponents[ComponentDefIndex[CI] + destroy].componentIndex;

                            float hardCheck = (float)DacRNG.Next(1, 100);
                            float hardValue = -1.0f;

                            switch (list.Key.componentType)
                            {
                                case ComponentTypeTN.ActiveSensor:
                                    hardValue = ShipASensor[ComponentIndex].aSensorDef.hardening * 100.0f;
                                    break;
                                case ComponentTypeTN.PassiveSensor:
                                    hardValue = ShipPSensor[ComponentIndex].pSensorDef.hardening * 100.0f;
                                    break;
                                case ComponentTypeTN.BeamFireControl:
                                    hardValue = ShipBFC[ComponentIndex].beamFireControlDef.hardening * 100.0f;
                                    break;
                                case ComponentTypeTN.MissileFireControl:
                                    hardValue = ShipMFC[ComponentIndex].mFCSensorDef.hardening * 100.0f;
                                    break;
                            }

                            int DamageDone = -1;

                            if (hardValue == -1)
                            {
                                /// <summary>
                                /// This is an error condition obviously. I likely forgot to put the component in above however.
                                /// </summary>
                                String ErrorString = String.Format("Unidentified electronic component in onDamaged() Type:{0}.", list.Key.componentType);
                                MessageEntry EMsg = new MessageEntry(MessageEntry.MessageType.Error, ShipsTaskGroup.Contact.Position.System, ShipsTaskGroup.Contact,
                                    GameState.Instance.GameDateTime, GameState.Instance.LastTimestep, ErrorString);
                                ShipsFaction.MessageLog.Add(EMsg);
                            }
                            else
                            {

                                if (hardCheck < hardValue)
                                {
                                    DamageDone = DestroyComponent(list.Key.componentType, CI, internalDamage, destroy, DacRNG);

                                    if (DamageDone != -1)
                                    {
                                        int ID = ComponentDefIndex[CI] + destroy;

                                        if (ShipComponents[ID].isDestroyed == true)
                                        {
                                            String DamageString = String.Format("{0} hit by {1} damage and was destroyed", ShipComponents[ID].Name, DamageDone);
                                            MessageEntry NMsg = new MessageEntry(MessageEntry.MessageType.ShipDamage, ShipsTaskGroup.Contact.Position.System, ShipsTaskGroup.Contact,
                                                                                 GameState.Instance.GameDateTime, GameState.Instance.LastTimestep, DamageString);

                                            ShipsFaction.MessageLog.Add(NMsg);
                                        }
                                        else
                                        {
                                            String DamageString = String.Format("{0} Absorbed {1} damage. Electronic Components shouldn't resist damage like this", ShipComponents[ID].Name, DamageDone);
                                            MessageEntry NMsg = new MessageEntry(MessageEntry.MessageType.ShipDamage, ShipsTaskGroup.Contact.Position.System, ShipsTaskGroup.Contact,
                                                                                 GameState.Instance.GameDateTime, GameState.Instance.LastTimestep, DamageString);

                                            ShipsFaction.MessageLog.Add(NMsg);
                                        }
                                    }
                                }
                                else
                                {

                                    int ID = ComponentDefIndex[CI] + destroy;
                                    String DamageString = String.Format("{0} Absorbed {1} damage", ShipComponents[ID].Name, DamageDone);
                                    MessageEntry NMsg = new MessageEntry(MessageEntry.MessageType.ShipDamage, ShipsTaskGroup.Contact.Position.System, ShipsTaskGroup.Contact,
                                                                         GameState.Instance.GameDateTime, GameState.Instance.LastTimestep, DamageString);

                                    ShipsFaction.MessageLog.Add(NMsg);

                                    DamageDone = 0;
                                }
                            }



                            if (DamageDone == -1)
                            {
                                Attempts++;
                                if (Attempts == 5)
                                {
                                    internalDamage = 0;
                                }
                                break;
                            }
                            else
                            {
                                /// <summary>
                                /// Electronic damage should always be only 1.
                                /// </summary>
                                internalDamage = 0;
                                break;
                            }
                        }
                        previousDAC = localDAC + 1;
                    }
                }
            }

            return false;
        }
Beispiel #5
0
        public bool OnDamaged(DamageTypeTN TypeOfDamage, ushort Value, ShipTN FiringShip, int RadLevel = 0)
        {
            /// <summary>
            /// Check damage type to see if atmosphere blocks it.
            /// Populations are damaged in several ways.
            /// Civilian Population will die off, about 50k per point of damage.
            /// Atmospheric dust will be kicked into the atmosphere(regardless of whether or not there is an atmosphere) lowering temperature for a while.
            /// Some beam weapons are blocked(partially or in whole) by atmosphere(Lasers,Gauss,Railguns,particle beams, plasma), some are not(Mesons), and some have no effect(microwaves) on populations.
            /// PDCs will be similarly defended by this atmospheric blocking but are vulnerable to microwaves.
            /// Missiles will increase the radiation value of the colony. Enhanced Radiation warheads will add more for less overall damage done. Radiation is of course harmful to life on the world. but
            /// not immediately so.
            /// Installations will have a chance at being destroyed. bigger installations should be more resilient to damage, but even infrastructure should have a chance to survive.
            /// Shipyards must be targetted in orbit around the colony. Special handling will be required for that.
            /// </summary>

            ushort ActualDamage;
            switch (TypeOfDamage)
            {
                /// <summary>
                /// Neither missile nor meson damage is effected by atmospheric pressure.
                /// </summary>
                case DamageTypeTN.Missile:
                case DamageTypeTN.Meson:
                    ActualDamage = Value;
                break;
                /// <summary>
                /// All other damage types must be adjusted by atmospheric pressure.
                /// </summary>
                default:
                    ActualDamage = (ushort)Math.Round((float)Value * Planet.Atmosphere.Pressure);
                break;
            }

            /// <summary>
            /// No damage was done. either all damage was absorbed by the atmosphere or the missile had no warhead. Missiles with no warhead should "probably" be sensor missiles that loiter in orbit
            /// until their fuel is gone.
            /// </summary>
            if (ActualDamage == 0)
            {
                return false;
            }

            /// <summary>
            /// Each point of damage kills off 50,000 people, or 0.05f as 1.0f = 1M people.
            /// </summary>
            float PopulationDamage = 0.05f * ActualDamage;
            CivilianPopulation = CivilianPopulation - PopulationDamage;

            /// <summary>
            /// Increase the atmospheric dust and radiation of the planet.
            /// </summary>
            Planet.AtmosphericDust = Planet.AtmosphericDust + ActualDamage;
            Planet.RadiationLevel = Planet.RadiationLevel + RadLevel;

            if (GameState.Instance.DamagedPlanets.Contains(Planet) == false)
                GameState.Instance.DamagedPlanets.Add(Planet);

            String IndustrialDamage = "Industrial Damage:";
            while (ActualDamage > 0)
            {
                ActualDamage = (ushort)(ActualDamage - 5);
                /// <summary>
                /// Installation destruction will be naive. pick an installation at random.
                /// </summary>
                int Inst = GameState.RNG.Next(0, (int)Installation.InstallationType.InstallationCount);
                if (Inst == (int)Installation.InstallationType.CommercialShipyard || Inst == (int)Installation.InstallationType.NavalShipyardComplex)
                {
                    /// <summary>
                    /// Damage was done, but installations escaped unharmed. Shipyards must be damaged from orbit.
                    /// </summary>
                    continue;
                }
                else if (Inst >= (int)Installation.InstallationType.ConvertCIToConstructionFactory && Inst <= (int)Installation.InstallationType.ConvertMineToAutomated)
                {
                    /// <summary>
                    /// These "installations" can't be damaged, so again, lucky planet.
                    /// </summary>
                    continue;
                }
                else
                {
                    int InstCount = (int)Math.Floor(Installations[Inst].Number);

                    /// <summary>
                    /// Luckily for the planet it had none of the installations that just got targetted.
                    /// </summary>
                    if (InstCount == 0)
                    {
                        continue;
                    }

                    switch ((Installation.InstallationType)Inst)
                    {
                        case Installation.InstallationType.DeepSpaceTrackingStation:
                            /// <summary>
                            /// A DSTS was destroyed at this population, inform the UI to update the display.
                            /// </summary>
                            _SensorUpdateAck++; 
                            break;
                    }

                    /// <summary>
                    /// Installation destroyed.
                    /// </summary>
                    Installations[Inst].Number = Installations[Inst].Number - 1.0f;

#warning Industry damage should be reworked to have differing resilience ratings, and logging should compress industrial damage.
                    IndustrialDamage = String.Format("{0} {1}: {2}", IndustrialDamage, Installations[Inst].Name, 1);
                }
            }

            String Entry = String.Format("{0} hit by {1} points of damage. Casualties: {2}{3}Environment Update: Atmospheric Dust:{4}, Radiation:{5}", Name,ActualDamage,PopulationDamage,
                                         IndustrialDamage,Planet.AtmosphericDust, Planet.RadiationLevel);
            MessageEntry NMsg = new MessageEntry(MessageEntry.MessageType.PopulationDamage, Planet.Position.System, Contact,
            GameState.Instance.GameDateTime, GameState.Instance.LastTimestep, Entry);
            Faction.MessageLog.Add(NMsg);

            return false;
        }
Beispiel #6
0
        public DamageTableTN(DamageTypeTN DamageType, ushort Damage)
            : base()
        {
            Type = DamageType;
            DamageTotal = Damage;
            Spread = 1;

            switch (Type)
            {
                /// <summary>
                /// Beams are the best at penetrating armor.
                /// </summary>
                case DamageTypeTN.Beam:

                    /// <summary>
                    /// As near as I can tell higher power beams are better at penetration overall than lower power beams.
                    /// </summary>
                    if (DamageTotal > 128)
                    {
                        Penetration = 5;
                    }
                    else if (DamageTotal > 64)
                    {
                        Penetration = 4;
                    }
                    else
                    {
                        Penetration = 3;
                    }
                    break;
                /// <summary>
                /// Railguns and particle beams are not as good at penetrating armor, but have other characteristics that are valuable.
                /// </summary>
                case DamageTypeTN.Kinetic:
                    Penetration = 2;
                    break;
                /// <summary>
                /// Plasma likewise roils over armor, but is cheap and does plenty of damage.
                /// Actual penetration is in effect 1/2.
                /// </summary>
                case DamageTypeTN.Plasma:
                    Penetration = 1;
                    break;
                /// <summary>
                /// Missiles are the premier weapon of the game, and have the weakest penetration overall.
                /// </summary>
                case DamageTypeTN.Missile:
                    Penetration = 1;
                    break;
            }

            /// <summary>
            /// Initialize the damage template.
            /// </summary>
            DamageTemplate = new BindingList<ushort>();
            for (int loop = 0; loop < 200; loop++)
            {
                DamageTemplate.Add(0);
            }

            HitPoint = 100;

            /// <summary>
            /// Plasmas actually have what is effectively 1/2 penetration.
            if (Type != DamageTypeTN.Plasma)
            {
                int RemainingDamage = DamageTotal;

                if (RemainingDamage > Penetration)
                {
                    DamageTemplate[HitPoint] = Penetration;
                    RemainingDamage = RemainingDamage - Penetration;
                }
                else
                {
                    DamageTemplate[HitPoint] = (ushort)RemainingDamage;
                    RemainingDamage = 0;
                }

                /// <summary>
                /// Do damage spread.
                /// </summary>
                while (RemainingDamage > 0)
                {
                    float DamagePerColumn = (float)((float)RemainingDamage / (float)(Spread + 2));
                    if (DamagePerColumn >= Penetration)
                    {
                        HalfSpread = (int)((float)(Spread + 1) / 2.0f);
                        /// <summary>
                        /// 100 is the arbitrary midpoint for the damage template for the time being, and two is added to spread value every iteration of this
                        /// while loop.
                        /// </summary>
                        for (int loop = (HitPoint - HalfSpread); loop <= (HitPoint + HalfSpread); loop++)
                        {
                            DamageTemplate[loop] = (ushort)(DamageTemplate[loop] + (ushort)Penetration);
                            RemainingDamage = RemainingDamage - Penetration;
                        }

                        Spread = Spread + 2;
                    }
                    else
                    {
                        int BasePerColumn = (int)Math.Floor(DamagePerColumn);
                        HalfSpread = (int)((float)(Spread + 1) / 2.0f);
                        if (BasePerColumn > 0)
                        {
                            for (int loop = (HitPoint - HalfSpread); loop <= (HitPoint + HalfSpread); loop++)
                            {
                                DamageTemplate[loop] = (ushort)(DamageTemplate[loop] + (ushort)BasePerColumn);
                                RemainingDamage = RemainingDamage - BasePerColumn;
                            }
                        }

                        for (int loop = (HitPoint - HalfSpread); loop <= (HitPoint + HalfSpread); loop++)
                        {
                            DamageTemplate[loop] = (ushort)(DamageTemplate[loop] + 1);
                            RemainingDamage = RemainingDamage - 1;

                            if (RemainingDamage == 0)
                                break;
                        }
                    }
                }
            }
            else
            {
                /// <summary>
                /// Plasma damage has to be handled a little differently from beams,particle weapons, and missiles. Penetration value is effectively 1/2, and damage to armor spreads out more.
                /// </summary>

                int RemainingDamage = DamageTotal;

                if (RemainingDamage == 1)
                {
                    DamageTemplate[HitPoint] = 1;
                    RemainingDamage = 0;
                }
                else
                {
                    DamageTemplate[HitPoint] = 1;
                    DamageTemplate[HitPoint + 1] = 1;
                    RemainingDamage = RemainingDamage - 2;

                    Spread = 2;

                    while (RemainingDamage != 0)
                    {
                        HalfSpread = Spread / 2;

                        for (int loop = HalfSpread; loop >= 0; loop--)
                        {
                            DamageTemplate[HitPoint - loop] = (ushort)(DamageTemplate[HitPoint - loop] + (ushort)1);

                            RemainingDamage = RemainingDamage - 1;
                            if (RemainingDamage == 0)
                                break;

                            DamageTemplate[HitPoint + loop + 1] = (ushort)(DamageTemplate[HitPoint + loop + 1] + (ushort)1);

                            RemainingDamage = RemainingDamage - 1;
                            if (RemainingDamage == 0)
                                break;
                        }

                        Spread = Spread + 2;
                    }
                }
            }

            /// <summary>
            /// Remove the excess 0s from the template.
            /// </summary>

            int limit = DamageTemplate.Count;
            for (int loop = limit - 1; loop >= 0; loop--)
            {
                if (DamageTemplate[loop] == 0)
                {
                    DamageTemplate.RemoveAt(loop);

                    if (loop < HitPoint)
                        HitPoint--;
                }
            }
        }