Beispiel #1
0
        virtual public void AccumulateStats()
        {
            if (m_Stats == null)
            {
                m_Stats = new StatsDK();
            }

            m_Stats.Strength              = m_DKStats.Strength;
            m_Stats.Stamina               = m_DKStats.Stamina;
            m_Stats.PhysicalHaste         = m_DKStats.PhysicalHaste;
            m_Stats.CritRating            = m_DKStats.CritRating;
            m_Stats.PhysicalHit           = m_DKStats.PhysicalHit;
            m_Stats.BonusDamageMultiplier = m_DKStats.BonusDamageMultiplier;
            m_Stats.Expertise             = StatConversion.GetExpertiseFromDodgeParryReduc(m_DKStats.PhysicalHit);

            if (m_Talents.GlyphofRaiseDead)
            {
                m_Stats.Strength += (m_DKStats.Strength * .4f);
                m_Stats.Stamina  += (m_DKStats.Stamina * .4f);
            }
            m_Stats.DamageTakenReductionMultiplier = 1f - (1f - m_Stats.DamageTakenReductionMultiplier) * (1f - .90f); // 90% passive AOE damage reduction.

            // Apply ratings and such.
            m_Stats.AttackPower  = (float)Math.Floor(m_Stats.Strength * 2);
            m_Stats.PhysicalCrit = StatConversion.GetCritFromRating(m_Stats.CritRating);
            m_Stats.SpellCrit    = StatConversion.GetCritFromRating(m_Stats.CritRating);
        }
Beispiel #2
0
        virtual public void AccumulateStats()
        {
            if (m_Stats == null)
                m_Stats = new StatsDK();

            m_Stats.Strength = m_DKStats.Strength;
            m_Stats.Stamina = m_DKStats.Stamina;
            m_Stats.PhysicalHaste = m_DKStats.PhysicalHaste;
            m_Stats.CritRating = m_DKStats.CritRating;
            m_Stats.PhysicalHit = m_DKStats.PhysicalHit;
            m_Stats.BonusDamageMultiplier = m_DKStats.BonusDamageMultiplier;
            m_Stats.Expertise = StatConversion.GetExpertiseFromDodgeParryReduc(m_DKStats.PhysicalHit);

            if (m_Talents.GlyphofRaiseDead)
            {
                m_Stats.Strength += (m_DKStats.Strength * .4f);
                m_Stats.Stamina += (m_DKStats.Stamina * .4f);
            }
            m_Stats.DamageTakenReductionMultiplier = 1f - (1f - m_Stats.DamageTakenReductionMultiplier) * (1f - .90f); // 90% passive AOE damage reduction.

            // Apply ratings and such.
            m_Stats.AttackPower = (float)Math.Floor(m_Stats.Strength * 2);
            m_Stats.PhysicalCrit = StatConversion.GetCritFromRating(m_Stats.CritRating);
            m_Stats.SpellCrit = StatConversion.GetCritFromRating(m_Stats.CritRating);

        }
Beispiel #3
0
 public DKCombatTable(Character c, StatsDK stats, CharacterCalculationsBase calcs, ICalculationOptionBase calcOpts, BossOptions bossOpts)
 {
     m_CState = new CombatState();
     if (c != null)
     {
         m_CState.m_Char    = c;
         m_CState.m_Talents = c.DeathKnightTalents;
         m_CState.m_Spec    = CalculationsDPSDK.GetSpec(c.DeathKnightTalents);
     }
     m_CState.m_Stats = stats;
     // TODO: Put in check here for null.
     m_Calcs             = calcs as CharacterCalculationsDPSDK;
     m_Opts              = calcOpts as CalculationOptionsDPSDK;
     m_CState.m_Presence = Presence.Frost;
     if (calcOpts != null && m_Opts == null)
     {
         //throw new Exception("Opts not converted properly.");
         m_Opts = new CalculationOptionsDPSDK();
     }
     try { m_CState.m_Presence = m_Opts.presence; } catch { } // pass  stay w/ default
     m_BO = bossOpts;
     if (m_BO == null)
     {
         m_BO = new BossOptions();
     }
     // JOTHAY TODO: Kind of an Ugly Hack to do this, but it will give them a value
     m_CState.m_NumberOfTargets = m_BO.MultiTargs ? m_BO.DynamicCompiler_MultiTargs.GetAverageTargetGroupSize(m_BO.BerserkTimer) : 1f;
     //
     m_CState.m_bAttackingFromBehind = m_BO.InBack;
     m_CState.fBossArmor             = m_BO.Armor;
     SetupExpertise(c);
 }
Beispiel #4
0
        public Pet(StatsDK dkstats, DeathKnightTalents t, BossOptions bo, Presence p)
        {
            m_BO = bo;
            m_DKStats = dkstats;
            m_Talents = t;
            m_Presence = p;

            AccumulateStats();
        }
Beispiel #5
0
        public Pet(StatsDK dkstats, DeathKnightTalents t, BossOptions bo, Presence p)
        {
            m_BO       = bo;
            m_DKStats  = dkstats;
            m_Talents  = t;
            m_Presence = p;

            AccumulateStats();
        }
Beispiel #6
0
        public Gargoyle(StatsDK dkstats, DeathKnightTalents t, BossOptions bo, Presence p)
        {
            m_BO       = bo;
            m_DKStats  = dkstats;
            m_Talents  = t;
            m_Presence = p;

            AccumulateStats();
            DamageType = ItemDamageType.Physical;
        }
        /// <summary>
        /// Process the Stat modifier values 
        /// </summary>
        /// <param name="statsTotal">[in/out] Stats object for the total character stats.</param>
        /// <param name="iBladedArmor">[in] character.talent.BladedArmor</param>
        private void ProcessStatModifiers(StatsDK statsTotal, int iBladedArmor, Character c)
        {
            statsTotal.Strength = StatConversion.ApplyMultiplier(statsTotal.Strength, statsTotal.BonusStrengthMultiplier);
            statsTotal.Agility = StatConversion.ApplyMultiplier(statsTotal.Agility, statsTotal.BonusAgilityMultiplier);
            // The stamina value is floor in game for the calculation
            statsTotal.Stamina = StatConversion.ApplyMultiplier(statsTotal.Stamina, statsTotal.BonusStaminaMultiplier);
            statsTotal.Stamina = (float)Math.Floor(statsTotal.Stamina);
            statsTotal.Armor = StatConversion.ApplyMultiplier(statsTotal.Armor, statsTotal.BaseArmorMultiplier);
            statsTotal.AttackPower = StatConversion.ApplyMultiplier(statsTotal.AttackPower, statsTotal.BonusAttackPowerMultiplier);
            statsTotal.BonusArmor = StatConversion.ApplyMultiplier(statsTotal.BonusArmor, statsTotal.BonusArmorMultiplier);

            statsTotal.Armor += statsTotal.BonusArmor;
            statsTotal.Health += StatConversion.GetHealthFromStamina(statsTotal.Stamina);
            statsTotal.Health = statsTotal.Health * (1 + statsTotal.BonusHealthMultiplier);

            // Talent: BladedArmor //////////////////////////////////////////////////////////////
            if (iBladedArmor > 0)
            {
                statsTotal.AttackPower += (statsTotal.Armor / 180f) * (float)iBladedArmor;
            }
            // AP, crit, etc.  already being factored in w/ multiplier.
            statsTotal.AttackPower += StatConversion.ApplyMultiplier((statsTotal.Strength * 2), statsTotal.BonusAttackPowerMultiplier);
        }
        /// <summary>
        /// Get Character Stats for multiple calls.  Allowing means by which to stack different sets/Special effects.
        /// </summary>
        /// <param name="character"></param>
        /// <param name="additionalItem"></param>
        /// <param name="sType">Enum describing which set of stats we want.</param>
        /// <returns></returns>
        private StatsDK GetCharacterStats(Character character, Item additionalItem, StatType sType, TankDKChar TDK, Rotation rot = null)
        {
            StatsDK statsTotal = new StatsDK();
            if (null == character.CalculationOptions)
            {
                // Possibly put some error text here.
                return statsTotal;
            }
            // Warning TDK can be blank at this point.
            TDK.Char = character;
            TDK.calcOpts = character.CalculationOptions as CalculationOptionsTankDK;
            TDK.bo = character.BossOptions;

            // Start populating data w/ Basic racial & class baseline.
            Stats BStats = BaseStats.GetBaseStats(character);
            statsTotal.Accumulate(BStats);
            statsTotal.BaseAgility = BStats.Agility;

            AccumulateItemStats(statsTotal, character, additionalItem);
            // Stack only the info we care about.
            statsTotal = GetRelevantStatsLocal(statsTotal);

            AccumulateBuffsStats(statsTotal, character.ActiveBuffs);
            AccumulateSetBonusStats(statsTotal, character.SetBonusCount);

            #region Tier Bonuses: Tank
            #region T11
            int tierCount;
            if (character.SetBonusCount.TryGetValue("Magma Plated Battlearmor", out tierCount))
            {
                if (tierCount >= 2) { statsTotal.b2T11_Tank = true; }
                if (tierCount >= 4) { statsTotal.b4T11_Tank = true; }
            }
            if (statsTotal.b4T11_Tank)
                statsTotal.AddSpecialEffect(_SE_IBF[1]);
            else
                statsTotal.AddSpecialEffect(_SE_IBF[0]);
            #endregion
            #region T12
            if (character.SetBonusCount.TryGetValue("Elementium Deathplate Battlearmor", out tierCount))
            {
                if (tierCount >= 2) { statsTotal.b2T12_Tank = true; }
                if (tierCount >= 4) { statsTotal.b4T12_Tank = true; }
            }
            if (statsTotal.b2T12_Tank)
            {
                // Your melee attacks cause Burning Blood on your target, 
                // which deals 800 Fire damage every 2 for 6 sec and 
                // causes your abilities to behave as if you had 2 diseases 
                // present on the target.
                // Implemented in CombatState DiseaseCount

                statsTotal.FireDamage = 800 / 2;
            }
            if (statsTotal.b4T12_Tank)
            {
                // Your when your Dancing Rune Weapon expires, it grants 15% additional parry chance for 12 sec.
                // Implemented in DRW talent Static Special Effect.
            }
            #endregion
            #region T13
            if (character.SetBonusCount.TryGetValue("Necrotic Boneplate Armor", out tierCount))
            {
                if (tierCount >= 2) { statsTotal.b2T13_Tank = true; }
                if (tierCount >= 4) { statsTotal.b4T13_Tank = true; }
            }
            if (statsTotal.b2T13_Tank)
            {
                // When an attack drops your health below 35%, one of your Blood Runes 
                // will immediately activate and convert into a Death Rune for the next 
                // 20 sec. This effect cannot occur more than once every 45 sec.
            }
            if (statsTotal.b4T13_Tank)
            {
                // Your Vampiric Blood ability also affects all party and raid members 
                // for 50% of the effect it has on you.
            }
            #endregion
            #endregion

            Rawr.DPSDK.CalculationsDPSDK.RemoveDuplicateRunes(statsTotal, character, true/*statsTotal.bDW*/);
            Rawr.DPSDK.CalculationsDPSDK.AccumulateTalents(statsTotal, character);
            Rawr.DPSDK.CalculationsDPSDK.AccumulatePresenceStats(statsTotal, Presence.Blood, character.DeathKnightTalents);


            statsTotal.ArcaneResistance += statsTotal.ArcaneResistanceBuff; statsTotal.ArcaneResistanceBuff = 0f;
            statsTotal.FireResistance   += statsTotal.FireResistanceBuff;   statsTotal.FireResistanceBuff   = 0f;
            statsTotal.FrostResistance  += statsTotal.FrostResistanceBuff;  statsTotal.FrostResistanceBuff  = 0f;
            statsTotal.NatureResistance += statsTotal.NatureResistanceBuff; statsTotal.NatureResistanceBuff = 0f;
            statsTotal.ShadowResistance += statsTotal.ShadowResistanceBuff; statsTotal.ShadowResistanceBuff = 0f;

            /* At this point, we're combined all the data from gear and talents and all that happy jazz.
             * However, we haven't applied any special effects nor have we applied any multipliers.
             * Many special effects are now getting dependant upon combat info (rotations).
             */
            StatsDK PreRatingsBase = statsTotal.Clone() as StatsDK;
            // Apply the ratings to actual stats.
            ProcessRatings(statsTotal);
            ProcessAvoidance(statsTotal, TDK.bo.Level, TDK.Char, PreRatingsBase);
            statsTotal.EffectiveParry = 0;
            if (character.MainHand != null)
            {
                statsTotal.EffectiveParry = statsTotal.Parry;
            }
            float fChanceToGetHit = 1f - Math.Min(1f, statsTotal.Miss + statsTotal.Dodge + statsTotal.EffectiveParry);

            // Now comes the special handling for secondary stats passes that are dependant upon Boss & Rotation values.
            if (sType != StatType.Unbuffed
                && (null != TDK.bo && null != rot)) // Make sure we have the rotation and Boss info.
            {
                #region Special Effects
                #region Talent: Bone Shield
                if (character.DeathKnightTalents.BoneShield > 0)
                {
                    int BSStacks = 4;  // The number of bones by default.  
                    if (Rawr.Properties.GeneralSettings.Default.PTRMode)
                        BSStacks = 6;  // The number of bones by default.  
                    float BoneLossRate = Math.Max(2f, TDK.bo.DynamicCompiler_Attacks.AttackSpeed / fChanceToGetHit);  // 2 sec internal cooldown on loosing bones so the DK can't get spammed to death.  
                    float moveVal = character.DeathKnightTalents.GlyphofBoneShield ? 0.15f : 0f;
                    SpecialEffect primary = new SpecialEffect(Trigger.Use,
                        new Stats() { DamageTakenReductionMultiplier = 0.20f, BonusDamageMultiplier = 0.02f, MovementSpeed = moveVal, },
                        BoneLossRate * BSStacks, 60) {BypassCache = true,};
                    statsTotal.AddSpecialEffect(primary);
                }
                #endregion
                #region Vengeance
                // Vengence has the chance to increase AP.
                int iVengenceMax = (int)(statsTotal.Stamina + (BaseStats.GetBaseStats(character).Health) * .1);
                int iAttackPowerMax = (int)statsTotal.AttackPower + iVengenceMax;
                float mitigatedDPS = TDK.bo.GetDPSByType(TDK.role, 0, statsTotal.DamageTakenReductionMultiplier,
                    0, .14f, statsTotal.Miss, statsTotal.Dodge, statsTotal.EffectiveParry, 0, 0,
                    0, 0, 0, 0, 0);
                    //statsTotal.ArcaneResistance, statsTotal.FireResistance, statsTotal.FrostResistance, statsTotal.NatureResistance, statsTotal.ShadowResistance);
                mitigatedDPS = mitigatedDPS * (1 - (float)StatConversion.GetArmorDamageReduction(TDK.bo.Level, statsTotal.Armor, 0f, 0f));
                float APStackSingle = mitigatedDPS * 0.05f * TDK.bo.DynamicCompiler_Attacks.AttackSpeed;
                int APStackCountMax = (int)Math.Floor(iVengenceMax / APStackSingle);
                SpecialEffect seVeng = new SpecialEffect(Trigger.DamageTaken,
                    new Stats() { AttackPower = APStackSingle },
                    2 * 10,
                    0,
                    1,
                    APStackCountMax) { BypassCache = true, };
                Dictionary<Trigger, float> triggerInterval = new Dictionary<Trigger,float>();
                Dictionary<Trigger, float> triggerChance = new Dictionary<Trigger,float>();
                triggerInterval.Add(Trigger.DamageTaken, TDK.bo.DynamicCompiler_Attacks.AttackSpeed);
                triggerChance.Add(Trigger.DamageTaken, 1f); // MitigatedDPS already factors in avoidance.
                statsTotal.VengenceAttackPower = seVeng.GetAverageStats(triggerInterval, triggerChance).AttackPower;
                statsTotal.AttackPower += statsTotal.VengenceAttackPower * TDK.calcOpts.VengeanceWeight;
                #endregion
                statsTotal.AddSpecialEffect(_SE_DeathPact);
                // For now we just factor them in once.
                Rawr.DPSDK.StatsSpecialEffects se = new Rawr.DPSDK.StatsSpecialEffects(rot.m_CT, rot, TDK.bo);
                StatsDK statSE = new StatsDK();

                foreach (SpecialEffect effect in statsTotal.SpecialEffects())
                {
                    if (HasRelevantStats(effect.Stats))
                    {
                        statSE.Accumulate(se.getSpecialEffects(effect));
//                        statsTotal.Accumulate(se.getSpecialEffects(effect)); // This is done further down.
                    }
                }

                // Darkmoon card greatness procs
                if (statSE.HighestStat > 0 || statSE.Paragon > 0)
                {
                    if (statSE.Strength >= statSE.Agility) { statSE.Strength += statSE.HighestStat + statSE.Paragon; }
                    else if (statSE.Agility > statSE.Strength) { statSE.Agility += statSE.HighestStat + statSE.Paragon; }
                    statSE.HighestStat = 0;
                    statSE.Paragon = 0;
                }

                // Any Modifiers from stats need to be applied to statSE
                statSE.Strength = StatConversion.ApplyMultiplier(statSE.Strength, statsTotal.BonusStrengthMultiplier);
                statSE.Agility = StatConversion.ApplyMultiplier(statSE.Agility, statsTotal.BonusAgilityMultiplier);
                statSE.Stamina = StatConversion.ApplyMultiplier(statSE.Stamina, statsTotal.BonusStaminaMultiplier);
                //            statSE.Stamina = (float)Math.Floor(statSE.Stamina);
                statSE.Armor = StatConversion.ApplyMultiplier(statSE.Armor, statsTotal.BaseArmorMultiplier);
                statSE.AttackPower = StatConversion.ApplyMultiplier(statSE.AttackPower, statsTotal.BonusAttackPowerMultiplier);
                statSE.BonusArmor = StatConversion.ApplyMultiplier(statSE.BonusArmor, statsTotal.BonusArmorMultiplier);

                statSE.Armor += statSE.BonusArmor;
                statSE.Health += StatConversion.GetHealthFromStamina(statSE.Stamina) + statSE.BattlemasterHealthProc;
                statSE.Health = statSE.Health * (1 + statSE.BonusHealthMultiplier);
                statsTotal.BonusHealthMultiplier = ((1 + statsTotal.BonusHealthMultiplier) * (1 + statSE.BonusHealthMultiplier)) - 1 ;
                if (character.DeathKnightTalents.BladedArmor > 0)
                {
                    statSE.AttackPower += (statSE.Armor / 180f) * (float)character.DeathKnightTalents.BladedArmor;
                }
                statSE.AttackPower += StatConversion.ApplyMultiplier((statSE.Strength * 2), statsTotal.BonusAttackPowerMultiplier);
                statSE.ParryRating += statSE.Strength * 0.27f;

                // Any Modifiers from statSE need to be applied to stats
                statsTotal.Strength = StatConversion.ApplyMultiplier(statsTotal.Strength, statSE.BonusStrengthMultiplier);
                statsTotal.Agility = StatConversion.ApplyMultiplier(statsTotal.Agility, statSE.BonusAgilityMultiplier);
                statsTotal.Stamina = StatConversion.ApplyMultiplier(statsTotal.Stamina, statSE.BonusStaminaMultiplier);
                //            stats.Stamina = (float)Math.Floor(stats.Stamina);
                statsTotal.Armor = StatConversion.ApplyMultiplier(statsTotal.Armor, statSE.BaseArmorMultiplier);
                statsTotal.AttackPower = StatConversion.ApplyMultiplier(statsTotal.AttackPower, statSE.BonusAttackPowerMultiplier);
                statsTotal.BonusArmor = StatConversion.ApplyMultiplier(statsTotal.BonusArmor, statSE.BonusArmorMultiplier);

                statsTotal.Accumulate(statSE);
                PreRatingsBase.Miss += statSE.Miss;
                PreRatingsBase.Dodge += statSE.Dodge;
                PreRatingsBase.Parry += statSE.Parry;
#if DEBUG
                if (float.IsNaN(statsTotal.Stamina))
                    throw new Exception("Something very wrong in stats.");
#endif
                #endregion // Special effects
            }
            // Apply the Multipliers
            ProcessStatModifiers(statsTotal, character.DeathKnightTalents.BladedArmor, character);
            ProcessAvoidance(statsTotal, TDK.bo.Level, TDK.Char, PreRatingsBase);
            if (character.MainHand != null)
            {
                statsTotal.EffectiveParry = statsTotal.Parry;
            }
            return (statsTotal);
        }
        private CharacterCalculationsTankDK GetCharacterCalculations(TankDKChar TDK, StatsDK stats, Rotation rot, bool isBurstCalc, bool needsDisplayCalcs)
        {
            CharacterCalculationsTankDK calcs = new CharacterCalculationsTankDK();

            // Level differences.
            int iLevelDiff = Math.Max(TDK.bo.Level - TDK.Char.Level, 0);

            float fChanceToGetHit = 1f - Math.Min(1f, stats.Miss + stats.Dodge + stats.EffectiveParry);
            float ArmorDamageReduction = (float)StatConversion.GetArmorDamageReduction(TDK.bo.Level, stats.Armor, 0f, 0f);

            #region **** Setup Fight parameters ****

            // Get the values of each type of damage in %.
            // So first we get each type of damage in the same units: DPS.
            // Get the total DPS.

            float[] fCurrentDTPS = new float[3];
            fCurrentDTPS[(int)SurvivalSub.Physical] = 0f;
            fCurrentDTPS[(int)SurvivalSub.Bleed] = 0f;
            fCurrentDTPS[(int)SurvivalSub.Magic] = 0f;
            float[] fCurrentDmgBiggestHit = new float[3];
            fCurrentDmgBiggestHit[(int)SurvivalSub.Physical] = 0f;
            fCurrentDmgBiggestHit[(int)SurvivalSub.Bleed] = 0f;
            fCurrentDmgBiggestHit[(int)SurvivalSub.Magic] = 0f;
            float[] fCurrentDTPSPerc = new float[3];
            fCurrentDTPSPerc[(int)SurvivalSub.Physical] = 1f;
            fCurrentDTPSPerc[(int)SurvivalSub.Bleed] = 0f;
            fCurrentDTPSPerc[(int)SurvivalSub.Magic] = 0f;
            float fTotalDTPS = 0;

            float fAvoidanceTotal = 1f - fChanceToGetHit;

            // We want to start getting the Boss Handler stuff going on.
            // Setup initial Boss data.
            // How much of what kind of damage does this boss deal with?
            #region ** Incoming Boss Dam **
            // Let's make sure this is even valid
            float DPHit = 0;
            float DPTick = 0;
            switch (TDK.calcOpts.PlayerRole)
            {
                case 0:
                    TDK.role = PLAYER_ROLES.MainTank;
                    break;
                case 1:
                    TDK.role = PLAYER_ROLES.OffTank;
                    break;
                case 2:
                    TDK.role = PLAYER_ROLES.TertiaryTank;
                    break;
                default:
                    TDK.role = PLAYER_ROLES.MainTank;
                    break;
            }
            TDK.role = PLAYER_ROLES.MainTank;
            foreach (Attack a in TDK.bo.Attacks)
            {
                // PlayerRole on calcOpts is MT=0, OT=1, TT=2, Any Tank = 3
                // Any Tank means it should be affected by anything that affects a tanking role
                if (a.AffectsRole[PLAYER_ROLES.MainTank] && (TDK.calcOpts.PlayerRole == 0 || TDK.calcOpts.PlayerRole == 3)
                    || a.AffectsRole[PLAYER_ROLES.OffTank] && (TDK.calcOpts.PlayerRole == 1 || TDK.calcOpts.PlayerRole == 3)
                    || a.AffectsRole[PLAYER_ROLES.TertiaryTank] && (TDK.calcOpts.PlayerRole == 2 || TDK.calcOpts.PlayerRole == 3))
                {
                    // TODO: Figure out a way to get the phase changes handled.
                    DPHit = a.DamagePerHit;
                    DPTick = a.DamagePerTick;
                    if (a.DamageIsPerc)
                    {
#if DEBUG
                        if ((a.DamagePerHit >= 1f) || (a.DamagePerTick >= 1f))
                            throw new Exception("Percentage Damage is >= 100%.");
#endif
                        DPHit = a.DamagePerHit * stats.Health;
                        DPTick = a.DamagePerTick * stats.Health;
                    }

                    // Bleeds vs Magic vs Physical
                    if (a.DamageType == ItemDamageType.Physical) 
                    {
                        // Bleed or Physical
                        // Need to figure out how to determine bleed vs. physical hits.
                        // Also need to balance out the physical hits and balance the hit rate.
                        // JOTHAY NOTE: Bleeds are DoTs
                        if (a.IsDoT) {
                            fCurrentDTPS[(int)SurvivalSub.Bleed] += GetDPS(DPHit, a.AttackSpeed) + GetDPS(DPTick, a.TickInterval);
                            if (fCurrentDmgBiggestHit[(int)SurvivalSub.Bleed] < DPHit + (DPTick * a.NumTicks))
                                fCurrentDmgBiggestHit[(int)SurvivalSub.Bleed] = DPHit + (DPTick * a.NumTicks);
                        } 
                        else 
                        {
                            fCurrentDTPS[(int)SurvivalSub.Physical] += GetDPS(DPHit, a.AttackSpeed);
                            if (fCurrentDmgBiggestHit[(int)SurvivalSub.Physical] < DPHit)
                                fCurrentDmgBiggestHit[(int)SurvivalSub.Physical] = DPHit;
                        }
                    } 
                    else 
                    {
                        // Magic now covering magical dots.
                        fCurrentDTPS[(int)SurvivalSub.Magic] += GetDPS(DPHit, a.AttackSpeed) + GetDPS(DPTick, a.TickInterval);
                        if (fCurrentDmgBiggestHit[(int)SurvivalSub.Magic] < DPHit + (DPTick * a.NumTicks))
                            fCurrentDmgBiggestHit[(int)SurvivalSub.Magic] = DPHit + (DPTick * a.NumTicks);
                    }
                }
            }
            fTotalDTPS += fCurrentDTPS[(int)SurvivalSub.Physical];
            fTotalDTPS += fCurrentDTPS[(int)SurvivalSub.Bleed];
            fTotalDTPS += fCurrentDTPS[(int)SurvivalSub.Magic];

            if (fTotalDTPS > 0)
            {
                fCurrentDTPSPerc[(int)SurvivalSub.Physical] = fCurrentDTPS[(int)SurvivalSub.Physical] / fTotalDTPS;
                fCurrentDTPSPerc[(int)SurvivalSub.Bleed]    = fCurrentDTPS[(int)SurvivalSub.Bleed] / fTotalDTPS;
                fCurrentDTPSPerc[(int)SurvivalSub.Magic]    = fCurrentDTPS[(int)SurvivalSub.Magic] / fTotalDTPS;
            }
            #endregion

            // Set the Fight Duration to no larger than the Berserk Timer
            // Question: What is the units for Berserk & Speed Timer? MS/S/M?
            #endregion

            #region ***** Survival Rating *****
            // Magical damage:
            // if there is a max resistance, then it's likely they are stacking for that resistance.  So factor in that Max resistance.
            float fMaxResist = Math.Max(stats.ArcaneResistance, stats.FireResistance);
            fMaxResist       = Math.Max(fMaxResist, stats.FrostResistance);
            fMaxResist       = Math.Max(fMaxResist, stats.NatureResistance);
            fMaxResist       = Math.Max(fMaxResist, stats.ShadowResistance);

            float fMagicDR = StatConversion.GetAverageResistance(TDK.bo.Level, TDK.Char.Level, fMaxResist, 0f);
            calcs.MagicDamageReduction = fMagicDR;

            float[] SurvivalResults = new float [EnumHelper.GetCount(typeof(SurvivalSub))];
            SurvivalResults = GetSurvival(ref TDK, stats, fCurrentDTPSPerc, ArmorDamageReduction, fMagicDR);

            calcs.ArmorDamageReduction   = ArmorDamageReduction;
            calcs.PhysicalSurvival       = SoftCapSurvival(TDK, fCurrentDmgBiggestHit[(int)SurvivalSub.Physical], SurvivalResults[(int)SurvivalSub.Physical], isBurstCalc);
            calcs.BleedSurvival          = SoftCapSurvival(TDK, fCurrentDmgBiggestHit[(int)SurvivalSub.Bleed],    SurvivalResults[(int)SurvivalSub.Bleed], isBurstCalc);
            calcs.MagicSurvival          = SoftCapSurvival(TDK, fCurrentDmgBiggestHit[(int)SurvivalSub.Magic],    SurvivalResults[(int)SurvivalSub.Magic], isBurstCalc);
            calcs.HitsToSurvive          = TDK.calcOpts.HitsToSurvive;
            #endregion

            #region ***** Threat Rating *****
            rot.TotalDamage += (int)(stats.FireDamage * (1 + stats.BonusFireDamageMultiplier) * rot.CurRotationDuration);
            rot.TotalThreat += (int)(stats.FireDamage * (1 + stats.BonusFireDamageMultiplier) * rot.CurRotationDuration) * 2;
            calcs.RotationTime = rot.CurRotationDuration; // Display the rot in secs.
            calcs.Threat = rot.m_TPS;
            calcs.DPS = rot.m_DPS;
            calcs.Blood = rot.m_BloodRunes;
            calcs.Frost = rot.m_FrostRunes;
            calcs.Unholy = rot.m_UnholyRunes;
            calcs.Death = rot.m_DeathRunes;
            calcs.RP = rot.m_RunicPower;
            calcs.TotalThreat = (int)rot.TotalThreat;

            calcs.ThreatWeight = TDK.calcOpts.ThreatWeight;
            if (needsDisplayCalcs)
            {
                TDK.calcOpts.szRotReport = rot.ReportRotation();
            }
            #endregion

            #region ***** Mitigation Rating *****
            float[] fCurrentDTPSNoAvoid = new float[3];
            fCurrentDTPSNoAvoid = fCurrentDTPS.Clone() as float[];
            float[] fCurrentMitigation = GetMitigation(ref TDK, stats, rot, (stats.CritChanceReduction / .06f), ArmorDamageReduction, fCurrentDTPS, fMagicDR);
            calcs.ArmorMitigation        = fCurrentMitigation[(int)MitigationSub.Armor];
            calcs.AvoidanceMitigation    = fCurrentMitigation[(int)MitigationSub.Avoidance];
            calcs.CritMitigation         = fCurrentMitigation[(int)MitigationSub.Crit];
            calcs.DamageTakenMitigation  = fCurrentMitigation[(int)MitigationSub.DamageReduction];
            calcs.DamageTakenMitigation += fCurrentMitigation[(int)MitigationSub.Haste];
            calcs.HealsMitigation        = fCurrentMitigation[(int)MitigationSub.Heals];
            calcs.ImpedenceMitigation    = fCurrentMitigation[(int)MitigationSub.Impedences];
            calcs.MagicDamageReductedByAmount = fCurrentMitigation[(int)MitigationSub.AMS];
            calcs.MagicDamageReductedByAmount += fCurrentMitigation[(int)MitigationSub.Magic];

            calcs.Crit = (.06f - stats.CritChanceReduction);
            calcs.DTPS = 0;
            calcs.DTPSNoAvoidance = 0;
            foreach (float f in fCurrentDTPS)
            {
                // These are sometimes coming back as negative.
                // Assuming we are just 100% absorbing the attack, no damage
                if (f > 0) { calcs.DTPS += f; }
            }
            if (TDK.calcOpts.b_RecoveryInclAvoidance == false)
            {
                GetMitigation(ref TDK, stats, rot, (stats.CritChanceReduction / .06f), ArmorDamageReduction, fCurrentDTPSNoAvoid, fMagicDR, false);
                foreach (float f in fCurrentDTPSNoAvoid)
                {
                    // These are sometimes coming back as negative.
                    // Assuming we are just 100% absorbing the attack, no damage
                    if (f > 0) { calcs.DTPSNoAvoidance += f; }
                }
            }
            // Have to ensure we don't divide by 0
            calcs.Mitigation = StatConversion.MitigationScaler / (Math.Max(1f, calcs.DTPS) / fTotalDTPS);
            #endregion

            return calcs;
        }
Beispiel #10
0
        public void AbilityDK_PlagueStrike_BP_Basic()
        {
            // Needs AP passed in 
            Stats FFTestStats = new StatsDK();
            FFTestStats.AttackPower = 100;
            
            Item i = new Item("Test", ItemQuality.Common, ItemType.Dagger, 1, "", ItemSlot.MainHand, "", false, new Stats(), new Stats(), ItemSlot.None, ItemSlot.None, ItemSlot.None, 10, 20, ItemDamageType.Physical, 2, "");
            Rawr.TankDK.CalculationOptionsTankDK c = new Rawr.TankDK.CalculationOptionsTankDK();
            //c.talents = new DeathKnightTalents();
            //Weapon w = new Weapon(i, FFTestStats, c, 0f);

            CombatState combatState = new CombatState();
            //combatState.m_Stats = FFTestStats;
            //combatState.MH = w;
            //combatState.m_Talents = c.talents;
            
            //AbilityDK_PlagueStrike PS = new AbilityDK_PlagueStrike(combatState);

            // Blood Plauge application.
            //AbilityDK_BloodPlague BP = new AbilityDK_BloodPlague(combatState);

            // A disease dealing [0 + AP * 0.055 * 1.15] Shadow damage every 3 sec . 
            // Base damage 0
            // Bonus from attack power [AP * 0.055 * 1.15]

            // Plague Strike Checking
            /*
            Assert.IsTrue(PS.szName == "Plague Strike", "Name");
            Assert.AreEqual(PS.AbilityCost[(int)DKCostTypes.Blood], 0, "Blood Rune");
            Assert.AreEqual(PS.AbilityCost[(int)DKCostTypes.Frost], 0, "Frost Rune");
            Assert.AreEqual(PS.AbilityCost[(int)DKCostTypes.UnHoly], 1, "UnHoly Rune");
            Assert.AreEqual(PS.AbilityCost[(int)DKCostTypes.RunicPower], -10, "RP");
            Assert.AreEqual(Math.Floor((378 + PS.wMH.damage) / 2), PS.uBaseDamage, "BaseDamage");
            Assert.AreEqual(Math.Floor((378 + PS.wMH.damage) / 2), PS.uBaseDamage, "Total Damage");
            Assert.AreEqual(PS.uRange, AbilityDK_Base.MELEE_RANGE, "Range");
            Assert.AreEqual(PS.tDamageType, ItemDamageType.Physical, "Damage Type");
            Assert.AreEqual(PS.Cooldown, 1500u, "Cooldown");

            // Blood Plague Checking
            Assert.IsTrue(BP.szName == "Blood Plague", "Name");
            Assert.AreEqual(BP.AbilityCost[(int)DKCostTypes.Blood], 0, "Blood Rune");
            Assert.AreEqual(BP.AbilityCost[(int)DKCostTypes.Frost], 0, "Frost Rune");
            Assert.AreEqual(BP.AbilityCost[(int)DKCostTypes.UnHoly], 0, "UnHoly Rune");
            Assert.AreEqual(BP.AbilityCost[(int)DKCostTypes.RunicPower], 0, "Runic Power");
            Assert.AreEqual(BP.uBaseDamage, 0u, "Damage");
            Assert.AreEqual(BP.tDamageType, ItemDamageType.Shadow, "Damage Type");
            // Not sure if this actually needs a Cooldown.
//            Assert.AreEqual(BP.Cooldown, 0u, "Cooldown");
            Assert.AreEqual(BP.uDuration, 15000u, "Duration");
            Assert.AreEqual(BP.uTickRate, 3000u, "TickRate");
            Assert.AreEqual((int)(FFTestStats.AttackPower * 0.055f * 1.15f), BP.GetTickDamage(), 0.1, "GetTickDamage");
            Assert.AreEqual((int)(BP.GetTickDamage() * (15 / 3)), BP.GetTotalDamage(), 0.1, "GetTotalDamage");
             * */
        }
        public static void AccumulatePresenceStats(StatsDK PresenceStats, Presence p, DeathKnightTalents t)
        {
            switch(p)
            {
                case Presence.Blood:
                {
                    if (t.ImprovedBloodPresence > 0)
                    {
                        PresenceStats.CritChanceReduction += 0.03f * t.ImprovedBloodPresence;
                        PresenceStats.BonusRuneRegeneration += .1f * t.ImprovedBloodPresence;
                    }
                    else if (t.ImprovedFrostPresence > 0)
                        PresenceStats.BonusRPMultiplier += .02f * t.ImprovedFrostPresence;
                    else if (t.ImprovedUnholyPresence == 1)
                        PresenceStats.MovementSpeed += .08f;
                    else if (t.ImprovedUnholyPresence == 2)
                        PresenceStats.MovementSpeed += .15f;
                    PresenceStats.BonusStaminaMultiplier += .08125f; 
                    if (Rawr.Properties.GeneralSettings.Default.PTRMode)
                        PresenceStats.BaseArmorMultiplier += 0.55f;
                    else
                        PresenceStats.BaseArmorMultiplier += 0.3f;

                    PresenceStats.DamageTakenReductionMultiplier = 1f - (1f - PresenceStats.DamageTakenReductionMultiplier) * (1f - 0.08f);
                    // Threat bonus.
                    PresenceStats.ThreatIncreaseMultiplier += 1f; 
                    break;
                }
                case Presence.Frost:
                {
                    if (t.ImprovedBloodPresence > 0)
                        PresenceStats.DamageTakenReductionMultiplier = 1f - (1f - PresenceStats.DamageTakenReductionMultiplier) * (1f - 0.02f * t.ImprovedBloodPresence);
                    else if (t.ImprovedUnholyPresence == 1)
                        PresenceStats.MovementSpeed += .08f;
                    else if (t.ImprovedUnholyPresence == 2)
                        PresenceStats.MovementSpeed += .15f;
                    PresenceStats.BonusDamageMultiplier += 0.1f;
                    PresenceStats.BonusRPMultiplier += 0.1f;  
                    PresenceStats.ThreatReductionMultiplier += .20f; // Wowhead has this as effect #3
                    break;
                }
                case Presence.Unholy:
                {
                    if (t.ImprovedBloodPresence > 0)
                        PresenceStats.DamageTakenReductionMultiplier = 1f - (1f - PresenceStats.DamageTakenReductionMultiplier) * (1f - 0.02f * t.ImprovedBloodPresence);
                    else if (t.ImprovedFrostPresence > 0)
                        PresenceStats.BonusRPMultiplier += .02f * t.ImprovedFrostPresence;
                    else if (t.ImprovedUnholyPresence > 0)
                        PresenceStats.PhysicalHaste = AddStatMultiplierStat(PresenceStats.PhysicalHaste, (.025f * t.ImprovedUnholyPresence));
                    PresenceStats.PhysicalHaste = AddStatMultiplierStat(PresenceStats.PhysicalHaste, .1f);
                    //PresenceStats.BonusRuneRegeneration += .1f;
                    PresenceStats.MovementSpeed += .15f;
                    PresenceStats.ThreatReductionMultiplier += .20f; // Wowhead has this as effect #3
                    break;
                }
            }
        }
        private void AccumulateSpecialEffectStats(StatsDK s, Character c, CalculationOptionsDPSDK calcOpts, DKCombatTable t, Rotation rot)
        {
            StatsSpecialEffects se = new StatsSpecialEffects(t, rot, c.BossOptions );
            StatsDK statSE = new StatsDK();

            foreach (SpecialEffect effect in s.SpecialEffects())
            {
                if (HasRelevantStats(effect.Stats))
                {
                    statSE = se.getSpecialEffects(effect);
                    s.Accumulate(statSE);
                }
            }
        }
 private StatsDK GetRelevantStatsLocal(Stats stats)
 {
     StatsDK s = new StatsDK();
     s.Accumulate(GetRelevantStats(stats));
     return s;
 }
 private float[] GetMitigation(ref TankDKChar TDK, StatsDK stats, Rotation rot, float fPercentCritMitigation, float ArmorDamageReduction, float[] fCurrentDTPS, float fMagicDR)
 {
     return GetMitigation(ref TDK, stats, rot, fPercentCritMitigation, ArmorDamageReduction, fCurrentDTPS, fMagicDR, true);
 }
        /// <summary>
        /// With Triggers already setup, just pass into the Accumulate function and return the values
        /// </summary>
        /// <param name="effect"></param>
        /// <returns></returns>
        public StatsDK getSpecialEffects(SpecialEffect effect)
        {
            StatsDK statsAverage = new StatsDK();
            triggerIntervals[Trigger.Use] = effect.Cooldown;
            if (float.IsInfinity(effect.Cooldown)) triggerIntervals[Trigger.Use] = m_bo.BerserkTimer;

            effect.AccumulateAverageStats(statsAverage, triggerIntervals, triggerChances, unhastedAttackSpeed, m_bo.BerserkTimer);
            return statsAverage;
        }
Beispiel #16
0
 public DKCombatTable(Character c, StatsDK stats, CharacterCalculationsBase calcs, ICalculationOptionBase calcOpts, BossOptions bossOpts)
 {
     m_CState = new CombatState();
     if (c != null) {
         m_CState.m_Char = c;
         m_CState.m_Talents = c.DeathKnightTalents;
         m_CState.m_Spec = CalculationsDPSDK.GetSpec(c.DeathKnightTalents);
     }
     m_CState.m_Stats = stats;
     // TODO: Put in check here for null.
     m_Calcs = calcs as CharacterCalculationsDPSDK;
     m_Opts = calcOpts as CalculationOptionsDPSDK;
     m_CState.m_Presence = Presence.Frost;
     if (calcOpts != null && m_Opts == null) {
         //throw new Exception("Opts not converted properly.");
         m_Opts = new CalculationOptionsDPSDK();
     }
     try { m_CState.m_Presence = m_Opts.presence; } catch { } // pass  stay w/ default
     m_BO = bossOpts;
     if (m_BO == null) { m_BO = new BossOptions(); }
     // JOTHAY TODO: Kind of an Ugly Hack to do this, but it will give them a value
     m_CState.m_NumberOfTargets = m_BO.MultiTargs ? m_BO.DynamicCompiler_MultiTargs.GetAverageTargetGroupSize(m_BO.BerserkTimer) : 1f;
     //
     m_CState.m_bAttackingFromBehind = m_BO.InBack;
     m_CState.fBossArmor = m_BO.Armor;
     SetupExpertise(c);
 }
        /// <summary>
        /// GetCharacterStats is the 2nd-most calculation intensive method in a model. Here the model will
        /// combine all of the information about the character, including race, gear, enchants, buffs,
        /// calculationoptions, etc., to form a single combined Stats object. Three of the methods below
        /// can be called from this method to help total up stats: GetItemStats(character, additionalItem),
        /// GetEnchantsStats(character), and GetBuffsStats(character.ActiveBuffs).
        /// </summary>
        /// <param name="character">The character whose stats should be totaled.</param>
        /// <param name="additionalItem">An additional item to treat the character as wearing.
        /// This is used for gems, which don't have a slot on the character to fit in, so are just
        /// added onto the character, in order to get gem calculations.</param>
        /// <returns>A Stats object containing the final totaled values of all character stats.</returns>
        public override Stats GetCharacterStats(Character character, Item additionalItem) 
        {
            StatsDK statsTotal = new StatsDK();
            if (null == character)
            {
#if DEBUG
                throw new Exception("Character is Null");
#else
                return statsTotal;
#endif
            }
            CalculationOptionsDPSDK calcOpts = character.CalculationOptions as CalculationOptionsDPSDK;
            if (null == calcOpts) { calcOpts = new CalculationOptionsDPSDK(); }
            DeathKnightTalents talents = character.DeathKnightTalents;
            if (null == talents) { return statsTotal; }

            statsTotal.Accumulate(GetRaceStats(character));
            AccumulateItemStats(statsTotal, character, additionalItem);
            statsTotal = GetRelevantStats(statsTotal) as StatsDK; // GetRel removes any stats specific to the StatsDK object.

            statsTotal.bDW = false;
            if (character.MainHand != null && character.OffHand != null) statsTotal.bDW = true;
            RemoveDuplicateRunes(statsTotal, character, statsTotal.bDW);
            AccumulateBuffsStats(statsTotal, character.ActiveBuffs);

            #region Tank
            #region T11
            int tierCount;
            if (character.SetBonusCount.TryGetValue("Magma Plated Battlearmor", out tierCount))
            {
                if (tierCount >= 2) { statsTotal.b2T11_Tank = true; }
                if (tierCount >= 4) { statsTotal.b4T11_Tank = true; }
            }
            if (statsTotal.b4T11_Tank)
                statsTotal.AddSpecialEffect(_SE_IBF[1]);
            else
                statsTotal.AddSpecialEffect(_SE_IBF[0]);
            #endregion
            #region T12
            if (character.SetBonusCount.TryGetValue("Elementium Deathplate Battlearmor", out tierCount))
            {
                if (tierCount >= 2) { statsTotal.b2T12_Tank = true; }
                if (tierCount >= 4) { statsTotal.b4T12_Tank = true; }
            }
            if (statsTotal.b2T12_Tank)
            {
                // Your melee attacks cause Burning Blood on your target, 
                // which deals 800 Fire damage every 2 for 6 sec and 
                // causes your abilities to behave as if you had 2 diseases 
                // present on the target.

                // Implemented in CombatState DiseaseCount
                statsTotal.FireDamage = 800 / 2;
            }
            if (statsTotal.b4T12_Tank)
            {
                // Your Dancing Rune Weapon grants 15% additional parry chance.
                // Implemented in DRW talent Static Special Effect.
            }
            #endregion
            #region T13
            if (character.SetBonusCount.TryGetValue("Necrotic Boneplate Armor", out tierCount))
            {
                if (tierCount >= 2) { statsTotal.b2T13_Tank = true; }
                if (tierCount >= 4) { statsTotal.b4T13_Tank = true; }
            }
            if (statsTotal.b2T13_Tank)
            {
                // When an attack drops your health below 35%, one of your Blood Runes 
                // will immediately activate and convert into a Death Rune for the next 
                // 20 sec. This effect cannot occur more than once every 45 sec.
            }
            if (statsTotal.b4T13_Tank)
            {
                // Your Vampiric Blood ability also affects all party and raid members 
                // for 50% of the effect it has on you.
            }
            #endregion
            #endregion
            #region DPS
            #region T11
            if (character.SetBonusCount.TryGetValue("Magma Plated Battlegear", out tierCount))
            {
                if (tierCount >= 2)
                {
                    statsTotal.b2T11_DPS = true;
                    if (tierCount >= 4) { statsTotal.b4T11_DPS = true; }
                }
                if (statsTotal.b2T11_DPS)
                {
                    // increase the crit chance of your DeathCoil & FS by 5%
                    statsTotal.BonusCritChanceDeathCoil += .05f;
                    statsTotal.BonusCritChanceFrostStrike += .05f;
                }
                if (statsTotal.b4T11_DPS)
                {
                    // Each time you gain a Death Rune or trigger your Killing Machine talent, 
                    // you also gain 1% increased attack power for 30 sec. Stacks up to 3 times.
                    statsTotal.AddSpecialEffect(new SpecialEffect(Trigger.DeathRuneGained,
                        new Stats() { BonusAttackPowerMultiplier = 0.01f, },
                        30, 0, 1f, 3));
                    statsTotal.AddSpecialEffect(new SpecialEffect(Trigger.KillingMachine,
                        new Stats() { BonusAttackPowerMultiplier = 0.01f, },
                        30, 0, 1f, 3));
                }
            }
            #endregion
            #region T12
            if (character.SetBonusCount.TryGetValue("Elementium Deathplate Battlegear", out tierCount))
            {
                if (tierCount >= 2)
                {
                    statsTotal.b2T12_DPS = true;
                    if (tierCount >= 4)
                    {
                        
                        statsTotal.b4T12_DPS = true;
                    }
                }
            }
            if (statsTotal.b2T12_DPS)
            {
                // Horn of Winter also grats 3 RPp5
                statsTotal.RPp5 += 3;
            }
            if (statsTotal.b4T12_DPS)
            {
                // Your Obliterate and Scourge Strike abilities instantly deal 6% additional damage as Fire damage.
                // Implemented in Oblit and SS classes.
            }
            #endregion
            #region T13
            if (character.SetBonusCount.TryGetValue("Necrotic Boneplate Battlegear", out tierCount))
            {
                if (tierCount >= 2) { statsTotal.b2T13_DPS = true; }
                if (tierCount >= 4) { statsTotal.b4T13_DPS = true; }
            }
            if (statsTotal.b2T13_DPS)
            {
                // Sudden Doom has a 30% chance and Rime has a 60% chance 
                // to grant 2 charges when triggered instead of 1.
            }
            if (statsTotal.b4T13_DPS)
            {
                // Runic Empowerment has a 25% chance and Runic Corruption 
                // has a 40% chance to also grant 710 mastery rating for 12 sec when activated.
            }
            #endregion
            #endregion

            AccumulateTalents(statsTotal, character);
            AccumulatePresenceStats(statsTotal, calcOpts.presence, talents);

            return (statsTotal);
        }
        /// <summary>Build the talent effects.</summary>
        public static void AccumulateTalents(StatsDK FullCharacterStats, Character character)
        {
            Stats newStats = new Stats();
            FullCharacterStats.Mastery += StatConversion.GetMasteryFromRating(FullCharacterStats.MasteryRating);
            // Runic Focus:
            FullCharacterStats.SpellHit += 0.09f;

            // Which talent tree focus?
            #region Talent Speciality
            Rotation.Type r = GetSpec(character.DeathKnightTalents);
            switch (r)
            {
                case Rotation.Type.Blood:
                    {
                        // Special abilities for being blood
                        // Heart Strike
                        // Veteran of the third war
                        // Stamina +9%
                        FullCharacterStats.BonusStaminaMultiplier += .09f;
                        // Expertise +6
                        FullCharacterStats.Expertise += 6;
                        // Blood Rites
                        // Whenever you hit with Death Strike or Obliterate, the Frost and Unholy Runes 
                        // will become Death Runes when they activate.  Death Runes count as a Blood, Frost or Unholy Rune.
                        // Vengence
                        // Each time you take damage, you gain 5% of the damage taken as attack power, up to a maximum of 10% of your health.
                        // Mastery: Blood Shield
                        // Each Time you heal yourself w/ DS you gain a shield worth 50% of the amount healed
                        // Each Point of Mastery increases the shield by 6.25%
                        break;
                    }
                case Rotation.Type.Frost:
                    {
                        // Special abilities for being Frost
                        // Frost Strike
                        // Icy Talons
                        // Melee Attack speed +20%
                        FullCharacterStats.PhysicalHaste = AddStatMultiplierStat(FullCharacterStats.PhysicalHaste, .2f);
                        FullCharacterStats.BonusRuneRegeneration -= .2f; // Only this haste doesn't affect Rune Regen.  

                        // Blood of the North
                        // Blood runes are death runes.
                        // Mastery: Frozen Heart
                        // Increases all frost damage by 16%.  
                        // Each point of mastery increases frost damage by an additional 2.0%
                        FullCharacterStats.BonusFrostDamageMultiplier += .16f + (.02f * FullCharacterStats.Mastery);
                        break;
                    }
                case Rotation.Type.Unholy:
                    {
                        // Special abilities for being Unholy
                        // Scourge Strike
                        // Master of Ghouls
                        // Reduces the CD on Raise dead by 60 sec.
                        // The ghoul summoned is considered your pet w/o a limited duration.
                        // Reaping
                        // Whenever you hit with Blood strike, pestilence, or Festering strike, the runes spent will 
                        // become death runes when they activate.
                        // Unholy Might
                        // Str +25%
                        FullCharacterStats.BonusStrengthMultiplier += .25f;
                        // Mastery: Dreadblade.
                        // Increases shadow damage by 20% + 
                        // Each point of mastery increases shadow damage by an additional 2.5%
                        FullCharacterStats.BonusShadowDamageMultiplier += .2f + (.025f * FullCharacterStats.Mastery);
                        break;
                    }
            }
            #endregion

            #region Blood Talents
            // Butchery
            // 1RPp5 per Point
            if (character.DeathKnightTalents.Butchery > 0)
            {
                FullCharacterStats.RPp5 += 1 * character.DeathKnightTalents.Butchery;
            }

            // Blade Barrier
            // Reduce damage by 2% per point for 10 sec.
            if (character.DeathKnightTalents.BladeBarrier > 0)
            {
                // If you don't have your Blood Runes on CD, you're doing it wrong. 
                FullCharacterStats.DamageTakenReductionMultiplier = 1f - (1f - FullCharacterStats.DamageTakenReductionMultiplier) * (1f - .02f * character.DeathKnightTalents.BladeBarrier);
            }

            // Bladed Armor
            // 2 AP per point per 180 Armor
            if (character.DeathKnightTalents.BladedArmor > 0)
            {
                // If you don't have your Blood Runes on CD, you're doing it wrong. 
                FullCharacterStats.AttackPower += (2 * character.DeathKnightTalents.BladedArmor) * (FullCharacterStats.Armor / 180);
            }

            // Improved Blood Tap
            // Reduces Blood tap CD by 15 sec * pts.
           
            // Scent of Blood
            // 15% after Dodge, Parry or damage received causing 1 melee hit per point to generate 10 runic power.
            // Implemented in WhiteSwing.

            // Scarlet Fever
            // Those hit by BB do have a 50/100% chance to reduce damage dealt by 10% for 30 sec.
            if (character.DeathKnightTalents.ScarletFever > 0)
            {
                // Like Blade Barrier, this should always be up.
                // Be sure to put this in the rotation solver for Tanking Rotations.
                // JOTHAY TODO: Isn't this conflicting with the Buffs pane?
                FullCharacterStats.DamageTakenReductionMultiplier = 1f - (1f - FullCharacterStats.DamageTakenReductionMultiplier) * (1f - .05f * character.DeathKnightTalents.ScarletFever);
            }

            // Hand of Doom
            // Reduces the CD for Strangulate by 30/60 sec.

            if (r == Rotation.Type.Blood)
            {
                // Blood-Caked Blade
                // 10% chance per point to cause Blood-Caked strike
                // Implmented in WhiteDamage ability file.
                
                // Bone Shield
                // 6 Bones 
                // Takes 20% less damage from all sources
                // Does 2% more damage to target
                // Each damaging attack consumes a bone.
                // Lasts 5 mins

                // Toughness
                // Increases Armor Value from items by 3% per point.
                if (character.DeathKnightTalents.Toughness > 0)
                {
                    FullCharacterStats.BaseArmorMultiplier = AddStatMultiplierStat(FullCharacterStats.BaseArmorMultiplier, (.03f * character.DeathKnightTalents.Toughness));
                }

                // Abominations Might
                // increase AP by 5%/10% of raid.
                // 1% per point increase to str.
                if (character.DeathKnightTalents.AbominationsMight > 0)
                {
                    // This happens no matter what:
                    FullCharacterStats.BonusStrengthMultiplier += (0.01f * character.DeathKnightTalents.AbominationsMight);
                    // This happens only if there isn't Trueshot Aura/Unleashed Rage/Abom's might  available:
                    if (!(character.ActiveBuffsContains("Trueshot Aura") || character.ActiveBuffsContains("Unleashed Rage") || character.ActiveBuffsContains("Abomination's Might")))
                    {
                        FullCharacterStats.BonusAttackPowerMultiplier += (.05f * character.DeathKnightTalents.AbominationsMight);
                    }
                }

                // Sanguine Fortitude
                // Buff's IBF:
                // While Active, your IBF reduces Dam taken by 15/30% and costs 50/100% less RP to activate.
                // CD duration? 3min suggested on pwnwear.
                // Cost?  This is a CD stacker.
                // TODO: look into CD stacking code./max v average values.

                // Blood Parasite
                // Melee Attacks have 5% * PTS chance of spawning a blood worm.
                // Blood worm attacks your enemies, gorging itself on blood
                // until it bursts to heal nearby allies. Lasts 20 sec.
                if (character.DeathKnightTalents.BloodParasite > 0)
                {
                    float fDamageDone = 200f; // TODO: Put this in a way to increase DPS.
                    float fBWAttackSpeed = 1.4f; // TODO: Validate this speed.
                    float fBWDuration = 20f;
                    float avgstacks = 5; // TODO: Figure out the best way to determine avg Stacks of BloodGorged
                    float WormHealth = (FullCharacterStats.Health * 0.35f);
                    _SE_Bloodworms = new SpecialEffect[] {
                        null,
                        new SpecialEffect(Trigger.MeleeAttack, new Stats() { Healed = ((avgstacks * WormHealth * .05f) / fBWDuration), PhysicalDamage = (fDamageDone/fBWAttackSpeed) }, fBWDuration, 0, .05f * 1),
                        new SpecialEffect(Trigger.MeleeAttack, new Stats() { Healed = ((avgstacks * WormHealth * .05f) / fBWDuration), PhysicalDamage = (fDamageDone/fBWAttackSpeed) }, fBWDuration, 0, .05f * 2),
                    };
                    FullCharacterStats.AddSpecialEffect(_SE_Bloodworms[character.DeathKnightTalents.BloodParasite]);
                }

                // Improved Blood Presence
                // Reduces chance to be critically hit while in blood presence by 3/6%
                // In addition while in Frost or Unholy, retain the 2/4% Dam reduction. 
                // Implemented in AccumulatePresenceStats()

                // Will of the Necropolis
                // Dam that takes you below 35% health or while at less than 35% is reduced by 5% per point.  
                if (character.DeathKnightTalents.WillOfTheNecropolis > 0)
                {
                    // Need to factor in the damage taken aspect of the trigger.
                    // Using the assumption that the tank will be at < 35% health about that % of the time.
                    FullCharacterStats.AddSpecialEffect(_SE_WillOfTheNecropolis[character.DeathKnightTalents.WillOfTheNecropolis]);
                }

                // Rune Tap
                // Convert 1 BR to 10% health.
                if (character.DeathKnightTalents.RuneTap > 0)
                {
                    FullCharacterStats.AddSpecialEffect(_SE_RuneTap);
                }

                // Vampiric Blood
                // temp 15% of max health and
                // increases health generated by 25% for 10 sec.
                // 1 min CD. 
                if (character.DeathKnightTalents.VampiricBlood > 0)
                {
                    FullCharacterStats.AddSpecialEffect(_SE_VampiricBlood[character.DeathKnightTalents.GlyphofVampiricBlood ? 1 : 0]);
                }

                // Improved Death Strike
                if (character.DeathKnightTalents.ImprovedDeathStrike > 0)
                {
                    FullCharacterStats.BonusDamageDeathStrike += (.40f * character.DeathKnightTalents.ImprovedDeathStrike);
                    // Also improves DS Healing.  Implemented in TankDK heals section.
                }

                // Crimson Scourge 
                // Increases the damage dealt by your Blood Boil by 20/40%, and when you Plague Strike a target that is already
                // infected with your Blood Plague, there is a 50/100% chance that your next Blood Boil will consume no runes.
                if (character.DeathKnightTalents.CrimsonScourge > 0)
                {
                    // Part 1 implmented in BB Ability
                    // TODO: Part 2 implement in rotation.
                }

                // Dancing Rune Weapon
                if (character.DeathKnightTalents.DancingRuneWeapon > 0)
                {
                    uint u4T12 = FullCharacterStats.b4T12_Tank ? 1u : 0u;
                    uint uGDRW = character.DeathKnightTalents.GlyphofDancingRuneWeapon ? 1u : 0u;
                    FullCharacterStats.AddSpecialEffect(_SE_DRW[u4T12][uGDRW]);
                }
            }
            #endregion

            #region Frost Talents

            // Runic Power Mastery
            // Increases Max RP by 10 per point
            if (character.DeathKnightTalents.RunicPowerMastery > 0)
            {
                FullCharacterStats.BonusMaxRunicPower += 10 * character.DeathKnightTalents.RunicPowerMastery;
            }

            // Icy Reach
            // Increases range of IT & CoI and HB by 5 yards per point.

            // Nerves of Cold Steel
            // Increase hit w/ 1H weapons by 1% per point
            // Increase damage done by off hand weapons by 8/16/25% per point
            // Implement off-hand weapon buff in combat shot roation
            if (character.MainHand != null && 
                (character.MainHand.Slot == ItemSlot.MainHand
                || character.MainHand.Slot == ItemSlot.OneHand))
            {
                FullCharacterStats.PhysicalHit += (character.DeathKnightTalents.NervesOfColdSteel * .01f);
            }

            // Lichborne
            // for 10 sec, immune to charm, fear, sleep
            // CD 2 Mins

            // On a Pale Horse
            // Reduce duration of Movement slowing effects by 15% per point
            // increase mount speed by 10% per point
            if (character.DeathKnightTalents.OnAPaleHorse > 0)
            {
                // Now w/ boss handler, reduce the duration of the movement slowing effects. 
            }

            // Endless Winter
            // Mind Freeze RP cost is reduced by 50% per point.
            if (character.DeathKnightTalents.EndlessWinter > 0)
            {  }

            if (r == Rotation.Type.Frost)
            {
                // Merciless Combat
                // addtional 6% per point damage for IT, HB, Oblit, and FS
                // on targets of less than 35% health.
                if (character.DeathKnightTalents.MercilessCombat > 0)
                {
                    // implemented in the abilities section (increase the damage done by 15% * 35%)
                }

                // Chill of the Grave
                // CoI, HB, IT and Oblit generate 5 RP per point.
                if (character.DeathKnightTalents.ChillOfTheGrave > 0)
                {
                    // Implemented in the abilities.
                }

                // Killing Machine
                // Melee attacks have a chance to make OB, or FS a crit.
                // increased proc per point.
                // Research Suggests 5 PPM at 3/3
                if (character.DeathKnightTalents.KillingMachine > 0)
                {
//                    FullCharacterStats.AddSpecialEffect(_KM[character.DeathKnightTalents.KillingMachine]);
                    // Implemented in Frost Rotation
                }


                // Rime
                // Oblit has a 15% per point your next IT or HB consumes no runes
                if (character.DeathKnightTalents.Rime > 0)
                {
                    // Implemented in FrostRotation.
                }

                // Pillar of Frost
                // 1 min CD, 20 sec dur
                // Str +20%
                if (character.DeathKnightTalents.PillarOfFrost > 0)
                {
                    FullCharacterStats.AddSpecialEffect(_SE_PillarOfFrost);
                }

                // Improved Icy Talons
                // increases the melee haste of the group/raid by 10%
                // increases your haste by 5% all the time.
                if (character.DeathKnightTalents.ImprovedIcyTalons > 0)
                {
                    FullCharacterStats.PhysicalHaste = AddStatMultiplierStat(FullCharacterStats.PhysicalHaste, 0.05f);
                    if (!character.ActiveBuffsContains("Improved Icy Talons")
                        && !character.ActiveBuffsContains("Windfury Totem"))
                    {
                        FullCharacterStats.PhysicalHaste = AddStatMultiplierStat(FullCharacterStats.PhysicalHaste, .1f);
                        FullCharacterStats.RangedHaste += .1f;
                    }
                }

                // Brittle Bones:
                // Str +2% per point
                // FF chills the bones of its victims increasing damage taken by 2% per point.
                if (character.DeathKnightTalents.BrittleBones > 0)
                {
                    FullCharacterStats.BonusStrengthMultiplier += .02f * character.DeathKnightTalents.BrittleBones;
                    FullCharacterStats.BonusDamageMultiplier += .02f * character.DeathKnightTalents.BrittleBones;
                }

                // Chilblains
                // FF victimes are movement reduced 25% per point

                // Hungering Cold
                // Spell that freezes all enemies w/ 10 yards.


                // Improved Frost Presence
                // Increases your bonus damage while in Frost Presence by an additional 2% per point.  
                // In addition, while in Blood Presence or Unholy Presence, you retain 2% per point increased runic power generation from Frost Presence.
                if (character.DeathKnightTalents.ImprovedFrostPresence > 0)
                {
                    FullCharacterStats.BonusDamageMultiplier += (0.02f * character.DeathKnightTalents.ImprovedFrostPresence);
                }

                // Threat of Thassarian: 
                // When dual-wielding, your Death Strikes, Obliterates, Plague Strikes, 
                // Blood Strikes and Frost Strikes and Rune Strike (as of 3.2.2) have a 30/60/100% chance 
                // to also deal damage with your off-hand weapon. 
                if (character.DeathKnightTalents.ThreatOfThassarian > 0)
                { 
                    // implemented in the abilities
                }

                // Might of the Frozen Wastes
                // When wielding a two-handed weapon, your autoattacks have a 15% chance to generate 10 Runic Power.
                if (character.DeathKnightTalents.MightOfTheFrozenWastes > 0)
                {
                    // WhiteDamage Bonus in WhiteDamage Ability.
                    if (character.MainHand != null && character.MainHand.Slot == ItemSlot.TwoHand)
                        FullCharacterStats.BonusPhysicalDamageMultiplier += (.1f/3) * character.DeathKnightTalents.MightOfTheFrozenWastes;
                }

                // Howling Blast.
            }
            #endregion

            #region UnHoly Talents
            // Unholy Command
            // reduces CD of DG by 5 sec per point

            // Virulence
            // 
            if (character.DeathKnightTalents.Virulence > 0)
            {
                FullCharacterStats.BonusDiseaseDamageMultiplier += (.1f * character.DeathKnightTalents.Virulence);
            }

            // Epidemic
            // Increases Duration of BP and FF by 4 sec per point
            // Implemented in the abilities page.

            // Desecration
            // PS and SS cause Desecrated Ground effect.
            // Targets are slowed by 25% per point
            // Not Implemented.
            
            // Resilient Infection
            // When your diseases are dispelled you have a 50/100% to activate a 
            // Frost rune if FF was dispelled
            // Unholy rune if BP was dispelled
            // Not Implemented

            // Morbidity
            // increases dam & healing of DC by 5% per point
            // increases dam of DnD by 10% sec per point
            if (character.DeathKnightTalents.Morbidity > 0)
            {
                // implemented in abilities.
            }

            if (r == Rotation.Type.Unholy)
            {
                // Runic Corruption
                // Reduces the cost of your Death Coil by 3 per point, and causes 
                // your Runic Empowerment ability to no longer refresh a depleted 
                // rune, but instead to increase your rune regeneration rate by 50/100% for 3 sec.
                if (character.DeathKnightTalents.RunicCorruption > 0)
                {
                    // Implmented in rotation.
                }

                // Unholy Frenzy
                // Induces a friendly unit into a killing frenzy for 30 sec.  
                // The target is Enraged, which increases their melee and ranged haste by 20%, 
                // but causes them to lose health equal to 2% of their maximum health every 3 sec.
                // TODO:

                // Contagion
                // Increases the damage of your diseases spread via Pestilence by 50/100%.
                if (character.DeathKnightTalents.Contagion > 0)
                    FullCharacterStats.BonusDiseaseDamageMultiplier += .5f * character.DeathKnightTalents.Contagion;

                // Shadow Infusion
                // When you cast Death Coil, you have a 33% per point chance to empower your active Ghoul, 
                // increasing its damage dealt by 10% for 30 sec.  Stacks up to 5 times.
                // TODO: Implement in Rotation & Ghoul

                // Magic Suppression
                // AMS absorbs additional 8, 16, 25% of spell damage.

                // Rage of Rivendare
                // Increases the damage of your Plague Strike, Scourge Strike, and Festering Strike abilities by 15% per point.
                if (character.DeathKnightTalents.RageOfRivendare > 0)
                {
                    // Implemented in the abilities.
                }

                // Unholy Blight
                // Causes the victims of your Death Coil to be surrounded by a vile swarm of unholy insects, 
                // taking 10% of the damage done by the Death Coil over 10 sec, and preventing any diseases on the victim from being dispelled.
                // Implemented in the DeathCoil ability.

                // AntiMagic Zone
                // Creates a zone where party/raid members take 75% less spell damage
                // Lasts 10 secs or X damage.  
                if (character.DeathKnightTalents.AntiMagicZone > 0)
                {
                    FullCharacterStats.AddSpecialEffect(_SE_AntiMagicZone);
                }

                // Improved Unholy Presence
                // Grants you an additional 2% haste while in Unholy Presence.  
                // In addition, while in Blood Presence or Frost Presence, you retain 8% increased movement speed from Unholy Presence.
                // Implemented in Presence Stats.

                // Dark Transformation
                // Consume 5 charges of Shadow Infusion on your Ghoul to transform it into a powerful 
                // undead monstrosity for 30 sec.  The Ghoul's abilities are empowered and take on new 
                // functions while the transformation is active.
                // TODO: implement in Ghoul

                // Ebon Plaguebringer
                // Your Plague Strike, Icy Touch, Chains of Ice, and Outbreak abilities also infect 
                // their target with Ebon Plague, which increases damage taken from your diseases 
                // by 15/30% and all magic damage taken by an additional 8%.
                if (character.DeathKnightTalents.EbonPlaguebringer > 0)
                {
                    if (!character.ActiveBuffsContains("Earth and Moon")
                        && !character.ActiveBuffsContains("Curse of the Elements")
                        && !character.ActiveBuffsContains("Ebon Plaguebringer"))
                    {
                        float fBonus = .08f;
                        FullCharacterStats.BonusArcaneDamageMultiplier += fBonus;
                        FullCharacterStats.BonusFireDamageMultiplier += fBonus;
                        FullCharacterStats.BonusFrostDamageMultiplier += fBonus;
                        FullCharacterStats.BonusHolyDamageMultiplier += fBonus;
                        FullCharacterStats.BonusNatureDamageMultiplier += fBonus;
                        FullCharacterStats.BonusShadowDamageMultiplier += fBonus;
                    }
                    FullCharacterStats.BonusDiseaseDamageMultiplier += (.15f * character.DeathKnightTalents.EbonPlaguebringer);
                }

                // Sudden Doom
                // Your auto attacks have a 5% per point chance to make your next Death Coil cost no runic power.
                // TODO: To Implment in DeathCoil

                // Summon Gargoyle
            }
            #endregion
        }
        /// <summary>
        /// Process All the ratings score to their base values.
        /// </summary>
        /// <param name="s"></param>
        private void ProcessRatings(StatsDK statsTotal)
        {
            // Expertise Rating -> Expertise:
            statsTotal.Expertise += StatConversion.GetExpertiseFromRating(statsTotal.ExpertiseRating);
            // Mastery Rating  Handled during AccumulateTalents.
//            statsTotal.Mastery += StatConversion.GetMasteryFromRating(statsTotal.MasteryRating);

            statsTotal.PhysicalHit += StatConversion.GetPhysicalHitFromRating(statsTotal.HitRating);
            statsTotal.PhysicalCrit += StatConversion.GetPhysicalCritFromRating(statsTotal.CritRating);
            statsTotal.PhysicalCrit += StatConversion.GetPhysicalCritFromAgility(statsTotal.Agility, CharacterClass.DeathKnight);
            statsTotal.PhysicalHaste += StatConversion.GetPhysicalHasteFromRating(statsTotal.HasteRating, CharacterClass.DeathKnight);

            statsTotal.SpellHit += StatConversion.GetSpellHitFromRating(statsTotal.HitRating);
            statsTotal.SpellCrit += StatConversion.GetSpellCritFromRating(statsTotal.CritRating);
            statsTotal.SpellCrit += StatConversion.GetSpellCritFromIntellect(statsTotal.Intellect);
            statsTotal.SpellCrit += statsTotal.SpellCritOnTarget;
            statsTotal.SpellHaste += StatConversion.GetSpellHasteFromRating(statsTotal.HasteRating, CharacterClass.DeathKnight);
        }
        /// <summary>
        /// GetCharacterCalculations is the primary method of each model, where a majority of the calculations
        /// and formulae will be used. GetCharacterCalculations should call GetCharacterStats(), and based on
        /// those total stats for the character, and any calculationoptions on the character, perform all the 
        /// calculations required to come up with the final calculations defined in 
        /// CharacterDisplayCalculationLabels, including an Overall rating, and all Sub ratings defined in 
        /// SubPointNameColors.
        /// </summary>
        /// <param name="character">The character to perform calculations for.</param>
        /// <param name="additionalItem">An additional item to treat the character as wearing.
        /// This is used for gems, which don't have a slot on the character to fit in, so are just
        /// added onto the character, in order to get gem calculations.</param>
        /// <returns>A custom CharacterCalculations object which inherits from CharacterCalculationsBase,
        /// containing all of the final calculations defined in CharacterDisplayCalculationLabels. See
        /// CharacterCalculationsBase comments for more details.</returns>
        public override CharacterCalculationsBase GetCharacterCalculations(Character character, Item additionalItem, bool referenceCalculation, bool significantChange, bool needsDisplayCalculations)
        {
            // First things first, we need to ensure that we aren't using bad data
            CharacterCalculationsDPSDK calc = new CharacterCalculationsDPSDK();
            if (character == null) { return calc; }
            CalculationOptionsDPSDK calcOpts = character.CalculationOptions as CalculationOptionsDPSDK;
            if (calcOpts == null) { return calc; }
            //
            StatsDK stats = new StatsDK();
            DeathKnightTalents talents = character.DeathKnightTalents;

            // Setup initial Boss data.
            // Get Boss from BossOptions data.
            BossOptions hBossOptions = character.BossOptions;
            if (hBossOptions == null) hBossOptions = new BossOptions(); 
            int targetLevel = hBossOptions.Level;

            stats = GetCharacterStats(character, additionalItem) as StatsDK;
            calc.BasicStats = stats.Clone() as StatsDK;
            ApplyRatings(calc.BasicStats);

            DKCombatTable combatTable = new DKCombatTable(character, calc.BasicStats, calc, calcOpts, hBossOptions);
            if (needsDisplayCalculations) combatTable.PostAbilitiesSingleUse(false);
            Rotation rot = new Rotation(combatTable);
            Rotation.Type RotT = rot.GetRotationType(character.DeathKnightTalents);

            // TODO: Fix this so we're not using pre-set rotations/priorities.
            if (RotT == Rotation.Type.Frost)
                rot.PRE_Frost();
            else if (RotT == Rotation.Type.Unholy)
                rot.PRE_Unholy();
            else if (RotT == Rotation.Type.Blood)
                rot.PRE_BloodDiseased();
            else
                rot.Solver();

            //TODO: This may need to be handled special since it's to update stats.
            AccumulateSpecialEffectStats(stats, character, calcOpts, combatTable, rot); // Now add in the special effects.
            ApplyRatings(stats);
            #region Cinderglacier
            if (stats.CinderglacierProc > 0)
            {
                // How many frost & shadow abilities do we have per min.?
                float CGabs = ((rot.m_FrostSpecials + rot.m_ShadowSpecials) / rot.CurRotationDuration) * 60f;
                float effCG = 0;
                if (CGabs > 0)
                    // Since 3 of those abilities get the 20% buff
                    // Get the effective ammount of CinderGlacier that would be applied across each ability.
                    // it is a proc after all.
                    effCG = 3 / CGabs;
                stats.BonusFrostDamageMultiplier += (.2f * effCG);
                stats.BonusShadowDamageMultiplier += (.2f * effCG);
            }
            #endregion

            // refresh w/ updated stats.
            combatTable = new DKCombatTable(character, stats, calc, calcOpts, hBossOptions);
            combatTable.PostAbilitiesSingleUse(false);
            rot = new Rotation(combatTable);
            RotT = rot.GetRotationType(character.DeathKnightTalents);

            // TODO: Fix this so we're not using pre-set rotations.
            if (RotT == Rotation.Type.Frost)
                rot.PRE_Frost();
            else if (RotT == Rotation.Type.Unholy)
                rot.PRE_Unholy();
            else if (RotT == Rotation.Type.Blood)
                rot.PRE_BloodDiseased();
            else
                rot.Solver();

            #region Pet Handling 
            // For UH, this is valid.  For Frost/Blood, we need to have this be 1/3 of the value since it has an uptime of 1 min for every 3.
            float ghouluptime = 1f;
            calc.dpsSub[(int)DKability.Gargoyle] = 0;
            if (RotT != Rotation.Type.Unholy) ghouluptime = 1f / 3f;
            else 
            {
                // Unholy will also have gargoyles.
                Pet Gar = new Gargoyle(stats, talents, hBossOptions, calcOpts.presence);
                float garuptime = .5f/3f;
                calc.dpsSub[(int)DKability.Gargoyle] = Gar.DPS * garuptime;
                calc.damSub[(int)DKability.Gargoyle] = Gar.DPS * 30f; // Duration 30 seconds.
            }
            Pet ghoul = new Ghoul(stats, talents, hBossOptions, calcOpts.presence);
            calc.dpsSub[(int)DKability.Ghoul] = ghoul.DPS * ghouluptime;
            calc.damSub[(int)DKability.Ghoul] = ghoul.DPS * 60f; // Duration 1 min.

            #endregion

            // Stats as Fire damage additive value proc.
            if (stats.ArcaneDamage > 1) calc.dpsSub[(int)DKability.OtherArcane] += stats.ArcaneDamage;
            if (stats.FireDamage > 1) calc.dpsSub[(int)DKability.OtherFire] += stats.FireDamage;
            if (stats.FrostDamage > 1) calc.dpsSub[(int)DKability.OtherFrost] += stats.FrostDamage;
            if (stats.HolyDamage > 1) calc.dpsSub[(int)DKability.OtherHoly] += stats.HolyDamage;
            if (stats.NatureDamage > 1) calc.dpsSub[(int)DKability.OtherNature] += stats.NatureDamage;
            if (stats.ShadowDamage > 1) calc.dpsSub[(int)DKability.OtherShadow] += stats.ShadowDamage;
            // Fire Dam Multiplier.

            calc.RotationTime = rot.CurRotationDuration;
            calc.Blood = rot.m_BloodRunes;
            calc.Frost = rot.m_FrostRunes;
            calc.Unholy = rot.m_UnholyRunes;
            calc.Death = rot.m_DeathRunes;
            calc.RP = rot.m_RunicPower;
            calc.FreeRERunes = rot.m_FreeRunesFromRE;

            calc.EffectiveArmor = stats.Armor;

            calc.OverallPoints = calc.DPSPoints = rot.m_DPS 
                // Add in supplemental damage from other sources
                + calc.dpsSub[(int)DKability.Ghoul] 
                + calc.dpsSub[(int)DKability.Gargoyle]
                + calc.dpsSub[(int)DKability.OtherArcane] + calc.dpsSub[(int)DKability.OtherFire] + calc.dpsSub[(int)DKability.OtherFrost] + calc.dpsSub[(int)DKability.OtherHoly] + calc.dpsSub[(int)DKability.OtherNature] + calc.dpsSub[(int)DKability.OtherShadow];
            if (needsDisplayCalculations)
            {
                AbilityDK_Base a = rot.GetAbilityOfType(DKability.White);
                if (rot.ml_Rot.Count > 1)
                {
                    AbilityDK_Base b;
                    b = rot.GetAbilityOfType(DKability.ScourgeStrike);
                    if (b == null) b = rot.GetAbilityOfType(DKability.FrostStrike);
                    if (b == null) b = rot.GetAbilityOfType(DKability.DeathStrike);
                    calc.YellowHitChance = b.HitChance;
                }
                calc.WhiteHitChance = (a == null ? 0 : a.HitChance + a.CritChance + .23f); // + glancing
                calc.MHWeaponDPS = (a == null ? 0 : rot.GetAbilityOfType(DKability.White).DPS);
                if (null != combatTable.MH)
                {
                    calc.MHWeaponDamage = combatTable.MH.damage;
                    calc.MHAttackSpeed = combatTable.MH.hastedSpeed;
                    calc.DodgedAttacks = combatTable.MH.chanceDodged;
                    calc.AvoidedAttacks = combatTable.MH.chanceDodged;
                    if (!hBossOptions.InBack)
                        calc.AvoidedAttacks += combatTable.MH.chanceParried;
                    calc.MissedAttacks = combatTable.MH.chanceMissed;
                }
                if (null != combatTable.OH)
                {
                    a = rot.GetAbilityOfType(DKability.WhiteOH);
                    calc.OHWeaponDPS = (a == null ? 0 : rot.GetAbilityOfType(DKability.WhiteOH).DPS);
                    calc.OHWeaponDamage = combatTable.OH.damage;
                    calc.OHAttackSpeed = combatTable.OH.hastedSpeed;
                }
                calcOpts.szRotReport = rot.ReportRotation();
                calc.m_RuneCD = (float)rot.m_SingleRuneCD / 1000;

                calc.DPSBreakdown(rot);
            }  

            return calc;
        }
        private void ProcessAvoidance(StatsDK statsTotal, int iTargetLevel, Character c, StatsDK PreRatingsBase)
        {
            // Key point to get avoidance bases.  
            // Ratings with change with multiple passes, 
            // but the actual values need to return back to the base.
            statsTotal.Miss = PreRatingsBase.Miss;
            statsTotal.Dodge = PreRatingsBase.Dodge;
            statsTotal.Parry = PreRatingsBase.Parry;
            // Get all the character avoidance numbers including deminishing returns.
            // Iterate through each hit type. and use fAvoidance array w/ the hitresult enum.
            float[] fAvoidance = new float[HitResultCount];
            for (uint i = 0; i < HitResultCount; i++)
            {
                // GetDRAvoidanceChance returns a dec. percentage.
                // Since CurrentAvoidance is a percent, need to multiply by 100.
                fAvoidance[i] = (StatConversion.GetDRAvoidanceChance(c, statsTotal, (HitResult)i, iTargetLevel));
            }

            // So let's populate the miss, dodge and parry values for the UI display as well as pulling them out of the avoidance number.
            // Cap and floor is already factored in as part of the GetDRAvoidanceChance.
            statsTotal.Miss = fAvoidance[(int)HitResult.Miss];
            statsTotal.Dodge = fAvoidance[(int)HitResult.Dodge];
            statsTotal.Parry = fAvoidance[(int)HitResult.Parry];
        }
Beispiel #22
0
        public Gargoyle(StatsDK dkstats, DeathKnightTalents t, BossOptions bo, Presence p)
        {
            m_BO = bo;
            m_DKStats = dkstats;
            m_Talents = t;
            m_Presence = p;

            AccumulateStats();
            DamageType = ItemDamageType.Physical;
        }
        private float[] GetSurvival(ref TankDKChar TDK, StatsDK stats, float[] DamagePercentages, float ArmorDamageReduction, float fMagicDR)
        {
            // For right now Survival Rating == Effective Health will be HP + Armor/Resistance mitigation values.
            // Everything else is really mitigating damage based on RNG.

            // The health bonus from Frost presence is now include in the character by default.
            float fPhysicalSurvival = stats.Health;
            float fBleedSurvival = stats.Health;
            float fMagicalSurvival = stats.Health;

            // Physical damage:
            fPhysicalSurvival = GetEffectiveHealth(stats.Health, ArmorDamageReduction, DamagePercentages[(int)SurvivalSub.Physical]);

            // Bleed damage:
            fBleedSurvival    = GetEffectiveHealth(stats.Health, 0, DamagePercentages[(int)SurvivalSub.Bleed]);
            
            // Magic Dam:
            fMagicalSurvival  = GetEffectiveHealth(stats.Health, fMagicDR, DamagePercentages[(int)SurvivalSub.Magic]);

            // Since Armor plays a role in Survival, so shall the other damage taken adjusters.
            // Note, it's expected that (at least for tanks) that DamageTakenMultiplier will be Negative.
            // JOTHAY NOTE: The above is no longer true. DamageTakenReductionMultiplier will now be positive, but must be handled multiplicatively and inversely
            // JOTHAY NOTE: YOUR FORMULAS HAVE BEEN UPDATED TO REFLECT THIS CHANGE
            // So the next line should INCREASE survival because 
            // fPhysicalSurvival * (1 - [some negative value] * (1 - [0 or some negative value])
            // will look like:
            // fPhysicalSurvival * 1.xx * 1.xx
            fPhysicalSurvival       = fPhysicalSurvival / ((1f - stats.DamageTakenReductionMultiplier) * (1f - stats.PhysicalDamageTakenReductionMultiplier));
            fBleedSurvival          = fBleedSurvival    / ((1f - stats.DamageTakenReductionMultiplier) * (1f - stats.PhysicalDamageTakenReductionMultiplier));
            fMagicalSurvival        = fMagicalSurvival  / ((1f - stats.DamageTakenReductionMultiplier) * (1f - stats.SpellDamageTakenReductionMultiplier   ));
            float[] SurvivalResults = new float[EnumHelper.GetCount(typeof(SurvivalSub))];
            SurvivalResults[(int)SurvivalSub.Physical] = fPhysicalSurvival;
            SurvivalResults[(int)SurvivalSub.Bleed] = fBleedSurvival;
            SurvivalResults[(int)SurvivalSub.Magic] = fMagicalSurvival;
            return SurvivalResults;
        }
        private void ApplyRatings(StatsDK statsTotal)
        {
            // Apply ratings.
            statsTotal.Expertise += (float)StatConversion.GetExpertiseFromRating(statsTotal.ExpertiseRating);

            statsTotal.Strength += statsTotal.HighestStat + statsTotal.Paragon;

            statsTotal.Agility = (float)Math.Floor(statsTotal.Agility * (1 + statsTotal.BonusAgilityMultiplier));
            statsTotal.Strength = (float)Math.Floor(statsTotal.Strength * (1 + statsTotal.BonusStrengthMultiplier));
            statsTotal.Stamina = (float)Math.Floor(statsTotal.Stamina * (1 + statsTotal.BonusStaminaMultiplier));
            statsTotal.Health += StatConversion.GetHealthFromStamina(statsTotal.Stamina);
            statsTotal.Health *= 1 + statsTotal.BonusHealthMultiplier;
            statsTotal.AttackPower = (float)Math.Floor(statsTotal.AttackPower + statsTotal.Strength * 2);
            statsTotal.Armor = (float)Math.Floor(StatConversion.ApplyMultiplier(statsTotal.Armor, statsTotal.BaseArmorMultiplier) +
                                StatConversion.ApplyMultiplier(statsTotal.BonusArmor, statsTotal.BonusArmorMultiplier));
            statsTotal.AttackPower *= 1f + statsTotal.BonusAttackPowerMultiplier;

            float HighestSecondaryStatValue = statsTotal.HighestSecondaryStat; // how much HighestSecondaryStat to add
            statsTotal.HighestSecondaryStat = 0f; // remove HighestSecondaryStat stat, since it's not needed
            if (statsTotal.CritRating > statsTotal.HasteRating && statsTotal.CritRating > statsTotal.MasteryRating) {
                statsTotal.CritRating += HighestSecondaryStatValue;
            } else if (statsTotal.HasteRating > statsTotal.CritRating && statsTotal.HasteRating > statsTotal.MasteryRating) {
                statsTotal.HasteRating += HighestSecondaryStatValue;
            } else /*if (statsTotal.MasteryRating > statsTotal.CritRating && statsTotal.MasteryRating > statsTotal.HasteRating)*/ {
                statsTotal.MasteryRating += HighestSecondaryStatValue;
            }

            statsTotal.PhysicalHit += StatConversion.GetPhysicalHitFromRating(statsTotal.HitRating);
            statsTotal.PhysicalCrit += StatConversion.GetPhysicalCritFromRating(statsTotal.CritRating);
            statsTotal.PhysicalCrit += StatConversion.GetPhysicalCritFromAgility(statsTotal.Agility, CharacterClass.DeathKnight);
            statsTotal.PhysicalHaste = AddStatMultiplierStat(statsTotal.PhysicalHaste, StatConversion.GetPhysicalHasteFromRating(statsTotal.HasteRating, CharacterClass.DeathKnight));

            statsTotal.SpellHit += StatConversion.GetSpellHitFromRating(statsTotal.HitRating);
            statsTotal.SpellCrit += StatConversion.GetSpellCritFromRating(statsTotal.CritRating);
            statsTotal.SpellCrit += StatConversion.GetSpellCritFromIntellect(statsTotal.Intellect);
            statsTotal.SpellCrit += statsTotal.SpellCritOnTarget;
            statsTotal.SpellHaste += StatConversion.GetSpellHasteFromRating(statsTotal.HasteRating, CharacterClass.DeathKnight);
        }
        private float[] GetMitigation(ref TankDKChar TDK, StatsDK stats, Rotation rot, float fPercentCritMitigation, float ArmorDamageReduction, float[] fCurrentDTPS, float fMagicDR, bool bFactorInAvoidance)
        {
            float[] fTotalMitigation = new float[EnumHelper.GetCount(typeof(MitigationSub))];
            // Ensure the CurrentDTPS structure is the right size.
            if (fCurrentDTPS.Length < EnumHelper.GetCount(typeof(SurvivalSub)))
            {
                fCurrentDTPS = new float[EnumHelper.GetCount(typeof(SurvivalSub))];
            }

            float fSegmentMitigation = 0f;
            float fSegmentDPS = 0f;
            float fPhyDamageDPS = fCurrentDTPS[(int)SurvivalSub.Physical];
            float fMagicDamageDPS = fCurrentDTPS[(int)SurvivalSub.Magic];
            float fBleedDamageDPS = fCurrentDTPS[(int)SurvivalSub.Bleed];
            #region *** Dam Avoided (Crit, Haste, Avoidance) ***
            #region ** Crit Mitigation **
            // Crit mitigation:
            // Crit mitigation work for Physical damage only.
            float fCritMultiplier = .12f;
            // Bleeds can't crit.
            // Neither can spells from bosses.  (As per a Loading screen ToolTip.)
            float fCritDPS = fPhyDamageDPS * fCritMultiplier;
            fSegmentMitigation = (fCritDPS * fPercentCritMitigation);
            // Add in the value of crit mitigation.
            fTotalMitigation[(int)MitigationSub.Crit] = fSegmentMitigation;
            // The max damage at this point needs to include crit.
            fCurrentDTPS[(int)SurvivalSub.Physical] = fCurrentDTPS[(int)SurvivalSub.Physical] + (fCritDPS - fSegmentMitigation);
            #endregion
            #region ** Haste Mitigation **
            // Placeholder for comparing differing DPS values related to haste.
            float fNewIncPhysDPS = 0;
            // Let's just look at Imp Icy Touch 
            #region Improved Icy Touch
            // Get the new slowed AttackSpeed based on ImpIcyTouch
            // Factor in the base slow caused by FF (14% base).
            float fBossAttackSpeedReduction = 0.0f;

            if (rot.Contains(DKability.IcyTouch)
                || rot.Contains(DKability.FrostFever))
            {
                fBossAttackSpeedReduction = 0.2f;
            }
            else if (stats.BossAttackSpeedReductionMultiplier > 0) // FF provided by someone else.
            {
                fBossAttackSpeedReduction = stats.BossAttackSpeedReductionMultiplier;
            }
            // Figure out what the new Physical DPS should be based on that.
            fSegmentDPS = TDK.bo.GetDPSByType(ATTACK_TYPES.AT_MELEE, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
            fNewIncPhysDPS = fSegmentDPS / (1 + fBossAttackSpeedReduction);
            // Send the difference to the Mitigation value.
            fSegmentMitigation = fSegmentDPS - fNewIncPhysDPS;
            fTotalMitigation[(int)MitigationSub.Haste] += fSegmentMitigation;
            fCurrentDTPS[(int)SurvivalSub.Physical] -= fSegmentMitigation;
            #endregion

            #endregion
            #region ** Avoidance Mitigation **
            // Let's see how much damage was avoided.
            // Raise the total mitgation by that amount.
            if (bFactorInAvoidance)
            {
                fSegmentDPS = fNewIncPhysDPS;
                fNewIncPhysDPS = TDK.bo.GetDPSByType(ATTACK_TYPES.AT_MELEE, 0, 0, 0, fBossAttackSpeedReduction, stats.Miss, stats.Dodge, stats.EffectiveParry, 0, 0, 0, 0, 0, 0, 0);
                fSegmentMitigation = fSegmentDPS - fNewIncPhysDPS;
                fTotalMitigation[(int)MitigationSub.Avoidance] += fSegmentMitigation;
                fCurrentDTPS[(int)SurvivalSub.Physical] -= fSegmentMitigation;
            }
            #endregion
            #endregion

            #region *** Dam Reduced (AMS, Armor, Magic Resist, DamageTaken Modifiers) ***
            #region ** Anti-Magic Shell **
            // TODO: This is a CD, so would only be in BURST.
            // Anti-Magic Shell. ////////////////////////////////////////////////////////
            // Talent: MagicSuppression increases AMS by 8/16/25% per point.
            // Glyph: GlyphofAntiMagicShell increases AMS by 2 sec.
            // AMS has a 45 sec CD.
            float amsDuration = (5f + (TDK.Char.DeathKnightTalents.GlyphofAntiMagicShell == true ? 2f : 0f)) * (1 + stats.DefensiveCooldownDurationMultiplier);
            float amsUptimePct = amsDuration / 45f;
            // AMS reduces damage taken by 75% up to a max of 50% health.
            float amsReduction = 0.75f * (1f + (TDK.Char.DeathKnightTalents.MagicSuppression * .25f / 3));
            float amsReductionMax = stats.Health * 0.5f * (1 + stats.DefensiveCooldownReductionMultiplier);
            // up to 50% of health means that the amdDRvalue equates to the raw damage points removed.  
            // This means that toon health and INC damage values from the options pane are going to affect this quite a bit.
            float amsDRvalue = (Math.Min(amsReductionMax, (fMagicDamageDPS * amsDuration) * amsReduction) * amsUptimePct);
            // Raise the TotalMitigation by that amount.
            fCurrentDTPS[(int)SurvivalSub.Magic] -= amsDRvalue;
            fTotalMitigation[(int)MitigationSub.AMS] += amsDRvalue;
            #endregion
            #region ** Armor Dam Mitigation **
            // For any physical only damage reductions. 
            // Factor in armor Dam Reduction
            fSegmentMitigation = fPhyDamageDPS * ArmorDamageReduction;
//            calcs.ArmorMitigation = fSegmentMitigation;
            fTotalMitigation[(int)MitigationSub.Armor] += fSegmentMitigation;
            fCurrentDTPS[(int)SurvivalSub.Physical] *= 1f - ArmorDamageReduction;
            #endregion
            #region ** Resistance Dam Mitigation **
            // For any physical only damage reductions. 
            // Factor in armor Dam Reduction
            fSegmentMitigation = fMagicDamageDPS * fMagicDR;
            fTotalMitigation[(int)MitigationSub.Magic] += fSegmentMitigation;
            fCurrentDTPS[(int)SurvivalSub.Magic] -= fCurrentDTPS[(int)SurvivalSub.Magic] * fMagicDR;
            #endregion
            #region ** Dam Taken Mitigation **
            fTotalMitigation[(int)MitigationSub.DamageReduction] += fMagicDamageDPS * (1f - stats.DamageTakenReductionMultiplier) * (1f - stats.SpellDamageTakenReductionMultiplier   );
            fTotalMitigation[(int)MitigationSub.DamageReduction] += fBleedDamageDPS * (1f - stats.DamageTakenReductionMultiplier) * (1f - stats.PhysicalDamageTakenReductionMultiplier);
            fTotalMitigation[(int)MitigationSub.DamageReduction] += fPhyDamageDPS   * (1f - stats.DamageTakenReductionMultiplier) * (1f - stats.PhysicalDamageTakenReductionMultiplier);
            
            fCurrentDTPS[(int)SurvivalSub.Magic]    *= (1f - stats.DamageTakenReductionMultiplier) * (1f - stats.SpellDamageTakenReductionMultiplier   );
            fCurrentDTPS[(int)SurvivalSub.Bleed]    *= (1f - stats.DamageTakenReductionMultiplier) * (1f - stats.PhysicalDamageTakenReductionMultiplier);
            fCurrentDTPS[(int)SurvivalSub.Physical] *= (1f - stats.DamageTakenReductionMultiplier) * (1f - stats.PhysicalDamageTakenReductionMultiplier);
            #endregion
            #region ** Dam Absorbed ** 
            fTotalMitigation[(int)MitigationSub.DamageReduction] += stats.DamageAbsorbed;

//            fCurrentDTPS[(int)SurvivalSub.Magic] *= (1f - stats.DamageTakenReductionMultiplier) * (1f - stats.SpellDamageTakenReductionMultiplier);
//            fCurrentDTPS[(int)SurvivalSub.Bleed] *= (1f - stats.DamageTakenReductionMultiplier) * (1f - stats.PhysicalDamageTakenReductionMultiplier);
//            fCurrentDTPS[(int)SurvivalSub.Physical] *= (1f - stats.DamageTakenReductionMultiplier) * (1f - stats.PhysicalDamageTakenReductionMultiplier);

            #endregion
            #endregion

            #region ** Boss Handler Mitigation (Impedences) **
            float TotalDuration = 0;
            float ImprovedDuration = 0;
            float ImpedenceMitigation = 0;
            #region ** Fear Based Mitigation (fear reduction) **
            if (TDK.bo.Fears.Count > 0)
            {
                foreach (Impedance m in TDK.bo.Fears)
                {
                    TotalDuration += m.Duration;
                }
                ImprovedDuration = TotalDuration / (1 + stats.FearDurReduc);
                fSegmentMitigation = (TotalDuration - ImprovedDuration) /* Add some multiplier to this */;
                ImpedenceMitigation += fSegmentMitigation;
            }
            #endregion

            #region ** Movement Based Mitigation (run speed) **
            if (TDK.bo.Moves.Count > 0)
            {
                TotalDuration = 0;
                foreach (Impedance m in TDK.bo.Moves)
                {
                    TotalDuration += m.Duration;
                }
                ImprovedDuration = TotalDuration / (1 + stats.MovementSpeed);
                fSegmentMitigation = (TotalDuration - ImprovedDuration) /* Add some multiplier to this */;
                ImpedenceMitigation += fSegmentMitigation;
            }
            #endregion

            #region ** Disarm Based Mitigation (Disarm reduction) **
            if (TDK.bo.Disarms.Count > 0)
            {
                TotalDuration = 0;
                foreach (Impedance m in TDK.bo.Disarms)
                {
                    TotalDuration += m.Duration;
                }
                ImprovedDuration = TotalDuration / (1 + stats.DisarmDurReduc);
                fSegmentMitigation = (TotalDuration - ImprovedDuration) /* Add some multiplier to this */;
                ImpedenceMitigation += fSegmentMitigation;
            }
            #endregion

            #region ** Stun Based Mitigation (stun reduction) **
            if (TDK.bo.Stuns.Count > 0)
            {
                TotalDuration = 0;
                foreach (Impedance m in TDK.bo.Stuns)
                {
                    TotalDuration += m.Duration;
                }
                ImprovedDuration = TotalDuration / (1 + stats.StunDurReduc);
                fSegmentMitigation = (TotalDuration - ImprovedDuration) /* Add some multiplier to this */;
                ImpedenceMitigation += fSegmentMitigation;
            }
            #endregion
            // calcs.ImpedenceMitigation = ImpedenceMitigation;
            fTotalMitigation[(int)MitigationSub.Impedences] += ImpedenceMitigation;
            #endregion

            #region ** Heals not from DS **
            fSegmentMitigation = StatConversion.ApplyMultiplier(stats.Healed, stats.HealingReceivedMultiplier);
            fSegmentMitigation += (StatConversion.ApplyMultiplier(stats.Hp5, stats.HealingReceivedMultiplier) / 5);
            fSegmentMitigation += StatConversion.ApplyMultiplier(stats.HealthRestore, stats.HealingReceivedMultiplier);
            // Health Returned by other sources than DS:
            if (stats.HealthRestoreFromMaxHealth > 0)
                fSegmentMitigation += (stats.HealthRestoreFromMaxHealth * stats.Health);
            fTotalMitigation[(int)MitigationSub.Heals] = fSegmentMitigation;
            #endregion

            return fTotalMitigation;
        }
        public override Stats GetRelevantStats(Stats stats)
        {
            StatsDK s = new StatsDK()
            {
                // Core stats
                Strength = stats.Strength,
                Agility = stats.Agility,
                Stamina = stats.Stamina,
                ExpertiseRating = stats.ExpertiseRating,
                AttackPower = stats.AttackPower,
                MasteryRating = stats.MasteryRating,
                // Other Base Stats
                HasteRating = stats.HasteRating,
                HitRating = stats.HitRating,
                CritRating = stats.CritRating,
                Armor = stats.Armor,
                BonusArmor = stats.BonusArmor,
                Resilience = stats.Resilience,

                // Secondary Stats
                Health = stats.Health,
                SpellHaste = stats.SpellHaste,
                PhysicalCrit = stats.PhysicalCrit,
                PhysicalHaste = stats.PhysicalHaste,
                PhysicalHit = stats.PhysicalHit,
                SpellCrit = stats.SpellCrit,
                SpellCritOnTarget = stats.SpellCritOnTarget,
                SpellHit = stats.SpellHit,
                SpellPenetration = stats.SpellPenetration,

                // Dam stats
                WeaponDamage = stats.WeaponDamage,
                PhysicalDamage = stats.PhysicalDamage,
                ShadowDamage = stats.ShadowDamage,
                ArcaneDamage = stats.ArcaneDamage,
                FireDamage = stats.FireDamage,
                FrostDamage = stats.FrostDamage,
                HolyDamage = stats.HolyDamage,
                NatureDamage = stats.NatureDamage,

                // Bonus to stat
                BonusHealthMultiplier = stats.BonusHealthMultiplier,
                BonusStrengthMultiplier = stats.BonusStrengthMultiplier,
                BonusStaminaMultiplier = stats.BonusStaminaMultiplier,
                BonusAgilityMultiplier = stats.BonusAgilityMultiplier,
                BonusCritDamageMultiplier = stats.BonusCritDamageMultiplier,
                BonusAttackPowerMultiplier = stats.BonusAttackPowerMultiplier,

                // Bonus to Dam
                // *Dam
                BonusWhiteDamageMultiplier = stats.BonusWhiteDamageMultiplier,
                BonusDamageMultiplier = stats.BonusDamageMultiplier,
                BonusPhysicalDamageMultiplier = stats.BonusPhysicalDamageMultiplier,
                BonusShadowDamageMultiplier = stats.BonusShadowDamageMultiplier,
                BonusFrostDamageMultiplier = stats.BonusFrostDamageMultiplier,
                BonusDiseaseDamageMultiplier = stats.BonusDiseaseDamageMultiplier,
                // +Dam
                BonusFrostWeaponDamage = stats.BonusFrostWeaponDamage,
                BonusDamageScourgeStrike = stats.BonusDamageScourgeStrike,
                BonusDamageBloodStrike = stats.BonusDamageBloodStrike,
                BonusDamageDeathCoil = stats.BonusDamageDeathCoil, 
                BonusDamageDeathStrike =  stats.BonusDamageDeathStrike,
                BonusDamageFrostStrike = stats.BonusDamageFrostStrike,
                BonusDamageHeartStrike = stats.BonusDamageHeartStrike,
                BonusDamageIcyTouch = stats.BonusDamageIcyTouch,
                BonusDamageObliterate = stats.BonusDamageObliterate,
                // Crit
                BonusCritChanceDeathCoil = stats.BonusCritChanceDeathCoil,
                BonusCritChanceFrostStrike = stats.BonusCritChanceFrostStrike,
                BonusCritChanceObliterate = stats.BonusCritChanceObliterate,
                // Other
                CinderglacierProc = stats.CinderglacierProc,
                HighestStat = stats.HighestStat,
                HighestSecondaryStat = stats.HighestSecondaryStat,
                Paragon = stats.Paragon,
                ThreatIncreaseMultiplier = stats.ThreatIncreaseMultiplier,
                ThreatReductionMultiplier = stats.ThreatReductionMultiplier,
                TargetArmorReduction = stats.TargetArmorReduction,
                // BossHandler
                SnareRootDurReduc = stats.SnareRootDurReduc,
                FearDurReduc = stats.FearDurReduc,
                StunDurReduc = stats.StunDurReduc,
                MovementSpeed = stats.MovementSpeed,
            };

            foreach (SpecialEffect effect in stats.SpecialEffects())
            {
                if (HasRelevantStats(effect.Stats))
                {
                    if (effect.Trigger == Trigger.DamageDone ||
                        effect.Trigger == Trigger.DamageOrHealingDone ||
                        effect.Trigger == Trigger.DamageSpellCast ||
                        effect.Trigger == Trigger.DamageSpellCrit ||
                        effect.Trigger == Trigger.DamageSpellHit ||
                        effect.Trigger == Trigger.SpellCast ||
                        effect.Trigger == Trigger.SpellCrit ||
                        effect.Trigger == Trigger.SpellHit ||
                        effect.Trigger == Trigger.DoTTick ||
                        effect.Trigger == Trigger.MeleeCrit ||
                        effect.Trigger == Trigger.MeleeHit ||
                        effect.Trigger == Trigger.CurrentHandHit ||
                        effect.Trigger == Trigger.MainHandHit ||
                        effect.Trigger == Trigger.OffHandHit ||
                        effect.Trigger == Trigger.PhysicalCrit ||
                        effect.Trigger == Trigger.PhysicalHit ||
                        effect.Trigger == Trigger.PhysicalAttack ||
                        effect.Trigger == Trigger.BloodStrikeHit ||
                        effect.Trigger == Trigger.HeartStrikeHit ||
                        effect.Trigger == Trigger.ScourgeStrikeHit ||
                        effect.Trigger == Trigger.ObliterateHit ||
                        effect.Trigger == Trigger.DeathStrikeHit ||
                        effect.Trigger == Trigger.IcyTouchHit ||
                        effect.Trigger == Trigger.PlagueStrikeHit ||
                        effect.Trigger == Trigger.RuneStrikeHit ||
                        effect.Trigger == Trigger.DeathRuneGained ||
                        effect.Trigger == Trigger.Use)
                    {
                        s.AddSpecialEffect(effect);
                    }
                }
            }

            return s;
        }