Example #1
0
        private void SetCvalues()
        {
            CMHItemType  = MH.Type;
            CMHItemSpeed = MH.Speed;
            if (OH != null)
            {
                COHItemType  = OH.Type;
                COHItemSpeed = OH.Speed;
            }
            useMH = _useMH; // public variable gets set once
            useOH = _useOH;

            CMHRacialExpertise = BaseStats.GetRacialExpertise(Char, ItemSlot.MainHand); //GetRacialExpertiseFromWeaponType(CmhItemType);
            CMHexpertise       = StatS.Expertise + StatConversion.GetExpertiseFromRating(Math.Max(0, StatS.ExpertiseRating)) + CMHRacialExpertise;
            CYmiss             = YwMissChance;
            CWmiss             = WhMissChance;
            CMHdodge           = MhDodgeChance;
            CMHparry           = MhParryChance;
            CMHblock           = MhBlockChance;
            CMHwcrit           = MhWhCritChance;
            CMHycrit           = MhYwCritChance;
            CGlance            = GlanceChance;
            if (useOH)
            {
                COHRacialExpertise = BaseStats.GetRacialExpertise(Char, ItemSlot.OffHand);// GetRacialExpertiseFromWeaponType(CohItemType);
                COhexpertise       = StatS.Expertise + StatConversion.GetExpertiseFromRating(Math.Max(0, StatS.ExpertiseRating)) + COHRacialExpertise;
                COhdodge           = OhDodgeChance;
                COhparry           = OhParryChance;
                COhblock           = OhBlockChance;
                COhwcrit           = OhWhCritChance;
                COhycrit           = OhYwCritChance;
            }
            else
            {
                COHItemType        = ItemType.None;
                COHItemSpeed       = 0f;
                COHRacialExpertise = 0f;
                COhexpertise       = 0f;
                COhdodge           = StatConversion.WHITE_DODGE_CHANCE_CAP[LevelDif];
                COhparry           = StatConversion.WHITE_PARRY_CHANCE_CAP[LevelDif];
                COhblock           = 0.0f;
                COhwcrit           = 0.0f;
                COhycrit           = 0.0f;
            }
        }
Example #2
0
        public void UpdateCalcs(bool firstPass)
        {
            // talents
            if (_calcOpts.PriorityInUse(EnhanceAbility.StormStrike))
            {
                stormstrikeBonusCrit = .25f * _talents.Stormstrike + (_talents.GlyphofStormstrike ? .1f : 0f);
            }
            else
            {
                stormstrikeBonusCrit = 0f;
            }
            //set bonus
            enhance4T11 = 0f;
            _character.SetBonusCount.TryGetValue("Battlegear of the Raging Elements", out setCount);
            if (setCount >= 4)
            {
                enhance4T11 = 0.1f;
            }

            critMultiplierSpell = 1.5f * (1 + _stats.BonusSpellCritDamageMultiplier);
            critMultiplierMelee = 2f * (1 + _stats.BonusCritDamageMultiplier);

            // Melee
            float hitBonus = _stats.PhysicalHit + StatConversion.GetHitFromRating(_stats.HitRating) + 0.06f;  //DualWieldSpecialization

            expertiseBonusMH = GetDPRfromExp(_stats.Expertise + StatConversion.GetExpertiseFromRating(_stats.ExpertiseRating) + BaseStats.GetRacialExpertise(_character, ItemSlot.MainHand));
            expertiseBonusOH = GetDPRfromExp(_stats.Expertise + StatConversion.GetExpertiseFromRating(_stats.ExpertiseRating) + BaseStats.GetRacialExpertise(_character, ItemSlot.OffHand));

            float meleeCritModifier = _stats.PhysicalCrit;
            float baseMeleeCrit     = StatConversion.GetCritFromRating(_stats.CritRating) +
                                      StatConversion.GetCritFromAgility(_stats.Agility, _character.Class) + .01f * _talents.Acuity;

            chanceDodgeMH = Math.Max(0f, DodgeChanceCap - expertiseBonusMH);
            chanceDodgeOH = Math.Max(0f, DodgeChanceCap - expertiseBonusOH);
            float ParryChance = ParryChanceCap - expertiseBonusMH;

            //chanceParryMH = (float)Math.Max(0f, _bossOpts.InBack ? ParryChance * PecentageInfrontBoss : ParryChance);
            ParryChance = ParryChanceCap - expertiseBonusOH;
            //chanceParryOH = (float)Math.Max(0f, _bossOpts.InBack ? ParryChance * PecentageInfrontBoss : ParryChance);
            chanceWhiteMissMH  = Math.Max(0f, WhiteHitCap - hitBonus) + chanceDodgeMH + chanceParryMH;
            chanceWhiteMissOH  = Math.Max(0f, WhiteHitCap - hitBonus) + chanceDodgeOH + chanceParryOH;
            chanceYellowMissMH = Math.Max(0f, YellowHitCap - hitBonus) + chanceDodgeMH + chanceParryMH; // base miss 8% now
            chanceYellowMissOH = Math.Max(0f, YellowHitCap - hitBonus) + chanceDodgeOH + chanceParryOH; // base miss 8% now

            // SetCritValues((1 + _stats.BonusCritChance) * (baseMeleeCrit + meleeCritModifier) + .00005f); //fudge factor for rounding
            SetCritValues(baseMeleeCrit + meleeCritModifier + .00005f); //fudge factor for rounding
            // set two export values so that ED crit isn't included
            exportMeleeCritMH = chanceWhiteCritMH + whiteCritDepression;
            exportMeleeCritOH = chanceWhiteCritOH + whiteCritDepression;

            // Spells
            ftBonusCrit = 0f;
            if (_calcOpts.MainhandImbue == "Flametongue")
            {
                ftBonusCrit += _talents.GlyphofFlametongueWeapon ? .02f : 0f;
            }
            if (_calcOpts.OffhandImbue == "Flametongue")
            {
                ftBonusCrit += _talents.GlyphofFlametongueWeapon ? .02f : 0f;
            }

            if (baseStats == null)
            {
                baseStats = BaseStats.GetBaseStats(_character);
            }

            elemPrecMod = _talents.ElementalPrecision > 0 ? (_stats.Spirit - baseStats.Spirit) * (_talents.ElementalPrecision / 3f) : 0f;
            float hitBonusSpell = _stats.SpellHit + StatConversion.GetSpellHitFromRating(_stats.HitRating + elemPrecMod);

            chanceSpellMiss = Math.Max(0f, SpellMissRate - hitBonusSpell);
            overSpellHitCap = Math.Max(0f, hitBonusSpell - SpellMissRate);
            float spellCritModifier = _stats.SpellCrit + _stats.SpellCritOnTarget + ftBonusCrit;
            float baseSpellCrit     = StatConversion.GetSpellCritFromRating(_stats.CritRating) +
                                      StatConversion.GetSpellCritFromIntellect(_stats.Intellect) + .01f * _talents.Acuity;

            //chanceSpellCrit = Math.Min(0.75f, (1 + _stats.BonusCritChance) * (baseSpellCrit + spellCritModifier) + .00005f); //fudge factor for rounding
            chanceSpellCrit = Math.Min(0.75f, baseSpellCrit + spellCritModifier + .00005f); //fudge factor for rounding

            float hasteBonus = StatConversion.GetHasteFromRating(_stats.HasteRating, _character.Class);

            unhastedMHSpeed = _character.MainHand == null ? 3.0f : _character.MainHand.Item.Speed;
            unhastedOHSpeed = _character.OffHand == null ? 3.0f : _character.OffHand.Item.Speed;
            float baseHastedMHSpeed    = unhastedMHSpeed / (1f + hasteBonus) / (1f + _stats.PhysicalHaste);
            float baseHastedOHSpeed    = unhastedOHSpeed / (1f + hasteBonus) / (1f + _stats.PhysicalHaste);
            float chanceToProcWFPerHit = .2f + (_character.ShamanTalents.GlyphofWindfuryWeapon ? .02f : 0f);

            if (_bossOpts.MultiTargs && _bossOpts.Targets != null && _bossOpts.Targets.Count > 0)
            {
                foreach (TargetGroup tg in _bossOpts.Targets)
                {
                    if (tg.Frequency <= 0 || tg.Chance <= 0)
                    {
                        continue; //bad one, skip it
                    }
                    float upTime = (tg.Frequency / fightLength * (tg.Duration / 1000f) * tg.Chance) / fightLength;
                    multiTargetMultiplier += (Math.Max(10, tg.NumTargs - (tg.NearBoss ? 0 : 1))) * upTime;
                }
            }

            //The Swing Loop
            //This is where we figure out feedback systems -- WF, MW, ED, Flurry, etc.
            //--------------
            flurryUptime = 1f;
            uWUptime     = 0f;
            //uFUptime = 0f;
            edUptime = 0f;
            float stormstrikeSpeed = firstPass ? (_talents.Stormstrike == 1 ? 8f : 0f) : AbilityCooldown(EnhanceAbility.StormStrike);
            float shockSpeed       = firstPass ? BaseShockSpeed : AbilityCooldown(EnhanceAbility.EarthShock);
            float lavaLashSpeed    = firstPass ? 10f : AbilityCooldown(EnhanceAbility.LavaLash);
            float fireNovaSpeed    = firstPass ? BaseFireNovaSpeed : AbilityCooldown(EnhanceAbility.FireNova);

            if (_calcOpts.PriorityInUse(EnhanceAbility.MagmaTotem))
            {
                fireTotemUptime = firstPass ? 1.0f : 60f / AbilityCooldown(EnhanceAbility.MagmaTotem);
            }
            else if (_calcOpts.PriorityInUse(EnhanceAbility.SearingTotem))
            {
                fireTotemUptime = firstPass ? 1.0f : 60f / AbilityCooldown(EnhanceAbility.SearingTotem);
            }
            else if (_calcOpts.PriorityInUse(EnhanceAbility.RefreshTotems)) // if no Searing or Magma totem use refresh of Flametongue totem.
            {
                fireTotemUptime = firstPass ? 1.0f : 300f / AbilityCooldown(EnhanceAbility.RefreshTotems);
            }

            float mwPPM             = (10f / 3f) * _talents.MaelstromWeapon;
            float flurryHasteBonus  = .10f * _talents.Flurry;
            float uWHasteBonus      = .4f + .1f * _talents.ElementalWeapons;
            float edCritBonus       = .03f * _talents.ElementalDevastation;
            float staticShockChance = .15f * _character.ShamanTalents.StaticShock;

            hitsPerSMHSS = 0f;
            hitsPerSOHSS = 0f;
            hitsPerSOH   = 0f;
            hitsPerSMH   = 0f;
            hitsPerSWF   = 0f;
            if (_talents.Stormstrike == 1)
            {
                hitsPerSMHSS = (1f - chanceYellowMissMH) / stormstrikeSpeed;
                hitsPerSOHSS = (1f - 2 * chanceYellowMissOH) / stormstrikeSpeed; //OH only swings if MH connect
            }
            hitsPerSLL = lavaLashSpeed == 0 ? 0f : (1f - chanceYellowMissOH) / lavaLashSpeed;
            float swingsPerSMHMelee = 0f;
            float swingsPerSOHMelee = 0f;
            float wfProcsPerSecond  = 0f;
            float mwProcsPerSecond  = 0f;

            secondsToFiveStack = 10f;
            float averageMeleeCritChance   = (chanceWhiteCritMH + chanceWhiteCritOH + chanceYellowCritMH + chanceYellowCritOH) / 4f;
            float averageMeleeHitChance    = ((1f - chanceWhiteMissMH - chanceDodgeMH - chanceParryMH) + (1f - chanceWhiteMissOH - chanceDodgeOH - chanceParryOH)) / 2f;
            float averageMeleeMissChance   = (chanceWhiteMissMH + chanceWhiteMissOH) / 2f;
            float whiteHitsPerSMH          = 0f;
            float whiteHitsPerSOH          = 0f;
            float moteHitsPerS             = 0f;
            float yellowHitsPerSMH         = 0f;
            float yellowHitsPerSOH         = 0f;
            float flameTongueHitsPerSecond = 0f;

            for (int i = 0; i < 5; i++)
            {
                // float bonusHaste = (1f + (flurryUptime * flurryHasteBonus));
                float bonusHaste = 1 / (1 - flurryUptime + flurryUptime / (1 + flurryHasteBonus)) / (1 - uWUptime + uWUptime / (1 + uWHasteBonus)); // use time based not proc based flurryUptime
                hastedMHSpeed     = baseHastedMHSpeed / bonusHaste;
                hastedOHSpeed     = baseHastedOHSpeed / bonusHaste;
                swingsPerSMHMelee = 1f / hastedMHSpeed;
                swingsPerSOHMelee = (hastedOHSpeed == 0f) ? 0f : 1f / hastedOHSpeed;
                whiteHitsPerSMH   = ChanceWhiteHitMH * swingsPerSMHMelee;
                whiteHitsPerSOH   = ChanceWhiteHitOH * swingsPerSOHMelee;
                moteHitsPerS      = _stats.MoteOfAnger * 2 * AverageWhiteHitChance;
                // Windfury model
                if (_calcOpts.MainhandImbue == "Windfury")
                {
                    float hitsThatProcWFPerS = whiteHitsPerSMH + hitsPerSMHSS;
                    if (unhastedOHSpeed != 0f)
                    {
                        hitsThatProcWFPerS += moteHitsPerS / 2; // half the hits will be OH and thus won't proc WF
                    }
                    else
                    {
                        hitsThatProcWFPerS += moteHitsPerS; // if no offhand then all motes will be MH weapon by definition
                    }
                    float maxExpectedWFPerFight = hitsThatProcWFPerS * chanceToProcWFPerHit * fightLength;
                    float ineligibleSeconds     = maxExpectedWFPerFight * (3.25f - hastedMHSpeed);
                    float expectedWFPerFight    = hitsThatProcWFPerS * chanceToProcWFPerHit * (fightLength - ineligibleSeconds);
                    wfProcsPerSecond = expectedWFPerFight / fightLength;
                    hitsPerSWF       = 3f * wfProcsPerSecond * (1f - chanceYellowMissMH);
                }
                yellowHitsPerSMH = hitsPerSWF + hitsPerSMHSS;
                yellowHitsPerSOH = hitsPerSOHSS + hitsPerSLL;

                //Due to attack table, a white swing has the same chance to crit as a yellow hit
// Old Flurry calc changed 10 Nov 2009
//                couldCritSwingsPerSecond = whiteHitsPerSMH + whiteHitsPerSOH + yellowHitsPerSMH + yellowHitsPerSOH;
//                float swingsThatConsumeFlurryPerSecond = swingsPerSMHMelee + swingsPerSOHMelee;
//                flurryUptime = 1f - (float)Math.Pow(1 - averageMeleeCritChance, (3 / swingsThatConsumeFlurryPerSecond) * couldCritSwingsPerSecond);  // old formulae
                flurryUptime = CalculateFlurryUptime(averageMeleeCritChance, averageMeleeHitChance, averageMeleeMissChance);
                //uWUptime = (float)Math.Max(12f / 15f, ??);  //FIXME!!!!
                uWUptime = 7.5f / 15f;  //Temp Uptime until above line is fixed

                // Maelstrom Weapon time to 5 stacks calc
                if (unhastedOHSpeed != 0f)
                {
                    hitsPerSMH       = whiteHitsPerSMH + yellowHitsPerSMH + moteHitsPerS / 2;
                    hitsPerSOH       = whiteHitsPerSOH + yellowHitsPerSOH + moteHitsPerS / 2;
                    mwProcsPerSecond = (mwPPM / (60f / unhastedMHSpeed)) * hitsPerSMH + (mwPPM / (60f / unhastedOHSpeed)) * hitsPerSOH;
                }
                else
                {
                    hitsPerSMH       = whiteHitsPerSMH + yellowHitsPerSMH + moteHitsPerS;
                    hitsPerSOH       = 0f;
                    mwProcsPerSecond = (mwPPM / (60f / unhastedMHSpeed)) * hitsPerSMH;
                }
                secondsToFiveStack = 5f / mwProcsPerSecond;

                // Elemental Devastation Uptime calc
                staticShocksPerSecond    = (hitsPerSLL + hitsPerSMHSS + hitsPerSOHSS) * staticShockChance;
                flameTongueHitsPerSecond = (_calcOpts.MainhandImbue == "Flametongue" ? HitsPerSMH : 0f) +
                                           ((_calcOpts.OffhandImbue == "Flametongue") ? HitsPerSOH : 0f);
                spellAttacksPerSec = (1f / secondsToFiveStack + 1f / shockSpeed + 1f / fireNovaSpeed + staticShocksPerSecond) // + flameTongueHitsPerSecond)
                                     * (1f - chanceSpellMiss);
                float couldCritSpellsPerS = spellAttacksPerSec;
                edUptime = 1f - (float)Math.Pow(1 - chanceSpellCrit, 10 * couldCritSpellsPerS);
                averageMeleeCritChance = (chanceWhiteCritMH + chanceWhiteCritOH + chanceYellowCritMH + chanceYellowCritOH) / 4f + edUptime * edCritBonus;
            }
            float yellowAttacksPerSecond = hitsPerSWF + hitsPerSMHSS;

            if (unhastedMHSpeed != 0)
            {
                yellowAttacksPerSecond += hitsPerSOHSS;
            }

            // set output variables
            edBonusCrit = edUptime * edCritBonus;
            //SetCritValues((1 + _stats.BonusCritChance) * (baseMeleeCrit + meleeCritModifier) + edBonusCrit + .00005f); //fudge factor for rounding
            SetCritValues(baseMeleeCrit + meleeCritModifier + edBonusCrit + .00005f); //fudge factor for rounding
            meleeAttacksPerSec = hitsPerSMH + hitsPerSOH;
            meleeCritsPerSec   = (whiteHitsPerSMH * chanceWhiteCritMH) + (whiteHitsPerSOH * chanceWhiteCritOH) +
                                 (yellowHitsPerSMH * chanceYellowCritMH) + (yellowHitsPerSOH * chanceYellowCritOH) +
                                 (_stats.MoteOfAnger * 2 * AverageWhiteCritChance);
            spellCritsPerSec  = spellAttacksPerSec * ChanceSpellCrit;
            spellCastsPerSec  = spellAttacksPerSec;
            spellMissesPerSec = spellAttacksPerSec * chanceSpellMiss;
            chanceMeleeHit    = meleeAttacksPerSec / (swingsPerSMHMelee + swingsPerSOHMelee + 2f * wfProcsPerSecond + .25f + 1f / 6f);
            maxMana           = _stats.Mana;
            float spellhaste = _stats.SpellHaste + StatConversion.GetSpellHasteFromRating(_stats.HasteRating);

            averageFSDotTime  = _talents.GlyphofFlameShock ? 27f : 18f;
            averageFSTickTime = 3f / (1f + spellhaste);
        }