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; }
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; } }