private static void modify(int id, decimal value, Dictionary<int, Modification> modifications)
 {
     Modification modification;
     if (!modifications.TryGetValue(id, out modification))
     {
         modification = new Modification(id);
         modifications.Add(id, modification);
     }
     modification.Modify(value);
 }
        /// <summary>
        /// There are a number of wrinkles with modifications that we need to fix up when all of the modification
        /// information has been gathered.  See in-code comments for each case
        /// </summary>
        public static void FixUpModifications(Module module, Dictionary<int, Modification> modifications)
        {
            if (module.EDName.StartsWith("Hpt_ShieldBooster_"))
            {
                // Shield boosters are treated internally as straight modifiers, so rather than (for example)
                // being a 4% boost they are a 104% multiplier.  Unfortunately this means that our % modification
                // is incorrect so we fix it

                Modification sbModification;
                if (modifications.TryGetValue(SHIELDBOOST, out sbModification))
                {
                    // We do have a boost modification
                    decimal boost;
                    if (module.grade == "E")
                    {
                        boost = 1.04M;
                    }
                    else if (module.grade == "D")
                    {
                        boost = 1.08M;
                    }
                    else if (module.grade == "C")
                    {
                        boost = 1.12M;
                    }
                    else if (module.grade == "B")
                    {
                        boost = 1.16M;
                    }
                    else
                    {
                        boost = 1.2M;
                    }

                    decimal alteredBoost = boost * (1 + sbModification.value) - boost;
                    decimal alteredValue = alteredBoost / (boost - 1);
                    sbModification = new Modification(SHIELDBOOST);
                    sbModification.Modify(alteredValue);
                    modifications.Remove(SHIELDBOOST);
                    modifications.Add(SHIELDBOOST, sbModification);
                }
            }

            Modification jitterModification;
            if (modifications.TryGetValue(JITTER, out jitterModification))
            {
                // Jitter is in degrees rather than being a percentage, so needs to be /100
                decimal value = jitterModification.value / 100;
                jitterModification = new Modification(JITTER);
                jitterModification.Modify(value);
                modifications.Remove(JITTER);
                modifications.Add(JITTER, jitterModification);
            }

            Modification rofModification;
            if (modifications.TryGetValue(ROF, out rofModification))
            {
                // Although Elite talks about rate of fire, it is internally modelled as burst interval
                // i.e. the interval between bursts of fire.  We've been happily modifying ROF with interval modifiers
                // until now, so flip it here to provide the right number
                decimal value = (1.0M / (1 + rofModification.value)) - 1;
                rofModification = new Modification(ROF);
                rofModification.Modify(value);
                modifications.Remove(ROF);
                modifications.Add(ROF, rofModification);
            }
        }
        /// <summary>
        /// There are a number of wrinkles with modifications that we need to fix up when all of the modification
        /// information has been gathered.  See in-code comments for each case
        /// </summary>
        public static void FixUpModifications(Module module, Dictionary <int, Modification> modifications)
        {
            if (module.EDName.StartsWith("Hpt_ShieldBooster_"))
            {
                // Shield boosters are treated internally as straight modifiers, so rather than (for example)
                // being a 4% boost they are a 104% multiplier.  Unfortunately this means that our % modification
                // is incorrect so we fix it

                Modification sbModification;
                if (modifications.TryGetValue(SHIELDBOOST, out sbModification))
                {
                    // We do have a boost modification
                    decimal boost;
                    if (module.grade == "E")
                    {
                        boost = 1.04M;
                    }
                    else if (module.grade == "D")
                    {
                        boost = 1.08M;
                    }
                    else if (module.grade == "C")
                    {
                        boost = 1.12M;
                    }
                    else if (module.grade == "B")
                    {
                        boost = 1.16M;
                    }
                    else
                    {
                        boost = 1.2M;
                    }

                    decimal alteredBoost = boost * (sbModification.value);
                    decimal alteredValue = alteredBoost / (boost - 1);
                    sbModification = new Modification(SHIELDBOOST);
                    sbModification.Modify(alteredValue);
                    modifications.Remove(SHIELDBOOST);
                    modifications.Add(SHIELDBOOST, sbModification);
                }
            }

            // Shield booster resistance is actually a damage modifier, so needs to be inverted
            if (module.EDName.StartsWith("Hpt_ShieldBooster_"))
            {
                Modification explResModification;
                if (modifications.TryGetValue(EXPLRES, out explResModification))
                {
                    Modification newExplResModification = new Modification(EXPLRES);
                    newExplResModification.Modify(explResModification.value * -1);
                    modifications.Remove(EXPLRES);
                    modifications.Add(EXPLRES, newExplResModification);
                }
                Modification kinResModification;
                if (modifications.TryGetValue(KINRES, out kinResModification))
                {
                    Modification newKinResModification = new Modification(KINRES);
                    newKinResModification.Modify(kinResModification.value * -1);
                    modifications.Remove(KINRES);
                    modifications.Add(KINRES, newKinResModification);
                }
                Modification thermResModification;
                if (modifications.TryGetValue(THERMRES, out thermResModification))
                {
                    Modification newThermResModification = new Modification(THERMRES);
                    newThermResModification.Modify(thermResModification.value * -1);
                    modifications.Remove(THERMRES);
                    modifications.Add(THERMRES, newThermResModification);
                }
            }

            // Shield generator resistance is actually a damage modifier, so needs to be inverted
            // In addition, the modification is based off the inherent resistance of the module
            if (module.EDName.StartsWith("Int_ShieldGenerator_"))
            {
                Modification explResModification;
                if (modifications.TryGetValue(EXPLRES, out explResModification))
                {
                    Modification newExplResModification = new Modification(EXPLRES);
                    newExplResModification.Modify(((1 - (1 - 0.5M) * (1 + explResModification.value / 10000)) - 0.5M) * 10000);
                    modifications.Remove(EXPLRES);
                    modifications.Add(EXPLRES, newExplResModification);
                }
                Modification kinResModification;
                if (modifications.TryGetValue(KINRES, out kinResModification))
                {
                    Modification newKinResModification = new Modification(KINRES);
                    newKinResModification.Modify(((1 - (1 - 0.4M) * (1 + kinResModification.value / 10000)) - 0.4M) * 10000);
                    modifications.Remove(KINRES);
                    modifications.Add(KINRES, newKinResModification);
                }
                Modification thermResModification;
                if (modifications.TryGetValue(THERMRES, out thermResModification))
                {
                    Modification newThermResModification = new Modification(THERMRES);
                    newThermResModification.Modify(((1 - (1 + 0.2M) * (1 + thermResModification.value / 10000)) + 0.2M) * 10000);
                    modifications.Remove(THERMRES);
                    modifications.Add(THERMRES, newThermResModification);
                }
            }

            // Hull reinforcement package resistance is actually a damage modifier, so needs to be inverted
            if (module.EDName.StartsWith("Int_HullReinforcement"))
            {
                Modification explResModification;
                if (modifications.TryGetValue(EXPLRES, out explResModification))
                {
                    Modification newExplResModification = new Modification(EXPLRES);
                    newExplResModification.Modify(explResModification.value * -1);
                    modifications.Remove(EXPLRES);
                    modifications.Add(EXPLRES, newExplResModification);
                }
                Modification kinResModification;
                if (modifications.TryGetValue(KINRES, out kinResModification))
                {
                    Modification newKinResModification = new Modification(KINRES);
                    newKinResModification.Modify(kinResModification.value * -1);
                    modifications.Remove(KINRES);
                    modifications.Add(KINRES, newKinResModification);
                }
                Modification thermResModification;
                if (modifications.TryGetValue(THERMRES, out thermResModification))
                {
                    Modification newThermResModification = new Modification(THERMRES);
                    newThermResModification.Modify(thermResModification.value * -1);
                    modifications.Remove(THERMRES);
                    modifications.Add(THERMRES, newThermResModification);
                }
            }

            // Bulkhead resistance is actually a damage modifier, so needs to be inverted
            // In addition, the modification is based off the inherent resistance of the module
            if (module.EDName.Contains("_Armour_"))
            {
                Modification explResModification;
                if (modifications.TryGetValue(EXPLRES, out explResModification))
                {
                    // TODO these should be part of the module definition
                    decimal explRes;
                    if (module.EDName.EndsWith("_Grade1"))
                    {
                        explRes = -0.4M;
                    }
                    else if (module.EDName.EndsWith("_Grade2"))
                    {
                        explRes = -0.4M;
                    }
                    else if (module.EDName.EndsWith("_Grade3"))
                    {
                        explRes = -0.4M;
                    }
                    else if (module.EDName.EndsWith("_Mirrored"))
                    {
                        explRes = -0.5M;
                    }
                    else if (module.EDName.EndsWith("_Reactive"))
                    {
                        explRes = 0.2M;
                    }
                    else
                    {
                        Logging.Warn("Unknown armour " + module.EDName);
                        explRes = -0.4M;
                    }
                    Modification newExplResModification = new Modification(EXPLRES);
                    newExplResModification.Modify(((1 - (1 - explRes) * (1 + explResModification.value / 10000)) - explRes) * 10000);
                    modifications.Remove(EXPLRES);
                    modifications.Add(EXPLRES, newExplResModification);
                }
                Modification kinResModification;
                if (modifications.TryGetValue(KINRES, out kinResModification))
                {
                    // TODO these should be part of the module definition
                    decimal kinRes;
                    if (module.EDName.EndsWith("_Grade1"))
                    {
                        kinRes = -0.2M;
                    }
                    else if (module.EDName.EndsWith("_Grade2"))
                    {
                        kinRes = -0.2M;
                    }
                    else if (module.EDName.EndsWith("_Grade3"))
                    {
                        kinRes = -0.2M;
                    }
                    else if (module.EDName.EndsWith("_Mirrored"))
                    {
                        kinRes = -0.75M;
                    }
                    else if (module.EDName.EndsWith("_Reactive"))
                    {
                        kinRes = 0.25M;
                    }
                    else
                    {
                        Logging.Warn("Unknown armour " + module.EDName);
                        kinRes = -0.2M;
                    }
                    Modification newKinResModification = new Modification(KINRES);
                    newKinResModification.Modify(((1 - (1 - kinRes) * (1 + kinResModification.value / 10000)) - kinRes) * 10000);
                    modifications.Remove(KINRES);
                    modifications.Add(KINRES, newKinResModification);
                }
                Modification thermResModification;
                if (modifications.TryGetValue(THERMRES, out thermResModification))
                {
                    // TODO these should be part of the module definition
                    decimal thermRes;
                    if (module.EDName.EndsWith("_Grade1"))
                    {
                        thermRes = 0;
                    }
                    else if (module.EDName.EndsWith("_Grade2"))
                    {
                        thermRes = 0;
                    }
                    else if (module.EDName.EndsWith("_Grade3"))
                    {
                        thermRes = 0;
                    }
                    else if (module.EDName.EndsWith("_Mirrored"))
                    {
                        thermRes = 0.5M;
                    }
                    else if (module.EDName.EndsWith("_Reactive"))
                    {
                        thermRes = -0.4M;
                    }
                    else
                    {
                        Logging.Warn("Unknown armour " + module.EDName);
                        thermRes = 0;
                    }
                    Modification newThermResModification = new Modification(THERMRES);
                    newThermResModification.Modify(((1 - (1 - thermRes) * (1 + thermResModification.value / 10000)) - thermRes) * 10000);
                    modifications.Remove(THERMRES);
                    modifications.Add(THERMRES, newThermResModification);
                }
            }

            Modification jitterModification;

            if (modifications.TryGetValue(JITTER, out jitterModification))
            {
                // Jitter is in degrees rather than being a percentage, so needs to be /100
                decimal value = jitterModification.value / 100;
                jitterModification = new Modification(JITTER);
                jitterModification.Modify(value);
                modifications.Remove(JITTER);
                modifications.Add(JITTER, jitterModification);
            }

            Modification rofModification;

            if (modifications.TryGetValue(ROF, out rofModification))
            {
                // Although Elite talks about rate of fire, it is internally modelled as burst interval
                // i.e. the interval between bursts of fire.  We've been happily modifying ROF with interval modifiers
                // until now, so flip it here to provide the right number
                decimal oldValue = rofModification.value;
                decimal value    = (1.0M / (1 + rofModification.value)) - 1;
                rofModification = new Modification(ROF);
                rofModification.Modify(value);
                modifications.Remove(ROF);
                modifications.Add(ROF, rofModification);
            }
        }