protected void AssertStatCorrect(Func<Stats, float> property, float expected)
        {
            CalculationsShadowPriest calculations = new CalculationsShadowPriest();

            Calculations.Models["ShadowPriest"] = typeof(CalculationsShadowPriest);
            Calculations.LoadModel(calculations);

            _character.CurrentModel = "ShadowPriest";

            Stats stats = calculations.GetCharacterStats(_character, null);

            //Assert.That(property(stats), Is.EqualTo(expected).Within(0.00005f));
        }
        public override Dictionary <string, string> GetCharacterDisplayCalculationValues()
        {
            Dictionary <string, string> dictValues = new Dictionary <string, string>();

            dictValues.Add("Health", BasicStats.Health.ToString());
            dictValues.Add("Stamina", BasicStats.Stamina.ToString());
            dictValues.Add("Mana", BasicStats.Mana.ToString());
            dictValues.Add("Intellect", BasicStats.Intellect.ToString());
            dictValues.Add("Spirit", Math.Floor(BasicStats.Spirit).ToString("0"));
            dictValues.Add("Shadow Damage", String.Format("{0}*Shadow: {1}\r\nSpell: {2}",
                                                          Math.Floor(BasicStats.SpellDamageRating + BasicStats.SpellShadowDamageRating),
                                                          Math.Floor(BasicStats.SpellShadowDamageRating),
                                                          Math.Floor(BasicStats.SpellDamageRating)));
            dictValues.Add("Regen", String.Format("{0}*InFSR: {0}\r\nOutFSR: {1}", RegenInFSR.ToString("0"), RegenOutFSR.ToString("0")));

            dictValues.Add("Spell Crit", string.Format("{0}%*{1} Spell Crit rating ({3}%)\r\n{2} ({4}%) points in Shadow Power",
                                                       BasicStats.SpellCrit + talents.GetTalent("Shadow Power").PointsInvested * 3,
                                                       BasicStats.SpellCritRating.ToString(),
                                                       talents.GetTalent("Shadow Power").PointsInvested, BasicStats.SpellCrit, talents.GetTalent("Shadow Power").PointsInvested * 3));

            int i = (int)Math.Round(CalculationsShadowPriest.GetSpellHitCap(talents) - BasicStats.SpellHitRating);

            dictValues.Add("Spell Hit", string.Format("{0}*{1}",
                                                      BasicStats.SpellHitRating,
                                                      (i > 0)? i + " requires to reach hit cap": i == 0? "Exactly hit cap": (-i) + " over hit cap"));


            dictValues.Add("Spell Haste", string.Format("{0}%*{1} Spell Haste rating\n",
                                                        Math.Round(BasicStats.SpellHasteRating / 15.7, 2), BasicStats.SpellHasteRating.ToString()));
            dictValues.Add("Global Cooldown", Spell.GetGlobalCooldown(BasicStats).ToString("0.00"));

            dictValues.Add("Shadow Word Pain", new ShadowWordPain(BasicStats, talents).ToString());
            dictValues.Add("Shadow Word Death", new ShadowWordDeath(BasicStats, talents).ToString());
            dictValues.Add("Mind Blast", new MindBlast(BasicStats, talents).ToString());
            dictValues.Add("Power Word Shield", new PowerWordShield(BasicStats, talents).ToString());

            if (talents.GetTalent("Vampiric Embrace").PointsInvested > 0)
            {
                dictValues.Add("Vampiric Embrace", new VampiricEmbrace(BasicStats, talents).ToString());
            }
            else
            {
                dictValues.Add("Vampiric Embrace", "- *No required talents");
            }

            if (talents.GetTalent("Vampiric Touch").PointsInvested > 0)
            {
                dictValues.Add("Vampiric Touch", new VampiricTouch(BasicStats, talents).ToString());
            }
            else
            {
                dictValues.Add("Vampiric Touch", "- *No required talents");
            }

            if (talents.GetTalent("Mind Flay").PointsInvested > 0)
            {
                dictValues.Add("Mind Flay", new MindFlay(BasicStats, talents).ToString());
            }
            else
            {
                dictValues.Add("Mind Flay", "- *No required talents");
            }

            Solver solver = new Solver(BasicStats, talents, CalculationOptions);

            solver.Calculate();

            dictValues.Add("Damage done", solver.OverallDamage.ToString());
            dictValues.Add("Dps", solver.OverallDps.ToString());

            return(dictValues);
        }
        public override Dictionary <string, string> GetCharacterDisplayCalculationValues()
        {
            Dictionary <string, string>    dictValues = new Dictionary <string, string>();
            CalculationOptionsShadowPriest calcOpts   = character.CalculationOptions as CalculationOptionsShadowPriest;
            BossOptions BossOpts  = character.BossOptions;
            Stats       baseStats = BaseStats.GetBaseStats(character.Level, character.Class, character.Race);
            bool        Ptr       = calcOpts.PTR;

            dictValues.Add("Health", BasicStats.Health.ToString());
            float ResilienceCap = 0.15f, ResilienceFromRating = StatConversion.GetCritReductionFromResilience(1);
            float Resilience = StatConversion.GetCritReductionFromResilience(BasicStats.Resilience);

            dictValues.Add("Resilience", string.Format("{0}*-{1}% Damage from DoT and Mana Drains\n\r-{1}% Chance to be crit\r\n-{2}% Damage from Crits.\r\n{3}",
                                                       BasicStats.Resilience.ToString(),
                                                       (Resilience * 100f).ToString("0.00"),
                                                       (Resilience * 100f * 2.2f).ToString("0.00"),
                                                       (Resilience > ResilienceCap) ? (string.Format("{0} rating above cap", ((float)Math.Floor((Resilience - ResilienceCap) / ResilienceFromRating)).ToString("0"))) : (string.Format("{0} rating below cap", ((float)Math.Ceiling((ResilienceCap - Resilience) / ResilienceFromRating)).ToString("0")))));
            dictValues.Add("Stamina", BasicStats.Stamina.ToString());
            dictValues.Add("Mana", BasicStats.Mana.ToString());
            dictValues.Add("Intellect", BasicStats.Intellect.ToString());
            dictValues.Add("Spirit", Math.Floor(BasicStats.Spirit).ToString("0"));
            dictValues.Add("Spell Power", String.Format("{0}*{1} Bonus Shadow\r\n{2} Bonus Holy\r\n{3} from Inner Fire",
                                                        Math.Floor(BasicStats.SpellPower),
                                                        Math.Floor(BasicStats.SpellPower + BasicStats.SpellShadowDamageRating),
                                                        Math.Floor(BasicStats.SpellPower /*+ BasicStats.SpellHolyDamageRating*/),
                                                        BasicStats.PriestInnerFire * CalculationsShadowPriest.GetInnerFireSpellPowerBonus(character)));
            dictValues.Add("Regen", String.Format("{0}*MP5: {1}\r\nOutFSR: {2}", RegenInFSR.ToString("0"), BasicStats.Mp5.ToString(), RegenOutFSR.ToString("0")));

            dictValues.Add("Crit", string.Format("{0}%*{1}% from {2} Spell Crit rating\r\n{3}% from Intellect\r\n{4}% from Focused Will\r\n{5}% from Base Crit\r\n{6}% from Buffs\r\n{7}% on Mind Blast, Mind Flay and Mind Sear.\r\n{8}% on VT, SW:P and DP\r\n{9}% on Smite, Holy Fire and Penance.",
                                                 (BasicStats.SpellCrit * 100f).ToString("0.00"),
                                                 (StatConversion.GetSpellCritFromRating(BasicStats.CritRating) * 100f).ToString("0.00"),
                                                 BasicStats.CritRating.ToString("0"),
                                                 (StatConversion.GetSpellCritFromIntellect(BasicStats.Intellect) * 100f).ToString("0.00"),
                                                 character.PriestTalents.FocusedWill,
                                                 (baseStats.SpellCrit * 100f).ToString("0.00"),
                                                 (BasicStats.SpellCrit * 100f - StatConversion.GetSpellCritFromRating(BasicStats.CritRating) * 100f - StatConversion.GetSpellCritFromIntellect(BasicStats.Intellect) * 100f - baseStats.SpellCrit * 100f - character.PriestTalents.FocusedWill).ToString("0.00"),
                                                 (BasicStats.SpellCrit * 100f + character.PriestTalents.MindMelt * 2f).ToString("0.00"),
                                                 (BasicStats.SpellCrit * 100f + character.PriestTalents.MindMelt * 3f).ToString("0.00"),
                                                 (BasicStats.SpellCrit * 100f + character.PriestTalents.HolySpecialization * 1f).ToString("0.00")));

#if RAWR3 || SILVERLIGHT
            float Hit = 100 - (StatConversion.GetSpellMiss(character.Level - BossOpts.Level, false) * 100);
#else
            float Hit = 100 - (StatConversion.GetSpellMiss(-calcOpts.TargetLevel, false) * 100);
#endif
            float  BonusHit   = BasicStats.SpellHit * 100f;
            float  RacialHit  = 0;
            string RacialText = "";
            if (character.Race == CharacterRace.Draenei)
            {
                RacialHit  = 1;
                RacialText = "1% from Draenei Racial\r\n";
                if (!character.ActiveBuffsContains("Heroic Presence"))
                {
                    BonusHit += 1;
                }
            }
            float DebuffHit = character.PriestTalents.Misery * 1f;
            if (character.ActiveBuffsConflictingBuffContains("Spell Hit Chance Taken"))
            {
                DebuffHit = 3f;
            }
            else
            {
                BonusHit += DebuffHit;
            }

            float RHitRating     = 0.01f / StatConversion.GetSpellHitFromRating(1);
            float ShadowFocusHit = character.PriestTalents.ShadowFocus * 1f;
            float HitShadow      = Hit + BonusHit + ShadowFocusHit;
            float HitHoly        = Hit + BonusHit;
            dictValues.Add("Hit", string.Format("{0}%*{1}% from {2} Hit Rating\r\n{3}% from Buffs\r\n{4}% from {5} points in Misery\r\n{6}% from {7} points in Shadow Focus\r\n{8}{9}% Hit with Shadow spells, {10}\r\n{11}% Hit with Holy spells, {12}",
                                                BonusHit.ToString("0.00"),
                                                (StatConversion.GetSpellHitFromRating(BasicStats.HitRating) * 100f).ToString("0.00"), BasicStats.HitRating,
                                                (BonusHit - StatConversion.GetSpellHitFromRating(BasicStats.HitRating) * 100f - RacialHit - DebuffHit).ToString("0.00"),
                                                DebuffHit, character.PriestTalents.Misery,
                                                ShadowFocusHit, character.PriestTalents.ShadowFocus,
                                                RacialText,
                                                HitShadow.ToString("0.00"), (HitShadow > 100f) ? string.Format("{0} hit rating above cap", Math.Floor((HitShadow - 100f) * RHitRating)) : string.Format("{0} hit rating below cap", Math.Ceiling((100f - HitShadow) * RHitRating)),
                                                HitHoly.ToString("0.00"), (HitHoly > 100f) ? string.Format("{0} hit rating above cap", Math.Floor((HitHoly - 100f) * RHitRating)) : string.Format("{0} hit rating below cap", Math.Ceiling((100f - HitHoly) * RHitRating))));

            dictValues.Add("Haste", string.Format("{0}%*{1}% from {2} Haste rating\r\n{3}% ({6}) points in Enlightenment\r\n{4}% from Buffs\r\n{5}s Global Cooldown",
                                                  (BasicStats.SpellHaste * 100f).ToString("0.00"), (StatConversion.GetSpellHasteFromRating(BasicStats.HasteRating) * 100f).ToString("0.00"), BasicStats.HasteRating.ToString(), (character.PriestTalents.Enlightenment * 2).ToString("0"), (((1f + BasicStats.SpellHaste) / (1f + StatConversion.GetSpellHasteFromRating(BasicStats.HasteRating)) / (1f + character.PriestTalents.Enlightenment * 0.02f) - 1f) * 100f).ToString("0.00"), Math.Max(1.0f, 1.5f / (1 + BasicStats.SpellHaste)).ToString("0.00"), character.PriestTalents.Enlightenment));
            dictValues.Add("Armor", string.Format("{0}*{1}% Damage Reduction.",
                                                  (BasicStats.Armor + BasicStats.BonusArmor).ToString("0"),
                                                  (StatConversion.GetArmorDamageReduction(80, (BasicStats.Armor + BasicStats.BonusArmor), 0f, 0f, 0f) * 100f).ToString("0.00")));

            float[] Resistances =
            {
                0,
                BasicStats.ArcaneResistance + BasicStats.ArcaneResistanceBuff,
                BasicStats.FireResistance + BasicStats.FireResistanceBuff,
                BasicStats.FrostResistance + BasicStats.FrostResistanceBuff,
                BasicStats.NatureResistance + BasicStats.NatureResistanceBuff,
                BasicStats.ShadowResistance + BasicStats.ShadowResistanceBuff,
            };

            string[] ResistanceNames =
            {
                "None",
                "Arcane",
                "Fire",
                "Frost",
                "Nature",
                "Shadow",
            };

            string ResistanceString = "*Resistances:";

            float MaxResist      = Resistances[0];
            int   MaxResistIndex = 0;
            float AvgResist      = 0f;
            for (int x = 1; x < Resistances.Length; x++)
            {
                AvgResist += Resistances[x];
                if (Resistances[x] > MaxResist)
                {
                    MaxResist      = Resistances[x];
                    MaxResistIndex = x;
                }
                ResistanceString += string.Format("\r\n{0} : {1}", ResistanceNames[x], Resistances[x]);
            }
            AvgResist /= (Resistances.Length - 1);

            if (AvgResist == 0)
            {
                ResistanceString = "None" + ResistanceString;
            }
            else
            {
                string ResistanceName = (MaxResist == AvgResist) ? "All" : ResistanceNames[MaxResistIndex];
                ResistanceString  = string.Format("{0} : {1}", ResistanceName, MaxResist.ToString("0")) + ResistanceString;
                ResistanceString += string.Format("\r\n\r\nResist ({0}):", ResistanceName);
                ResistanceString += string.Format("\r\n{0}", StatConversion.GetResistanceTableString(character.Level + 3, character.Level, MaxResist, 0));
            }

            dictValues.Add("Resistance", ResistanceString);

            SolverBase solver = GetSolver(character, BasicStats);
            solver.Calculate(this);

            dictValues.Add("Rotation", string.Format("{0}*{1}", solver.Name, solver.Rotation));
            if (solver.SpellSimulation != null)
            {
                String s = "Spell Cast List:";
                int    i = 0;
                foreach (Spell spell in solver.SpellSimulation)
                {
                    if (i++ % 10 == 0)
                    {
                        s += "\r\n";
                    }
                    s += ", " + spell.Name;
                }
                s += "\r\n---Repeat---";
                dictValues.Add("Castlist", string.Format("{0}*{1}", solver.SpellSimulation.Count, s));
            }
            else
            {
                dictValues.Add("Castlist", "Empty");
            }
            dictValues.Add("DPS", string.Format("{0}*Damage Pr Second", solver.DPS.ToString("0")));
            //dictValues.Add("SustainDPS", string.Format("{0}*Mana restrained DPS", solver.SustainDPS.ToString("0")));

            float baseMana = BaseStats.GetBaseStats(character).Mana;

            dictValues.Add("SW Pain", new ShadowWordPain(BasicStats, character, baseMana, Ptr).ToString());
            DevouringPlague dp = new DevouringPlague(BasicStats, character, baseMana, Ptr);
            dictValues.Add("Devouring Plague", dp.ToString());
            if (dp.ImprovedDP != null)
            {
                dictValues.Add("Imp. Devouring Plague", dp.ImprovedDP.ToString());
            }
            else
            {
                dictValues.Add("Imp. Devouring Plague", "- *No required talents");
            }
            dictValues.Add("SW Death", new ShadowWordDeath(BasicStats, character, baseMana, Ptr).ToString());
            dictValues.Add("Mind Blast", new MindBlast(BasicStats, character, baseMana, Ptr).ToString());
            dictValues.Add("PW Shield", new PowerWordShield(BasicStats, character, baseMana, Ptr).ToString());

            if (character.PriestTalents.VampiricTouch > 0)
            {
                dictValues.Add("Vampiric Touch", new VampiricTouch(BasicStats, character, baseMana, Ptr).ToString());
            }
            else
            {
                dictValues.Add("Vampiric Touch", "- *No required talents");
            }

            if (character.PriestTalents.MindFlay > 0)
            {
                dictValues.Add("Mind Flay", new MindFlay(BasicStats, character, baseMana, Ptr).ToString());
            }
            else
            {
                dictValues.Add("Mind Flay", "- *No required talents");
            }

            dictValues.Add("Shadowfiend", new Shadowfiend(BasicStats, character, baseMana, Ptr).ToString());

            dictValues.Add("Smite", new Smite(BasicStats, character, baseMana, Ptr).ToString());
            dictValues.Add("Holy Fire", new HolyFire(BasicStats, character, baseMana, Ptr).ToString());
            if (character.PriestTalents.Penance > 0)
            {
                dictValues.Add("Penance", new Penance(BasicStats, character, baseMana, Ptr).ToString());
            }
            else
            {
                dictValues.Add("Penance", "- *No required talents");
            }

            return(dictValues);
        }