コード例 #1
0
        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
            CharacterCalculationsEnhance calc = new CharacterCalculationsEnhance();
            if (character == null) { return calc; }
            CalculationOptionsEnhance calcOpts = character.CalculationOptions as CalculationOptionsEnhance;
            if (calcOpts == null) { return calc; }
            BossOptions bossOpts = character.BossOptions;
            if (bossOpts == null) { bossOpts = new BossOptions(); }
            
            #region Applied Stats
            Stats stats = GetCharacterStats(character, additionalItem);
            //StatsEnhance stats = GetCharacterStats(character, additionalItem) as StatsEnhance;
            calc.BasicStats = stats;
            calc.BuffStats = GetBuffsStats(character.ActiveBuffs, character.SetBonusCount);
            Item noBuffs = RemoveAddedBuffs(calc.BuffStats);
            calc.EnhSimStats = GetCharacterStats(character, noBuffs);
            calc.TargetLevel = bossOpts.Level;
            calc.ActiveBuffs = new List<Buff>(character.ActiveBuffs);
            float initialAP = stats.AttackPower;

            // deal with Special Effects - for now add into stats regardless of effect later need to be more precise
            StatsSpecialEffects se = new StatsSpecialEffects(character, stats, calcOpts, bossOpts);
            stats.Accumulate(se.getSpecialEffects());
            //Set up some talent variables
            float concussionMultiplier = 1f + .02f * character.ShamanTalents.Concussion; //
            float shieldBonus = 1f + .05f * character.ShamanTalents.ImprovedShields; //
            float callofFlameBonus = 1f + .1f * character.ShamanTalents.CallOfFlame; //
            float mentalQuickness = .5f;  //AP -> SP conversion
            float windfuryWeaponBonus = 4430f;  //WFAP (Check)
            float windfuryDamageBonus = 1f; //
            switch (character.ShamanTalents.ElementalWeapons)
            {
                case 1: windfuryDamageBonus = 1.20f; break;
                case 2: windfuryDamageBonus = 1.40f; break;
            }
            float focusedStrikes = 1f; //
            switch (character.ShamanTalents.FocusedStrikes)
            {
                case 1: focusedStrikes = 1.15f; break;
                case 2: focusedStrikes = 1.30f; break;
                case 3: focusedStrikes = 1.45f; break;
            }
            float unleashedRage = 0f;
            switch (character.ShamanTalents.UnleashedRage)
            {
                case 1: unleashedRage = .05f; break;
                case 2: unleashedRage = .10f; break;
            }

            // Tier Bonuses
            int setCount;
            float enhance2T11 = 0f;
            character.SetBonusCount.TryGetValue("Battlegear of the Raging Elements", out setCount);
            if (setCount >= 2)
            {
                enhance2T11 = 0.1f;
            }
            float enhance2T12 = 0f;
            float enhance4T12 = 0f;
            character.SetBonusCount.TryGetValue("Volcanic Battlegear", out setCount);
            if (setCount >= 2)
            {
                enhance2T12 = 0.05f;
            }
            if (setCount >= 4)
            {
                if (calcOpts.PriorityInUse(EnhanceAbility.StormStrike))
                {
                    enhance4T12 = 0.06f;
                    //enhance4T12 = 0.16f;
                }
            }
            //
            float FTspellpower = (float)Math.Floor((float)(748f * (1 + character.ShamanTalents.ElementalWeapons * .2f)));
            if (calcOpts.MainhandImbue == "Flametongue")
                stats.SpellPower += FTspellpower;
            if (calcOpts.OffhandImbue == "Flametongue")
                stats.SpellPower += FTspellpower;

            float addedAttackPower = stats.AttackPower - initialAP;
            float MQSpellPower = mentalQuickness * addedAttackPower * (1 + stats.BonusAttackPowerMultiplier);
            // make sure to add in the spellpower from MQ gained from all the bonus AP added in this section
            stats.SpellPower += MQSpellPower * (1 + stats.BonusSpellPowerMultiplier);
            // also add in bonus attack power
            stats.AttackPower += addedAttackPower * stats.BonusAttackPowerMultiplier;
            //
            #endregion

            #region Damage Model
            ////////////////////////////
            // Main calculation Block //
            ////////////////////////////

            CombatStats cs = new CombatStats(character, stats, calcOpts, bossOpts); // calculate the combat stats using modified stats

            // only apply unleashed rage talent if not already applied Unleashed Rage buff.
            if (!character.ActiveBuffsContains("Unleashed Rage") && 
                !character.ActiveBuffsContains("Trueshot Aura") && 
                !character.ActiveBuffsContains("Abomination's Might"))
            {
                float URattackPower = (calc.BuffStats.BonusAttackPowerMultiplier == .1f) ? 0f :
                                                        (stats.AttackPower * unleashedRage);
                stats.AttackPower += URattackPower; // no need to multiply by bonus attack power as the whole point is its zero if we need to add Unleashed rage
                stats.SpellPower += mentalQuickness * URattackPower * (1f + stats.BonusSpellPowerMultiplier);
            }

            // assign basic variables for calcs
            float attackPower = stats.AttackPower;
            float spellPower = stats.SpellPower;
            float mastery = 1f + ((8f + StatConversion.GetMasteryFromRating(stats.MasteryRating)) * 0.025f);
            float wdpsMH = character.MainHand == null ? 46.3f : (stats.WeaponDamage + (character.MainHand.MinDamage + character.MainHand.MaxDamage) / 2f) / character.MainHand.Speed;
            float wdpsOH = character.OffHand == null ? 46.3f : (stats.WeaponDamage + (character.OffHand.MinDamage + character.OffHand.MaxDamage) / 2f) / character.OffHand.Speed;
            float dualWieldSpecialization = .06f; //Hit portion of Dual Wield
            float bonusPhysicalDamage = (1f + stats.BonusDamageMultiplier) * (1f + stats.BonusPhysicalDamageMultiplier);
            //float bonusFrostDamage    = (1f + stats.BonusDamageMultiplier) * (1f + stats.BonusFrostDamageMultiplier) * (1f + character.ShamanTalents.ElementalPrecision * 0.01f); //
            float bonusFireDamage     = (1f + stats.BonusDamageMultiplier) * (1f + stats.BonusFireDamageMultiplier  ) * (1f + character.ShamanTalents.ElementalPrecision * 0.01f); //
            float bonusNatureDamage   = (1f + stats.BonusDamageMultiplier) * (1f + stats.BonusNatureDamageMultiplier) * (1f + character.ShamanTalents.ElementalPrecision * 0.01f); //
            #endregion

            #region Individual DPS
            #region Melee DPS
            float APDPS = (attackPower / 14f);
            float adjustedMHDPS = (wdpsMH + APDPS);
            float adjustedOHDPS = 0f;
            float dpsOHMeleeTotal = 0f;
            float dpsMoteOfAnger = 0f;

            float dpsMHMeleeNormal = adjustedMHDPS * cs.NormalHitModifierMH;
            float dpsMHMeleeCrits = adjustedMHDPS * cs.CritHitModifierMH;
            float dpsMHMeleeGlances = adjustedMHDPS * cs.GlancingHitModifier;
            float meleeMultipliers = cs.DamageReduction * bonusPhysicalDamage * (1f + stats.BonusWhiteDamageMultiplier);

            float dpsMHMeleeTotal = ((dpsMHMeleeNormal + dpsMHMeleeCrits + dpsMHMeleeGlances) * cs.UnhastedMHSpeed / cs.HastedMHSpeed) * meleeMultipliers;

            if (cs.HastedOHSpeed != 0)
            {
                adjustedOHDPS = (wdpsOH + APDPS) * .5f;
                float dpsOHMeleeNormal = adjustedOHDPS * cs.NormalHitModifierOH;
                float dpsOHMeleeCrits = adjustedOHDPS * cs.CritHitModifierOH;
                float dpsOHMeleeGlances = adjustedOHDPS * cs.GlancingHitModifier;
                dpsOHMeleeTotal = ((dpsOHMeleeNormal + dpsOHMeleeCrits + dpsOHMeleeGlances) * cs.UnhastedOHSpeed / cs.HastedOHSpeed) * meleeMultipliers;
            }

            // Generic MH & OH damage values used for SS, LL & WF
            float damageMHSwing = adjustedMHDPS * cs.UnhastedMHSpeed;
            float damageOHSwing = adjustedOHDPS * cs.UnhastedOHSpeed;

            if (cs.HastedOHSpeed != 0)
                dpsMoteOfAnger = (damageMHSwing + damageOHSwing) / 2 * stats.MoteOfAnger;
            else
                dpsMoteOfAnger = damageMHSwing * stats.MoteOfAnger;

            float dpsMelee = dpsMHMeleeTotal + dpsOHMeleeTotal + dpsMoteOfAnger;
            #endregion

            #region Stormstrike DPS
            float dpsSS = 0f;
            if (character.ShamanTalents.Stormstrike == 1 && calcOpts.PriorityInUse(EnhanceAbility.StormStrike) && character.MainHand != null)
            {
                float swingDPSMH = damageMHSwing * 2.25f * cs.HitsPerSMHSS;
                float swingDPSOH = damageOHSwing * 2.25f * cs.HitsPerSOHSS;
                float SSnormal = (swingDPSMH * cs.YellowHitModifierMH) + (swingDPSOH * cs.YellowHitModifierOH);
                float SScrit = ((swingDPSMH * cs.YellowCritModifierMH) + (swingDPSOH * cs.YellowCritModifierOH)) * cs.CritMultiplierMelee;
                dpsSS = (SSnormal + SScrit) * cs.DamageReduction * /*(1f + stats.BonusStormstrikeDamageMultiplier)*/focusedStrikes * (1f + enhance2T11);
            }
            #endregion

            #region Lavalash DPS
            /* Taken from EnhSim (thank you ziff)
               Damage = bwd * llb * (1.0 + sfs * (sfb + t12-2p) + ftb) * (1.0 + llt + llg + t11-2p) * fdm

               bwd    - Base weapon damage against a target with no armor
               llb    - Lava Lash Bonus, this is the default lava lash damage bonus of 2.0
               sfs    - # of current stacks of Searing Flames
               sfb    - the searing flames bonus from Improved Lava Lash.  Maxed out it is .20
               t12-2p - the 2 piece bonus from T12, which is currently an extra 0.05 per searing flame stack
               ftb    - the bonus if Flametongue weapon is on your off-hand, which is 0.40
               llt    - the Lava lash damage bonus from Improved Lava Lash.  Maxed out, it is 0.30
               llg    - the bonus from Lava Lash glyph, which is 0.20
               t11-2p - the 2 piece bonus from T11, which is 0.10
               fdm    - the fire damage multiplier, which includes the mastery bonus, elemental precision,
                        buffs, debuff, etc.  These multipliers are always multiplied to each other, and not
                        done additively.
             */
            float dpsLL = 0f;
            if (calcOpts.PriorityInUse(EnhanceAbility.LavaLash) && character.OffHand != null)
            {
                float impLL = character.ShamanTalents.ImprovedLavaLash * 0.15f;
                float searingFlames = 0f;
                float flametongue = 0f;
                float glyphLL = 0f;
                if (calcOpts.PriorityInUse(EnhanceAbility.SearingTotem) && character.ShamanTalents.SearingFlames != 0)
                {
                    searingFlames = (character.ShamanTalents.ImprovedLavaLash * 0.1f + enhance2T12) * 5f; //5f = number of stacks of searing flames (takes app. 8.25s to hit 5 stacks, LL CD is 10s).
                }
                if (calcOpts.OffhandImbue == "Flametongue")
                {
                    flametongue = .4f;
                }
                if (character.ShamanTalents.GlyphofLavaLash)
                {
                    glyphLL = .2f;
                }
                float lavalashDPS = damageOHSwing * 2f * cs.HitsPerSLL;
                float LLnormal = lavalashDPS * cs.YellowHitModifierOH;
                float LLcrit = lavalashDPS * cs.YellowCritModifierOH * cs.CritMultiplierMelee;
                dpsLL = (LLnormal + LLcrit) * (1f + searingFlames + flametongue) * (1f + impLL + glyphLL + enhance2T11) * (1 + enhance4T12) * mastery * bonusFireDamage;
            }
            #endregion

            #region Earth Shock DPS
            float dpsES = 0f;
            if (calcOpts.PriorityInUse(EnhanceAbility.EarthShock))
            {
                float damageESBase = 931f;
                float coefES = .386f;
                float damageES = concussionMultiplier/*(1f + stats.ConcussionMultiplier)*/ * (damageESBase + coefES * spellPower);
                float shockdps = damageES / cs.AbilityCooldown(EnhanceAbility.EarthShock);
                float shockNormal = shockdps * cs.NatureSpellHitModifier;
                float shockCrit = shockdps * cs.NatureSpellCritModifier * cs.CritMultiplierSpell;
                dpsES = (shockNormal + shockCrit) * mastery * bonusNatureDamage;
            }
            #endregion

            #region Flame Shock DPS
            float dpsFS = 0f;
            if (calcOpts.PriorityInUse(EnhanceAbility.FlameShock))
            {
                float FSBaseNumTick = 18f / 3f;
                float damageFSBase = 531f;
                float damageFSDoTTickBase = 852f / FSBaseNumTick;
                float FSNumTick = cs.AverageFSDotTime / cs.AverageFSTickTime;
                float coefFS = 1.5f / 3.5f / 2f;
                float coefFSDoT = .6f;
                float damageFS = (damageFSBase + coefFS * spellPower) * /*(1f + stats.ConcussionMultiplier)*/concussionMultiplier;
                float damageFTDoT = ((damageFSDoTTickBase * FSNumTick) + coefFSDoT * spellPower) * /*(1f + stats.ConcussionMultiplier)*/concussionMultiplier;
                float usesCooldown = cs.AbilityCooldown(EnhanceAbility.FlameShock);
                float flameShockdps = damageFS / usesCooldown;
                float flameShockDoTdps = damageFTDoT / usesCooldown;
                float flameShockNormal = (flameShockdps + flameShockDoTdps) * cs.SpellHitModifier;
                float flameShockCrit = (flameShockdps + flameShockDoTdps) * cs.SpellCritModifier * cs.CritMultiplierSpell;
                dpsFS = (flameShockNormal + flameShockCrit) * (1 + enhance4T12) * mastery * bonusFireDamage;
            }
            #endregion

            #region Lightning Bolt DPS
            float dpsLB = 0f;
            if (calcOpts.PriorityInUse(EnhanceAbility.LightningBolt))
            {
                float damageLBBase = 770f;
                float coefLB = .714f;
                float damageLB = concussionMultiplier/*(1f + stats.ConcussionMultiplier)*/ * (damageLBBase + coefLB * spellPower);
                float lbdps = damageLB / cs.AbilityCooldown(EnhanceAbility.LightningBolt);
                float lbNormal = lbdps * cs.NatureSpellHitModifier;
                float lbCrit = lbdps * cs.NatureSpellCritModifier * cs.CritMultiplierSpell;
                dpsLB = (lbNormal + lbCrit) * mastery * bonusNatureDamage;
                if (character.ShamanTalents.GlyphofLightningBolt)
                    dpsLB *= 1.04f; // 4% bonus dmg if Lightning Bolt Glyph
            }
            #endregion

            #region Chain Lightning DPS
            float dpsCL = 0f;
            float coefCL = 0f;
            if (calcOpts.PriorityInUse(EnhanceAbility.ChainLightning))
            {
                if (character.ShamanTalents.GlyphofChainLightning)
                {
                    coefCL = 0.5714f * 0.9f;
                }
                else
                {
                    coefCL = 0.5714f;
                }
                float damageCLBase = 1092f;
                float damageCL = concussionMultiplier/*(1f + stats.ConcussionMultiplier)*/ * (damageCLBase + coefCL * spellPower);
                float cldps = (damageCL) / cs.AbilityCooldown(EnhanceAbility.ChainLightning);
                float clNormal = cldps * cs.NatureSpellHitModifier;
                float clCrit = cldps * cs.NatureSpellCritModifier * cs.CritMultiplierSpell;
                dpsCL = (clNormal + clCrit) * mastery * bonusNatureDamage;
            }
            #endregion

            #region Windfury DPS
            float dpsWF = 0f;
            if (calcOpts.MainhandImbue == "Windfury" && character.MainHand != null)
            {
                float damageWFHit = damageMHSwing + (windfuryWeaponBonus / 14 * cs.UnhastedMHSpeed);
                float WFdps = damageWFHit * cs.HitsPerSWF;
                float WFnormal = WFdps * cs.YellowHitModifierMH;
                float WFcrit = WFdps * cs.YellowCritModifierMH * cs.CritMultiplierMelee;
                dpsWF = (WFnormal + WFcrit) * cs.DamageReduction * bonusPhysicalDamage * /*(1f + stats.BonusWindfuryDamageMultiplier)*/windfuryDamageBonus;
            }
            #endregion

            #region Lightning Shield DPS
            float dpsLS = 0f;
            if (calcOpts.PriorityInUse(EnhanceAbility.LightningShield))
            {
                float damageLSBase = 391f;
                float damageLSCoef = 0.267f; // co-efficient from EnhSim
                float damageLS = shieldBonus/*stats.ShieldBonus*/ * (damageLSBase + damageLSCoef * spellPower);
                float lsdps = damageLS * cs.StaticShockProcsPerS;
                float lsNormal = lsdps * cs.NatureSpellHitModifier;
                float lsCrit = lsdps * cs.NatureSpellCritModifier * cs.CritMultiplierSpell;
                dpsLS = (lsNormal + lsCrit) * mastery * bonusNatureDamage;
            }
            #endregion

            #region Fire Totem DPS
            float dpsFireTotem = 0f;
            if (calcOpts.PriorityInUse(EnhanceAbility.MagmaTotem))
            {
                float damageFireTotem = (268f + .067f * spellPower) * /*stats.CallofFlameBonus*/callofFlameBonus;
                float FireTotemdps = damageFireTotem / 2f * cs.FireTotemUptime;
                float FireTotemNormal = FireTotemdps * cs.SpellHitModifier;
                float FireTotemCrit = FireTotemdps * cs.SpellCritModifier * cs.CritMultiplierSpell;
                dpsFireTotem = (FireTotemNormal + FireTotemCrit) * mastery * bonusFireDamage * cs.MultiTargetMultiplier;
            }
            else if (calcOpts.PriorityInUse(EnhanceAbility.SearingTotem))
            {
                float damageFireTotem = (96f + .1669f * spellPower) * /*stats.CallofFlameBonus*/callofFlameBonus;
                float FireTotemdps = damageFireTotem / 1.65f * cs.FireTotemUptime;
                float FireTotemNormal = FireTotemdps * cs.SpellHitModifier;
                float FireTotemCrit = FireTotemdps * cs.SpellCritModifier * cs.CritMultiplierSpell;
                dpsFireTotem = (FireTotemNormal + FireTotemCrit) * mastery * bonusFireDamage;
            }
            dpsFireTotem *= (1f - cs.FireElementalUptime);
            #endregion

            #region Fire Nova DPS
            float dpsFireNova = 0f;
            if (calcOpts.PriorityInUse(EnhanceAbility.FireNova) && calcOpts.PriorityInUse(EnhanceAbility.FlameShock))
            {
                float damageFireNova = (686.0f + 0.143f * spellPower) * /*stats.CallofFlameBonus*/callofFlameBonus;
                float FireNovadps = (damageFireNova / cs.AbilityCooldown(EnhanceAbility.FireNova));
                float FireNovaNormal = FireNovadps * cs.SpellHitModifier;
                float FireNovaCrit = FireNovadps * cs.SpellCritModifier * cs.CritMultiplierSpell;
                dpsFireNova = (FireNovaNormal + FireNovaCrit) * (1 + enhance4T12) * mastery * bonusFireDamage * cs.MultiTargetMultiplier;
            }
            #endregion

            #region Flametongue Weapon DPS
            float dpsFT = 0f;
            /*if (calcOpts.MainhandImbue == "Flametongue")
            {
                //float damageFTBase = 306f * cs.UnhastedOHSpeed / 4.0f;
                //float damageFTCoef = 0.15396f * cs.UnhastedOHSpeed;
                //float damageFT = damageFTBase + damageFTCoef * attackPower;
                float damageFTBase = 306f;
                float damageFTCoef = 0.1253f;
                float damageFT = (damageFTBase + (damageFTCoef * attackPower)) * cs.UnhastedOHSpeed / 4.0f;
                float FTdps = damageFT * (cs.HitsPerSOH - cs.HitsPerSLL);
                float FTNormal = FTdps * cs.SpellHitModifier;
                float FTCrit = FTdps * cs.SpellCritModifier * cs.CritMultiplierSpell;
                dpsFT += (FTNormal + FTCrit) * (1 + enhance4T12) * mastery * bonusFireDamage * bossFireResistance;
            }*/
            if (calcOpts.OffhandImbue == "Flametongue" && character.OffHand != null)
            {
                //float damageFTBase = 306f * cs.UnhastedOHSpeed / 4.0f;
                //float damageFTCoef = 0.1253f * cs.UnhastedOHSpeed;
                //float damageFT = damageFTBase + damageFTCoef * attackPower;
                float damageFTBase = 306f;
                float damageFTCoef = 0.1253f;
                float damageFT = (damageFTBase + (damageFTCoef * attackPower)) * cs.UnhastedOHSpeed / 4.0f;
                float FTdps = damageFT * (cs.HitsPerSOH - cs.HitsPerSLL);
                float FTNormal = FTdps * cs.SpellHitModifier;
                float FTCrit = FTdps * cs.SpellCritModifier * cs.CritMultiplierSpell;
                dpsFT += (FTNormal + FTCrit) * (1 + enhance4T12) * mastery * bonusFireDamage;
            }
            #endregion

            #region Unleash Elements DPS
            #region Unleash Windfury
            float dpsUW = 0f;
            if (calcOpts.PriorityInUse(EnhanceAbility.UnleashElements) && calcOpts.MainhandImbue == "Windfury" && character.MainHand != null)
            {
                float damageUWHit = damageMHSwing * 1.75f;
                float UWdps = damageUWHit / cs.AbilityCooldown(EnhanceAbility.UnleashElements);
                float UWnormal = UWdps * cs.YellowCritModifierMH;
                float UWcrit = UWdps * cs.YellowCritModifierMH * cs.CritMultiplierMelee;
                dpsUW = (UWnormal + UWcrit) * cs.DamageReduction * bonusPhysicalDamage;
            }
            #endregion
            #region Unleash Flametongue
            float dpsUF = 0f;
            if (calcOpts.PriorityInUse(EnhanceAbility.UnleashElements) && calcOpts.OffhandImbue == "Flametongue" && character.OffHand != null)
            {
                float damageUFBase = 1070f;
                float damageUFCoef = 0.43f;
                float damageUF = damageUFBase + damageUFCoef * spellPower;
                float UFdps = damageUF / cs.AbilityCooldown(EnhanceAbility.UnleashElements);
                float UFnormal = UFdps * cs.SpellHitModifier;
                float UFcrit = UFdps * cs.SpellCritModifier * cs.CritMultiplierSpell;
                dpsUF = (UFnormal + UFcrit) * (1 + enhance4T12) * mastery * bonusFireDamage;
            }
            #endregion
            #endregion

            #region Other (Damage Procs)

            #endregion

            #region Pet calculations
            // needed for pets - spirit wolves and Fire Elemental
            bool critDebuff = character.ActiveBuffsContains("Heart of the Crusader") ||
                              character.ActiveBuffsContains("Master Poisioner") ||
                              character.ActiveBuffsContains("Totem of Wrath");
            bool critBuff = character.ActiveBuffsContains("Leader of the Pack") ||
                            character.ActiveBuffsContains("Rampage");
            float critbuffs = (critDebuff ? 0.03f : 0f) + (critBuff ? 0.05f : 0f);
            float meleeHitBonus = stats.PhysicalHit + StatConversion.GetHitFromRating(stats.HitRating) + dualWieldSpecialization;
            float petMeleeMissRate = Math.Max(0f, StatConversion.WHITE_MISS_CHANCE_CAP[bossOpts.Level - character.Level] - meleeHitBonus) + cs.AverageDodge;
            float petMeleeMultipliers = cs.DamageReduction * bonusPhysicalDamage;
            #endregion

            #region Doggies!
            // TTT article suggests 300-450 dps while the dogs are up plus 30% of AP
            // my analysis reveals they get 31% of shaman AP + 2 * their STR and base 206.17 dps.
            float dpsDogs = 0f;
            if (character.ShamanTalents.FeralSpirit == 1 && calcOpts.PriorityInUse(EnhanceAbility.FeralSpirits))
            {
                float FSglyphAP = character.ShamanTalents.GlyphofFeralSpirit ? attackPower * .3f : 0f;
                float soeBuff = (character.ActiveBuffsContains("Strength of Earth Totem") || character.ActiveBuffsContains("Horn of Winter") || character.ActiveBuffsContains("Roar of Courage") ||
                    character.ActiveBuffsContains("Battle Shout")) ? 594f : 0f;
                float dogsStr = 331f + soeBuff;
                float dogsAgi = 113f + soeBuff;
                float dogsAP = ((dogsStr * 2f - 20f) + .31f * attackPower + FSglyphAP) * (1f + unleashedRage);
                float dogsCrit = (StatConversion.GetCritFromAgility(dogsAgi, CharacterClass.Shaman) + critbuffs) * (1 + stats.BonusCritDamageMultiplier);
                float dogsBaseSpeed = 1.5f;
                float dogsHitsPerS = 1f / (dogsBaseSpeed / (1f + stats.PhysicalHaste));
                float dogsBaseDamage = (490.06f + dogsAP / 14f) * dogsBaseSpeed;

                float dogsMeleeNormal = dogsBaseDamage * (1 - petMeleeMissRate - dogsCrit - cs.GlancingRate);
                float dogsMeleeCrits = dogsBaseDamage * dogsCrit * cs.CritMultiplierMelee;
                float dogsMeleeGlances = dogsBaseDamage * cs.GlancingHitModifier;

                float dogsTotalDamage = dogsMeleeNormal + dogsMeleeCrits + dogsMeleeGlances;

                dpsDogs = 2 * (30f / 120f) * dogsTotalDamage * dogsHitsPerS * petMeleeMultipliers;
                calc.SpiritWolf = new DPSAnalysis(dpsDogs, petMeleeMissRate, cs.AverageDodge, cs.GlancingRate, dogsCrit, 60f / cs.AbilityCooldown(EnhanceAbility.FeralSpirits));
            }
            else
            {
                calc.SpiritWolf = new DPSAnalysis(0, 0, 0, 0, 0, 0);
            }
            #endregion

            #region Fire Elemental
            if (calcOpts.PriorityInUse(EnhanceAbility.FireElemental))
            {
                float spellHitBonus = stats.SpellHit + StatConversion.GetHitFromRating(stats.HitRating);
                float petSpellMissRate = Math.Max(0f, StatConversion.WHITE_MISS_CHANCE_CAP[bossOpts.Level - character.Level] - spellHitBonus);
                float petSpellMultipliers = bonusFireDamage * /*stats.CallofFlameBonus*/callofFlameBonus;
                float petCritRate = critbuffs * (1 + stats.BonusCritDamageMultiplier);
                calc.FireElemental = new FireElemental(attackPower, spellPower, stats.Intellect, cs, 
                        petCritRate, petMeleeMissRate, petMeleeMultipliers, petSpellMissRate, petSpellMultipliers);
            }
            else
                calc.FireElemental = new FireElemental(0, 0, 0, cs, 0, 0, 0, 0, 0);
            float dpsFireElemental = calc.FireElemental.getDPS();
            #endregion
            #endregion

            #region Set CalculatedStats
            calc.DPS = dpsMelee + dpsSS + dpsLL + dpsES + dpsFS + dpsLB + dpsCL + dpsWF + dpsLS + dpsFireTotem + dpsFireNova + dpsFT + dpsDogs + dpsFireElemental;
            calc.Survivability = stats.Health * 0.02f;
            calc.OverallPoints = calc.DPS + calc.Survivability;
            calc.DodgedAttacks = cs.AverageDodge * 100f;
            calc.ParriedAttacks = cs.AverageParry * 100f;
            calc.MissedAttacks = (1 - cs.AverageWhiteHitChance) * 100f;
            calc.AvoidedAttacks = calc.MissedAttacks + calc.DodgedAttacks + calc.ParriedAttacks;
            calc.YellowHit = (float)Math.Floor((float)(cs.AverageYellowHitChance * 10000f)) / 100f;
            calc.SpellHit = (float)Math.Floor((float)(cs.ChanceSpellHit * 10000f)) / 100f;
            calc.ElemPrecMod = cs.ElemPrecMod;
            calc.DraeneiHitBonus = character.Race == CharacterRace.Draenei ? 0.01f : 0.00f;
            calc.OverSpellHitCap = (float)Math.Floor((float)(cs.OverSpellHitCap * 10000f)) / 100f;
            calc.OverMeleeCritCap = (float)Math.Floor((float)(cs.OverMeleeCritCap * 10000f)) / 100f;
            calc.WhiteHit = (float)Math.Floor((float)(cs.AverageWhiteHitChance * 10000f)) / 100f;
            calc.MeleeCrit = (float)Math.Floor((float)((cs.DisplayMeleeCrit)) * 10000f) / 100f;
            calc.YellowCrit = (float)Math.Floor((float)((cs.DisplayYellowCrit)) * 10000f) / 100f;
            calc.SpellCrit = (float)Math.Floor((float)(cs.ChanceSpellCrit * 10000f)) / 100f;
            calc.GlancingBlows = cs.GlancingRate * 100f;
            calc.ArmorMitigation = (1f - cs.DamageReduction) * 100f;
            calc.MasteryRating = stats.MasteryRating;  //CATA FIXME!!
            calc.AttackPower = attackPower;
            calc.SpellPower = spellPower;
            calc.AvMHSpeed = cs.HastedMHSpeed;
            calc.AvOHSpeed = cs.HastedOHSpeed;
            calc.EDBonusCrit = cs.EDBonusCrit * 100f;
            calc.EDUptime = cs.EDUptime * 100f;
            calc.FlurryUptime = cs.FlurryUptime * 100f;
            calc.SecondsTo5Stack = cs.SecondsToFiveStack;
            calc.MHEnchantUptime = se.GetMHUptime() * 100f;
            calc.OHEnchantUptime = se.GetOHUptime() * 100f;
            calc.Trinket1Uptime = se.GetUptime(character.Trinket1) * 100f;
            calc.Trinket2Uptime = se.GetUptime(character.Trinket2) * 100f;
            calc.FireTotemUptime = cs.FireTotemUptime * 100f;
            calc.BaseRegen = cs.BaseRegen;
            calc.ManaRegen = cs.ManaRegen;

            calc.TotalExpertiseMH = (float) Math.Floor(cs.ExpertiseBonusMH * 400f);
            calc.TotalExpertiseOH = (float) Math.Floor(cs.ExpertiseBonusOH * 400f);

            calc.SwingDamage = new DPSAnalysis(dpsMelee, 1 - cs.AverageWhiteHitChance, cs.AverageDodge, cs.GlancingRate, cs.AverageWhiteCritChance, cs.MeleePPM);
            calc.Stormstrike = new DPSAnalysis(dpsSS, 1 - cs.AverageYellowHitChance, cs.AverageDodge, -1, cs.AverageYellowCritChance, 60f / cs.AbilityCooldown(EnhanceAbility.StormStrike));
            calc.LavaLash = new DPSAnalysis(dpsLL, 1 - cs.ChanceYellowHitOH, cs.ChanceDodgeOH, -1, cs.ChanceYellowCritOH, 60f / cs.AbilityCooldown(EnhanceAbility.LavaLash));
            calc.EarthShock = new DPSAnalysis(dpsES, 1 - cs.ChanceSpellHit, -1, -1, cs.ChanceNatureSpellCrit, 60f / cs.AbilityCooldown(EnhanceAbility.EarthShock));
            calc.FlameShock = new DPSAnalysis(dpsFS, 1 - cs.ChanceSpellHit, -1, -1, cs.ChanceSpellCrit, 60f / cs.AbilityCooldown(EnhanceAbility.FlameShock));
            calc.LightningBolt = new DPSAnalysis(dpsLB, 1 - cs.ChanceSpellHit, -1, -1, cs.ChanceLBSpellCrit/*cs.ChanceNatureSpellCrit*/, 60f / cs.AbilityCooldown(EnhanceAbility.LightningBolt));
            calc.WindfuryAttack = new DPSAnalysis(dpsWF, 1 - cs.ChanceYellowHitMH, cs.ChanceDodgeMH, -1, cs.ChanceYellowCritMH, cs.WFPPM);
            calc.LightningShield = new DPSAnalysis(dpsLS, 1 - cs.ChanceSpellHit, -1, -1, cs.ChanceNatureSpellCrit, 60f / cs.AbilityCooldown(EnhanceAbility.LightningShield));
            calc.ChainLightning = new DPSAnalysis(dpsCL, 1 - cs.ChanceSpellHit, -1, -1, cs.ChanceNatureSpellCrit, 60f / cs.AbilityCooldown(EnhanceAbility.ChainLightning));
            calc.SearingMagma = new DPSAnalysis(dpsFireTotem, 1 - cs.ChanceSpellHit, -1, -1, cs.ChanceSpellCrit,
                calcOpts.Magma ? 60f / cs.AbilityCooldown(EnhanceAbility.MagmaTotem) : 60f / cs.AbilityCooldown(EnhanceAbility.SearingTotem));
            calc.FlameTongueAttack = new DPSAnalysis(dpsFT, 1 - cs.ChanceSpellHit, -1, -1, cs.ChanceSpellCrit, cs.FTPPM);
            calc.FireNova = new DPSAnalysis(dpsFireNova, 1 - cs.ChanceSpellHit, -1, -1, cs.ChanceSpellCrit, 60f / cs.AbilityCooldown(EnhanceAbility.FireNova));
            calc.UnleashWind = new DPSAnalysis(dpsUW, 1 - cs.ChanceYellowHitMH, cs.ChanceDodgeMH, -1, cs.ChanceYellowCritMH, 60f / cs.AbilityCooldown(EnhanceAbility.UnleashElements));
            calc.UnleashFlame = new DPSAnalysis(dpsUF, 1 - cs.ChanceSpellHit, -1, -1, cs.ChanceSpellCrit, 60f / cs.AbilityCooldown(EnhanceAbility.UnleashElements));
            calc.Other = new DPSAnalysis(0f, 1 - cs.ChanceSpellHit, -1, -1, cs.ChanceSpellCrit, 0f);
            #endregion
            return calc;
        }
コード例 #2
0
        private void SetTriggerChanceAndSpeed(SpecialEffect effect)
        {
            trigger             = 0f;
            chance              = 1f;
            unhastedAttackSpeed = 3f;
            switch (effect.Trigger)
            {
            case Trigger.DamageDone:
                trigger             = (_cs.HastedMHSpeed + 1f / _cs.GetSpellAttacksPerSec()) / 2f;
                chance              = (float)Math.Min(1.0f, _cs.AverageWhiteHitChance + _cs.ChanceSpellHit); // limit to 100% chance
                unhastedAttackSpeed = _cs.UnhastedMHSpeed;
                break;

            case Trigger.DamageOrHealingDone:
                // Need to add Self Heals
                trigger             = (_cs.HastedMHSpeed + 1f / _cs.GetSpellAttacksPerSec()) / 2f;
                chance              = (float)Math.Min(1.0f, _cs.AverageWhiteHitChance + _cs.ChanceSpellHit); // limit to 100% chance
                unhastedAttackSpeed = _cs.UnhastedMHSpeed;
                break;

            case Trigger.MeleeCrit:
            case Trigger.PhysicalCrit:
                trigger             = _cs.HastedMHSpeed;
                chance              = _cs.AverageWhiteCritChance;
                unhastedAttackSpeed = _cs.UnhastedMHSpeed;
                break;

            case Trigger.MeleeHit:
            case Trigger.PhysicalHit:
                trigger             = _cs.HastedMHSpeed;
                chance              = _cs.AverageWhiteHitChance;
                unhastedAttackSpeed = _cs.UnhastedMHSpeed;
                break;

            case Trigger.MeleeAttack:
                if (_character.ShamanTalents.DualWield == 1)
                {
                    trigger             = (_cs.HastedMHSpeed + _cs.HastedOHSpeed) / 2;
                    chance              = 1f;
                    unhastedAttackSpeed = (_cs.UnhastedMHSpeed + _cs.UnhastedOHSpeed) / 2;
                }
                else
                {
                    trigger             = _cs.HastedMHSpeed;
                    chance              = 1f;
                    unhastedAttackSpeed = _cs.UnhastedMHSpeed;
                }
                break;

            case Trigger.DamageSpellCast:
            case Trigger.SpellCast:
                trigger = 1f / _cs.GetSpellCastsPerSec();
                chance  = 1f;
                break;

            case Trigger.DamageSpellHit:
            case Trigger.SpellHit:
                trigger = 1f / _cs.GetSpellAttacksPerSec();
                chance  = _cs.ChanceSpellHit;
                break;

            case Trigger.DamageSpellCrit:
            case Trigger.SpellCrit:
                trigger = 1f / _cs.GetSpellCritsPerSec();
                chance  = _cs.ChanceSpellCrit;
                break;

            case Trigger.SpellMiss:
                trigger = 1f / _cs.GetSpellMissesPerSec();
                chance  = 1 - _cs.ChanceSpellHit;
                break;

            case Trigger.ShamanLightningBolt:
                trigger = 1f / _cs.AbilityCooldown(EnhanceAbility.LightningBolt);
                chance  = _cs.ChanceSpellHit;
                break;

            case Trigger.ShamanStormStrike:
                trigger = 1f / _cs.AbilityCooldown(EnhanceAbility.StormStrike);
                chance  = _cs.ChanceYellowHitMH;
                break;

            case Trigger.ShamanShock:
                trigger = 1f / _cs.AbilityCooldown(EnhanceAbility.EarthShock);
                chance  = _cs.ChanceSpellHit;
                break;

            case Trigger.ShamanLavaLash:
                trigger             = 1f / _cs.AbilityCooldown(EnhanceAbility.LavaLash);
                chance              = _cs.ChanceYellowHitOH;
                unhastedAttackSpeed = _cs.UnhastedOHSpeed;
                break;

            case Trigger.ShamanShamanisticRage:
                trigger = 1f / _cs.AbilityCooldown(EnhanceAbility.ShamanisticRage);
                chance  = 1f;
                break;

            case Trigger.ShamanFlameShockDoTTick:
            case Trigger.DoTTick:
                trigger = 1f / _cs.AbilityCooldown(EnhanceAbility.FlameShock);
                chance  = 1f;
                break;
            }
        }