private void comboBoxBoss_SelectedIndexChanged(object sender, EventArgs e) { if (!_loadingCalculationOptions) { _loadingCalculationOptions = true; CalculationsEnhance calcs = new CalculationsEnhance(); BossHandler boss = bosslist.GetBossFromBetterName(comboBoxBoss.Text); _calcOpts.SetBoss(boss); CB_TargLvl.Text = _calcOpts.TargetLevel.ToString(); CB_TargArmor.Text = _calcOpts.TargetArmor.ToString(); cmbLength.Value = (int)_calcOpts.FightLength; CK_InBack.Checked = _calcOpts.InBack; CB_InBackPerc.Value = _calcOpts.InBackPerc; CK_MultiTargs.Checked = _calcOpts.MultipleTargets; CB_MultiTargsMax.Enabled = CK_MultiTargs.Checked; CB_MultiTargsPerc.Enabled = CK_MultiTargs.Checked; CB_MultiTargsMax.Value = _calcOpts.AdditionalTargets; CB_MultiTargsPerc.Value = (int)(_calcOpts.AdditionalTargetPercent * 100 + .001f); Stats stats = calcs.GetCharacterStats(Character, null); TB_BossInfo.Text = boss.GenInfoString( 0, // The Boss' Damage bonuses against you (meaning YOU are debuffed) StatConversion.GetArmorDamageReduction(_calcOpts.TargetLevel, stats.Armor, 0, 0, 0), // Your Armor's resulting Damage Reduction StatConversion.GetDRAvoidanceChance(Character, stats, HitResult.Miss, _calcOpts.TargetLevel), // Your chance for Boss to Miss you StatConversion.GetDRAvoidanceChance(Character, stats, HitResult.Dodge, _calcOpts.TargetLevel), // Your chance Dodge StatConversion.GetDRAvoidanceChance(Character, stats, HitResult.Parry, _calcOpts.TargetLevel), // Your chance Parry 0, // Your Chance to Block 0); // How much you Block when you Block // Save the new names _loadingCalculationOptions = false; Character.OnCalculationsInvalidated(); } }
public static float EffectiveTargetArmorReduction(Character character, Stats stats, int targetArmor, int targetLevel) { float effectiveTargetArmor = GetEffectiveTargetArmor(character.Level, targetArmor, 0.0f, stats.ArmorPenetration, stats.ArmorPenetrationRating); float damageReduction = StatConversion.GetArmorDamageReduction(targetLevel, effectiveTargetArmor, 0f, 0f, 0f); return(damageReduction); }
public void UpdateCalcs() { float fightLength = _calcOpts.FightLength * 60f; float bloodlustUptime = ((float)Math.Floor(fightLength / 600f) * 40f + (float)Math.Min(fightLength % 600f, 40f)) / fightLength; float bloodlustHaste = 1f + (CalcOpts.Bloodlust ? (bloodlustUptime * .3f) : 0f); float awUptime = (float)Math.Ceiling((fightLength - 20f) / (180f - _talents.SanctifiedWrath * 30f)) * 20f / fightLength; AvengingWrathMulti = 1f + awUptime * .2f; float targetArmor = StatConversion.NPC_ARMOR[CalcOpts.TargetLevel - 80]; float dr = StatConversion.GetArmorDamageReduction(Character.Level, targetArmor, Stats.ArmorPenetration, 0f, Stats.ArmorPenetrationRating); float drAW = dr * ((1 - awUptime) + (1 - .25f * _talents.SanctifiedWrath) * awUptime); float drNoAW = dr; ArmorReduction = 1f - drAW; BaseWeaponSpeed = (_character.MainHand == null || _character.MainHand.Speed == 0.0f) ? 3.5f : _character.MainHand.Speed; // NOTE by Kavan: added a check against speed == 0, it can happen when item data is still being downloaded float baseWeaponDamage = _character.MainHand == null ? 371.5f : (_character.MainHand.MinDamage + _character.MainHand.MaxDamage) / 2f; AttackSpeed = BaseWeaponSpeed / ((1f + _stats.PhysicalHaste) * bloodlustHaste); WeaponDamage = baseWeaponDamage + _stats.AttackPower * BaseWeaponSpeed / 14f; NormalWeaponDamage = baseWeaponDamage + _stats.AttackPower * 3.3f / 14f; }
public static float TargetArmorReduction(Character character, Stats stats, int targetArmor) { float damageReduction = StatConversion.GetArmorDamageReduction(character.Level, targetArmor, stats.ArmorPenetration, 0f, stats.ArmorPenetrationRating); return(damageReduction); }
public ShotRotationCalculator(Character character, CharacterCalculationsHunter calculatedStats, CalculationOptionsHunter options, double totalStaticHaste, double effectiveRAPAgainstMob, double abilitiesCritDmgModifier, double yellowCritDmgModifier, double weaponDamageAverage, double ammoDamage, double talentModifiers) { ratings = new HunterRatings(); this.character = character; this.calculatedStats = calculatedStats; this.options = options; this.hawkRAPBonus = ratings.HAWK_BONUS_AP * (1.0 + 0.5 * character.HunterTalents.AspectMastery); this.totalStaticHaste = totalStaticHaste; this.effectiveRAPAgainstMob = effectiveRAPAgainstMob; this.abilitiesCritDmgModifier = abilitiesCritDmgModifier; this.yellowCritDmgModifier = yellowCritDmgModifier; this.weaponDamageAverage = weaponDamageAverage; this.ammoDamage = ammoDamage; this.talentModifiers = talentModifiers; int targetArmor = options.TargetArmor; this.armorReduction = 1f - StatConversion.GetArmorDamageReduction(character.Level, targetArmor, calculatedStats.BasicStats.ArmorPenetration, 0f, calculatedStats.BasicStats.ArmorPenetrationRating); //double targetArmor = (options.TargetArmor - calculatedStats.BasicStats.ArmorPenetration) * (1.0 - calculatedStats.BasicStats.ArmorPenetrationRating / (ratings.ARP_RATING_PER_PERCENT * 100.0)); //this.armorReduction = 1.0 - (targetArmor / (467.5 * options.TargetLevel + targetArmor - 22167.5)); //reducedArmor *= (1f - character.HunterTalents.PiercingShots * 0.02f); this.talentedArmorReduction = 1f - StatConversion.GetArmorDamageReduction(character.Level, targetArmor, calculatedStats.BasicStats.ArmorPenetration, character.HunterTalents.PiercingShots * 0.02f, calculatedStats.BasicStats.ArmorPenetrationRating); //this.talentedArmorReduction = 1.0 - (targetArmor / (467.5 * options.TargetLevel + targetArmor - 22167.5)); }
public static float ArmorReduction(Character character, Stats stats) { CalculationOptionsProtWarr calcOpts = character.CalculationOptions as CalculationOptionsProtWarr; return(StatConversion.GetArmorDamageReduction(calcOpts.TargetLevel, stats.Armor, 0.0f, 0.0f, 0.0f)); // return Math.Max(0.0f, Math.Min(0.75f, stats.Armor / (stats.Armor + (467.5f * calcOpts.TargetLevel - 22167.5f)))); }
protected float CalcMeleeDamage(bool canGlance, float bonusDamage) { int level = Mommy.Options.TargetLevel; int levelDelta = level - 80; float characterSheetDamage = BaseMeleeDamage + DamagePerAttackPower * CalcAttackPower() + bonusDamage; float combatTableModifier = CalcMeleeHitChance() + CalcMeleeCrit() - StatConversion.WHITE_DODGE_CHANCE_CAP[levelDelta]; if (canGlance) { combatTableModifier -= .3f * StatConversion.WHITE_GLANCE_CHANCE_CAP[levelDelta]; } float armorModifier = 1 - StatConversion.GetArmorDamageReduction( level, StatConversion.NPC_ARMOR[levelDelta], Stats.ArmorPenetration, // arpen debuffs 0f, // arpen buffs 0f); // arpen rating return(characterSheetDamage * combatTableModifier * armorModifier * MeleeModifiers.GetFinalDirectMultiplier()); }
public static float TargetArmorReduction(Character character, Stats stats, int targetArmor) { float ignoreArmor = 0.0f; if (character.MainHand != null && (character.MainHand.Type == ItemType.OneHandMace)) { ignoreArmor += character.WarriorTalents.MaceSpecialization * 0.03f; } return(StatConversion.GetArmorDamageReduction(character.Level, targetArmor, stats.ArmorPenetration, ignoreArmor, stats.ArmorPenetrationRating)); }
protected float CalcMeleeDamage(bool canGlance, float bonusDamage) { int level = Mommy.CalcOpts.TargetLevel; int levelDelta = level - Mommy.CalcOpts.PlayerLevel; if (levelDelta > 3) { levelDelta = 3; } float characterSheetDamage = BaseMeleeDamage + DamagePerAttackPower * CalcAttackPower() + bonusDamage; float combatTableModifier = CalcMeleeHitChance() + CalcMeleeCrit() - StatConversion.WHITE_DODGE_CHANCE_CAP[levelDelta]; if (canGlance) { combatTableModifier -= .3f * StatConversion.WHITE_GLANCE_CHANCE_CAP[levelDelta]; } float armorModifier = 1f - StatConversion.GetArmorDamageReduction(level, StatConversion.NPC_ARMOR[levelDelta], Stats.TargetArmorReduction, 0f); return(characterSheetDamage * combatTableModifier * armorModifier * MeleeModifiers.GetFinalDirectMultiplier()); }
// Now returns damage per cast to allow adjustments for fight length private float DoTreeCalcs(CharacterCalculationsMoonkin calcs, int playerLevel, int bossLevel, float effectiveNatureDamage, float treantLifespan) { float sunderPercent = calcs.BasicStats.TargetArmorReduction; float meleeHit = calcs.SpellHit * (StatConversion.WHITE_MISS_CHANCE_CAP[bossLevel - playerLevel] / StatConversion.GetSpellMiss(playerLevel - bossLevel, false)); float physicalDamageMultiplierBonus = (1f + calcs.BasicStats.BonusDamageMultiplier) * (1f + calcs.BasicStats.BonusPhysicalDamageMultiplier); float physicalDamageMultiplierReduc = (1f - calcs.BasicStats.DamageTakenReductionMultiplier) * (1f - calcs.BasicStats.PhysicalDamageTakenReductionMultiplier); // 932 = base AP, 57% spell power scaling float attackPower = 932.0f + (float)Math.Floor(0.57f * effectiveNatureDamage); // 1.65 s base swing speed float baseAttackSpeed = 1.65f; float attackSpeed = baseAttackSpeed / (1 + calcs.BasicStats.PhysicalHaste); // 580 = base DPS float damagePerHit = (580f + attackPower / 14.0f) * baseAttackSpeed; // 5% base crit rate, inherit crit debuffs // Remove crit depression, as it doesn't appear to have an effect (unless it's base ~10% crit rate) float critRate = 0.05f; // White hit glancing rate float glancingRate = StatConversion.WHITE_GLANCE_CHANCE_CAP[bossLevel - playerLevel]; // Hit rate determined by the amount of melee hit, not by spell hit float missRate = Math.Max(0f, StatConversion.WHITE_MISS_CHANCE_CAP[bossLevel - playerLevel] - meleeHit); // Since the trees inherit expertise from their hit, scale their hit rate such that when they are hit capped, they are expertise capped float dodgeRate = Math.Max(0f, StatConversion.WHITE_DODGE_CHANCE_CAP[bossLevel - playerLevel] * (missRate / StatConversion.WHITE_MISS_CHANCE_CAP[bossLevel - playerLevel])); // Armor damage reduction, including Sunder float damageReduction = StatConversion.GetArmorDamageReduction(playerLevel, StatConversion.NPC_ARMOR[bossLevel - playerLevel] * (1f - sunderPercent), 0, 0); // Final normal damage per swing damagePerHit *= 1.0f - damageReduction; damagePerHit *= physicalDamageMultiplierReduc; damagePerHit *= physicalDamageMultiplierBonus; // Damage per swing, including crits/glances/misses // This is a cheesy approximation of a true combat table, but because crit/miss/dodge rates will all be fairly low, I don't need to do the whole thing damagePerHit = (critRate * damagePerHit * 2.0f) + (glancingRate * damagePerHit * 0.75f) + ((1 - critRate - glancingRate - missRate - dodgeRate) * damagePerHit); // Total damage done in their estimated lifespan float damagePerTree = (treantLifespan * 30.0f / attackSpeed) * damagePerHit; return(3 * damagePerTree); }
public override Dictionary <string, string> GetCharacterDisplayCalculationValues() { Dictionary <string, string> dictValues = new Dictionary <string, string>(); CalculationOptionsShadowPriest calcOpts = character.CalculationOptions as CalculationOptionsShadowPriest; BossOptions BossOpts = character.BossOptions; Stats baseStats = BaseStats.GetBaseStats(character.Level, character.Class, character.Race); bool Ptr = calcOpts.PTR; dictValues.Add("Health", BasicStats.Health.ToString()); float ResilienceCap = 0.15f, ResilienceFromRating = StatConversion.GetCritReductionFromResilience(1); float Resilience = StatConversion.GetCritReductionFromResilience(BasicStats.Resilience); dictValues.Add("Resilience", string.Format("{0}*-{1}% Damage from DoT and Mana Drains\n\r-{1}% Chance to be crit\r\n-{2}% Damage from Crits.\r\n{3}", BasicStats.Resilience.ToString(), (Resilience * 100f).ToString("0.00"), (Resilience * 100f * 2.2f).ToString("0.00"), (Resilience > ResilienceCap) ? (string.Format("{0} rating above cap", ((float)Math.Floor((Resilience - ResilienceCap) / ResilienceFromRating)).ToString("0"))) : (string.Format("{0} rating below cap", ((float)Math.Ceiling((ResilienceCap - Resilience) / ResilienceFromRating)).ToString("0"))))); dictValues.Add("Stamina", BasicStats.Stamina.ToString()); dictValues.Add("Mana", BasicStats.Mana.ToString()); dictValues.Add("Intellect", BasicStats.Intellect.ToString()); dictValues.Add("Spirit", Math.Floor(BasicStats.Spirit).ToString("0")); dictValues.Add("Spell Power", String.Format("{0}*{1} Bonus Shadow\r\n{2} Bonus Holy\r\n{3} from Inner Fire", Math.Floor(BasicStats.SpellPower), Math.Floor(BasicStats.SpellPower + BasicStats.SpellShadowDamageRating), Math.Floor(BasicStats.SpellPower /*+ BasicStats.SpellHolyDamageRating*/), BasicStats.PriestInnerFire * CalculationsShadowPriest.GetInnerFireSpellPowerBonus(character))); dictValues.Add("Regen", String.Format("{0}*MP5: {1}\r\nOutFSR: {2}", RegenInFSR.ToString("0"), BasicStats.Mp5.ToString(), RegenOutFSR.ToString("0"))); dictValues.Add("Crit", string.Format("{0}%*{1}% from {2} Spell Crit rating\r\n{3}% from Intellect\r\n{4}% from Focused Will\r\n{5}% from Base Crit\r\n{6}% from Buffs\r\n{7}% on Mind Blast, Mind Flay and Mind Sear.\r\n{8}% on VT, SW:P and DP\r\n{9}% on Smite, Holy Fire and Penance.", (BasicStats.SpellCrit * 100f).ToString("0.00"), (StatConversion.GetSpellCritFromRating(BasicStats.CritRating) * 100f).ToString("0.00"), BasicStats.CritRating.ToString("0"), (StatConversion.GetSpellCritFromIntellect(BasicStats.Intellect) * 100f).ToString("0.00"), character.PriestTalents.FocusedWill, (baseStats.SpellCrit * 100f).ToString("0.00"), (BasicStats.SpellCrit * 100f - StatConversion.GetSpellCritFromRating(BasicStats.CritRating) * 100f - StatConversion.GetSpellCritFromIntellect(BasicStats.Intellect) * 100f - baseStats.SpellCrit * 100f - character.PriestTalents.FocusedWill).ToString("0.00"), (BasicStats.SpellCrit * 100f + character.PriestTalents.MindMelt * 2f).ToString("0.00"), (BasicStats.SpellCrit * 100f + character.PriestTalents.MindMelt * 3f).ToString("0.00"), (BasicStats.SpellCrit * 100f + character.PriestTalents.HolySpecialization * 1f).ToString("0.00"))); #if RAWR3 || SILVERLIGHT float Hit = 100 - (StatConversion.GetSpellMiss(character.Level - BossOpts.Level, false) * 100); #else float Hit = 100 - (StatConversion.GetSpellMiss(-calcOpts.TargetLevel, false) * 100); #endif float BonusHit = BasicStats.SpellHit * 100f; float RacialHit = 0; string RacialText = ""; if (character.Race == CharacterRace.Draenei) { RacialHit = 1; RacialText = "1% from Draenei Racial\r\n"; if (!character.ActiveBuffsContains("Heroic Presence")) { BonusHit += 1; } } float DebuffHit = character.PriestTalents.Misery * 1f; if (character.ActiveBuffsConflictingBuffContains("Spell Hit Chance Taken")) { DebuffHit = 3f; } else { BonusHit += DebuffHit; } float RHitRating = 0.01f / StatConversion.GetSpellHitFromRating(1); float ShadowFocusHit = character.PriestTalents.ShadowFocus * 1f; float HitShadow = Hit + BonusHit + ShadowFocusHit; float HitHoly = Hit + BonusHit; dictValues.Add("Hit", string.Format("{0}%*{1}% from {2} Hit Rating\r\n{3}% from Buffs\r\n{4}% from {5} points in Misery\r\n{6}% from {7} points in Shadow Focus\r\n{8}{9}% Hit with Shadow spells, {10}\r\n{11}% Hit with Holy spells, {12}", BonusHit.ToString("0.00"), (StatConversion.GetSpellHitFromRating(BasicStats.HitRating) * 100f).ToString("0.00"), BasicStats.HitRating, (BonusHit - StatConversion.GetSpellHitFromRating(BasicStats.HitRating) * 100f - RacialHit - DebuffHit).ToString("0.00"), DebuffHit, character.PriestTalents.Misery, ShadowFocusHit, character.PriestTalents.ShadowFocus, RacialText, HitShadow.ToString("0.00"), (HitShadow > 100f) ? string.Format("{0} hit rating above cap", Math.Floor((HitShadow - 100f) * RHitRating)) : string.Format("{0} hit rating below cap", Math.Ceiling((100f - HitShadow) * RHitRating)), HitHoly.ToString("0.00"), (HitHoly > 100f) ? string.Format("{0} hit rating above cap", Math.Floor((HitHoly - 100f) * RHitRating)) : string.Format("{0} hit rating below cap", Math.Ceiling((100f - HitHoly) * RHitRating)))); dictValues.Add("Haste", string.Format("{0}%*{1}% from {2} Haste rating\r\n{3}% ({6}) points in Enlightenment\r\n{4}% from Buffs\r\n{5}s Global Cooldown", (BasicStats.SpellHaste * 100f).ToString("0.00"), (StatConversion.GetSpellHasteFromRating(BasicStats.HasteRating) * 100f).ToString("0.00"), BasicStats.HasteRating.ToString(), (character.PriestTalents.Enlightenment * 2).ToString("0"), (((1f + BasicStats.SpellHaste) / (1f + StatConversion.GetSpellHasteFromRating(BasicStats.HasteRating)) / (1f + character.PriestTalents.Enlightenment * 0.02f) - 1f) * 100f).ToString("0.00"), Math.Max(1.0f, 1.5f / (1 + BasicStats.SpellHaste)).ToString("0.00"), character.PriestTalents.Enlightenment)); dictValues.Add("Armor", string.Format("{0}*{1}% Damage Reduction.", (BasicStats.Armor + BasicStats.BonusArmor).ToString("0"), (StatConversion.GetArmorDamageReduction(80, (BasicStats.Armor + BasicStats.BonusArmor), 0f, 0f, 0f) * 100f).ToString("0.00"))); float[] Resistances = { 0, BasicStats.ArcaneResistance + BasicStats.ArcaneResistanceBuff, BasicStats.FireResistance + BasicStats.FireResistanceBuff, BasicStats.FrostResistance + BasicStats.FrostResistanceBuff, BasicStats.NatureResistance + BasicStats.NatureResistanceBuff, BasicStats.ShadowResistance + BasicStats.ShadowResistanceBuff, }; string[] ResistanceNames = { "None", "Arcane", "Fire", "Frost", "Nature", "Shadow", }; string ResistanceString = "*Resistances:"; float MaxResist = Resistances[0]; int MaxResistIndex = 0; float AvgResist = 0f; for (int x = 1; x < Resistances.Length; x++) { AvgResist += Resistances[x]; if (Resistances[x] > MaxResist) { MaxResist = Resistances[x]; MaxResistIndex = x; } ResistanceString += string.Format("\r\n{0} : {1}", ResistanceNames[x], Resistances[x]); } AvgResist /= (Resistances.Length - 1); if (AvgResist == 0) { ResistanceString = "None" + ResistanceString; } else { string ResistanceName = (MaxResist == AvgResist) ? "All" : ResistanceNames[MaxResistIndex]; ResistanceString = string.Format("{0} : {1}", ResistanceName, MaxResist.ToString("0")) + ResistanceString; ResistanceString += string.Format("\r\n\r\nResist ({0}):", ResistanceName); ResistanceString += string.Format("\r\n{0}", StatConversion.GetResistanceTableString(character.Level + 3, character.Level, MaxResist, 0)); } dictValues.Add("Resistance", ResistanceString); SolverBase solver = GetSolver(character, BasicStats); solver.Calculate(this); dictValues.Add("Rotation", string.Format("{0}*{1}", solver.Name, solver.Rotation)); if (solver.SpellSimulation != null) { String s = "Spell Cast List:"; int i = 0; foreach (Spell spell in solver.SpellSimulation) { if (i++ % 10 == 0) { s += "\r\n"; } s += ", " + spell.Name; } s += "\r\n---Repeat---"; dictValues.Add("Castlist", string.Format("{0}*{1}", solver.SpellSimulation.Count, s)); } else { dictValues.Add("Castlist", "Empty"); } dictValues.Add("DPS", string.Format("{0}*Damage Pr Second", solver.DPS.ToString("0"))); //dictValues.Add("SustainDPS", string.Format("{0}*Mana restrained DPS", solver.SustainDPS.ToString("0"))); float baseMana = BaseStats.GetBaseStats(character).Mana; dictValues.Add("SW Pain", new ShadowWordPain(BasicStats, character, baseMana, Ptr).ToString()); DevouringPlague dp = new DevouringPlague(BasicStats, character, baseMana, Ptr); dictValues.Add("Devouring Plague", dp.ToString()); if (dp.ImprovedDP != null) { dictValues.Add("Imp. Devouring Plague", dp.ImprovedDP.ToString()); } else { dictValues.Add("Imp. Devouring Plague", "- *No required talents"); } dictValues.Add("SW Death", new ShadowWordDeath(BasicStats, character, baseMana, Ptr).ToString()); dictValues.Add("Mind Blast", new MindBlast(BasicStats, character, baseMana, Ptr).ToString()); dictValues.Add("PW Shield", new PowerWordShield(BasicStats, character, baseMana, Ptr).ToString()); if (character.PriestTalents.VampiricTouch > 0) { dictValues.Add("Vampiric Touch", new VampiricTouch(BasicStats, character, baseMana, Ptr).ToString()); } else { dictValues.Add("Vampiric Touch", "- *No required talents"); } if (character.PriestTalents.MindFlay > 0) { dictValues.Add("Mind Flay", new MindFlay(BasicStats, character, baseMana, Ptr).ToString()); } else { dictValues.Add("Mind Flay", "- *No required talents"); } dictValues.Add("Shadowfiend", new Shadowfiend(BasicStats, character, baseMana, Ptr).ToString()); dictValues.Add("Smite", new Smite(BasicStats, character, baseMana, Ptr).ToString()); dictValues.Add("Holy Fire", new HolyFire(BasicStats, character, baseMana, Ptr).ToString()); if (character.PriestTalents.Penance > 0) { dictValues.Add("Penance", new Penance(BasicStats, character, baseMana, Ptr).ToString()); } else { dictValues.Add("Penance", "- *No required talents"); } return(dictValues); }
public void CritsAndResists() { #region Crits, Resists { // Attack Rolltable (DW): // 27.0% miss (8.0% with 2H) // 6.5% dodge // 24.0% glancing (75% hit-dmg) // xx.x% crit // remaining = hit float targetArmor = calcOpts.BossArmor, totalArP = stats.ArmorPenetration; float arpBuffs = talents.BloodGorged * 2f / 100; physicalMitigation = 1f - StatConversion.GetArmorDamageReduction(character.Level, targetArmor, stats.ArmorPenetration, arpBuffs, stats.ArmorPenetrationRating); calcs.EnemyMitigation = 1f - physicalMitigation; calcs.EffectiveArmor = physicalMitigation; // Crit: Base .65% physCrits = .0065f; physCrits += StatConversion.GetPhysicalCritFromRating(stats.CritRating); physCrits += StatConversion.GetPhysicalCritFromAgility(stats.Agility, CharacterClass.DeathKnight); physCrits += .01f * (float)(talents.DarkConviction + talents.EbonPlaguebringer + talents.Annihilation); physCrits += stats.PhysicalCrit; calcs.CritChance = physCrits; float chanceAvoided = 0.335f; float chanceDodged = StatConversion.WHITE_DODGE_CHANCE_CAP[calcOpts.TargetLevel - 80]; calcs.DodgedMHAttacks = MH.chanceDodged; calcs.DodgedOHAttacks = OH.chanceDodged; if (character.MainHand != null) { chanceDodged = MH.chanceDodged; } if (character.OffHand != null) { if (DW) { chanceDodged += OH.chanceDodged; chanceDodged /= 2; } else if (character.MainHand == null) { chanceDodged = OH.chanceDodged; } } calcs.DodgedAttacks = chanceDodged; // Process White hits: float chanceMiss = DW ? StatConversion.WHITE_MISS_CHANCE_CAP_DW[calcOpts.TargetLevel - 80] : StatConversion.WHITE_MISS_CHANCE_CAP[calcOpts.TargetLevel - 80]; chanceMiss -= StatConversion.GetPhysicalHitFromRating(stats.HitRating); chanceMiss -= hitBonus; chanceMiss -= stats.PhysicalHit; // Cap the Miss rate at 0% chanceMiss = Math.Max(chanceMiss, 0f); calcs.MissedAttacks = chanceMiss; whiteMiss = chanceMiss; chanceAvoided = chanceDodged + chanceMiss; calcs.AvoidedAttacks = chanceDodged + chanceMiss; // Process Yellow hits chanceMiss = StatConversion.YELLOW_MISS_CHANCE_CAP[calcOpts.TargetLevel - 80]; chanceMiss -= StatConversion.GetPhysicalHitFromRating(stats.HitRating); chanceMiss -= hitBonus; chanceMiss -= stats.PhysicalHit; chanceMiss = Math.Max(chanceMiss, 0f); chanceDodged = MH.chanceDodged; missedSpecial = chanceMiss; dodgedSpecial = chanceDodged; // calcs.MissedAttacks = chanceMiss spellCrits = 0f; spellCrits += StatConversion.GetSpellCritFromRating(stats.CritRating); spellCrits += stats.SpellCrit + stats.SpellCritOnTarget; spellCrits += .01f * (float)(talents.DarkConviction + talents.EbonPlaguebringer); calcs.SpellCritChance = spellCrits; // Resists: Base 17% spellResist = .17f; spellResist -= StatConversion.GetSpellHitFromRating(stats.HitRating); spellResist -= .01f * talents.Virulence; spellResist -= stats.SpellHit; if (spellResist < 0f) { spellResist = 0f; } // Total physical misses totalMHMiss = calcs.DodgedMHAttacks + whiteMiss; totalOHMiss = calcs.DodgedOHAttacks + whiteMiss; double spellGCD = (calcOpts.rotation.presence == CalculationOptionsDPSDK.Presence.Blood ? 1.5d / ((1 + (StatConversion.GetHasteFromRating(stats.HasteRating, CharacterClass.DeathKnight))) * (1d + stats.SpellHaste)) < 1d ? 1d : 1.5d / ((1 + (StatConversion.GetHasteFromRating(stats.HasteRating, CharacterClass.DeathKnight))) * (1d + stats.SpellHaste)): 1d); double physicalGCD = (calcOpts.rotation.presence == CalculationOptionsDPSDK.Presence.Blood ? 1.5d : 1d); float minDuration = totalMeleeAbilities * (float)physicalGCD + totalSpellAbilities * (float)spellGCD; realDuration = (float)Math.Max(minDuration, calcOpts.rotation.CurRotationDuration); float dodgeMissPerRotation = (float)(totalMeleeAbilities - calcOpts.rotation.FrostStrike); chanceAvoided = chanceDodged + chanceMiss; double GChanceAvoided = (1 / (1 - chanceAvoided)) - 1; double GSpellResist = (1 / (1 - spellResist)) - 1; double ProbableGCDLossPerRotation = dodgeMissPerRotation * physicalGCD * GChanceAvoided + (calcOpts.rotation.IcyTouch + calcOpts.rotation.Pestilence) * spellGCD * GSpellResist; realDuration += (float)(((minDuration + ProbableGCDLossPerRotation) / realDuration < 1 ? (minDuration + ProbableGCDLossPerRotation) / realDuration : 1) * ProbableGCDLossPerRotation); // This last line is a bit hackish, but basically the extra GCD is more inconvenient the closer we are to having a GCD-capped rotation; once we're GCD-capped, they cost the full value. } #endregion }
public override Dictionary <string, string> GetCharacterDisplayCalculationValues() { Dictionary <string, string> dictValues = new Dictionary <string, string>(); Stats baseStats = BaseStats.GetBaseStats(character); dictValues.Add("Health", BasicStats.Health.ToString()); dictValues.Add("Stamina", BasicStats.Stamina.ToString()); float ResilienceCap = 0.15f, ResilienceFromRating = StatConversion.GetCritReductionFromResilience(1); float Resilience = StatConversion.GetCritReductionFromResilience(BasicStats.Resilience); dictValues.Add("Resilience", string.Format("{0}*-{1}% Damage from DoT and Mana Drains\n\r-{1}% Chance to be crit\r\n-{2}% Damage from Crits.\r\n{3}", BasicStats.Resilience.ToString(), (Resilience * 100f).ToString("0.00"), (Resilience * 100f * 2.2f).ToString("0.00"), (Resilience > ResilienceCap)?(string.Format("{0} rating above cap", ((float)Math.Floor((Resilience - ResilienceCap) / ResilienceFromRating)).ToString("0"))):(string.Format("{0} rating below cap", ((float)Math.Ceiling((ResilienceCap - Resilience) / ResilienceFromRating)).ToString("0"))))); dictValues.Add("Mana", BasicStats.Mana.ToString()); dictValues.Add("Intellect", BasicStats.Intellect.ToString()); dictValues.Add("Spirit", Math.Floor(BasicStats.Spirit).ToString("0")); dictValues.Add("Spell Power", string.Format("{0}*{1} from Inner Fire", Math.Floor(BasicStats.SpellPower).ToString("0"), BasicStats.PriestInnerFire * CalculationsHealPriest.GetInnerFireSpellPowerBonus(character))); //dictValues.Add("Healing", Math.Floor(BasicStats.SpellPower * 1.88f).ToString("0")); dictValues.Add("In FSR MP5", string.Format("{0}*{1} from MP5\r\n{2} from Meditation\r\n{3} Outside FSR\r\n{4} OFSR w/MP5", (BasicStats.Mp5 + RegenInFSR).ToString("0"), BasicStats.Mp5.ToString("0"), RegenInFSR.ToString("0"), RegenOutFSR.ToString("0"), (BasicStats.Mp5 + RegenOutFSR).ToString("0"))); dictValues.Add("Spell Crit", string.Format("{0}%*{1}% from Intellect\r\n{2}% from {6} Crit rating\r\n{3}% from Focused Will\r\n{4}% Class Base\r\n{5}% from Buffs", (BasicStats.SpellCrit * 100f).ToString("0.00"), (StatConversion.GetSpellCritFromIntellect(BasicStats.Intellect) * 100f).ToString("0.00"), (StatConversion.GetSpellCritFromRating(BasicStats.CritRating) * 100f).ToString("0.00"), character.PriestTalents.FocusedWill.ToString("0"), (baseStats.SpellCrit * 100f).ToString("0.00"), (BasicStats.SpellCrit * 100f - baseStats.SpellCrit * 100f - StatConversion.GetSpellCritFromRating(BasicStats.CritRating) * 100f - StatConversion.GetSpellCritFromIntellect(BasicStats.Intellect) * 100f - character.PriestTalents.FocusedWill * 1f).ToString("0.00"), BasicStats.CritRating)); dictValues.Add("Healing Crit", string.Format("{0}%*{1} ({1}%) points in Holy Specialization\r\n{2} ({3}%) points in Renewed Hope", ((BasicStats.SpellCrit * 100f) + character.PriestTalents.HolySpecialization * 1f + character.PriestTalents.RenewedHope * 2f).ToString("0.00"), character.PriestTalents.HolySpecialization, character.PriestTalents.RenewedHope, character.PriestTalents.RenewedHope * 2)); dictValues.Add("Spell Haste", string.Format("{0}%*{1}% from {2} Haste rating\r\n{3}% ({6}) points in Enlightenment\r\n{4}% from Buffs\r\n{5}s Global Cooldown", (BasicStats.SpellHaste * 100f).ToString("0.00"), (StatConversion.GetSpellHasteFromRating(BasicStats.HasteRating) * 100f).ToString("0.00"), BasicStats.HasteRating.ToString(), (character.PriestTalents.Enlightenment * 2).ToString("0"), (((1 + BasicStats.SpellHaste) / (1 + StatConversion.GetSpellHasteFromRating(BasicStats.HasteRating)) / (1 + character.PriestTalents.Enlightenment * 0.02f) - 1) * 100f).ToString("0.00"), Math.Max(1.0f, 1.5f / (1 + BasicStats.SpellHaste)).ToString("0.00"), character.PriestTalents.Enlightenment)); dictValues.Add("Armor", string.Format("{0}*{1}% Damage Reduction.", (BasicStats.Armor + BasicStats.BonusArmor).ToString("0"), (StatConversion.GetArmorDamageReduction(80, (BasicStats.Armor + BasicStats.BonusArmor), 0f, 0f, 0f) * 100f).ToString("0.00"))); float[] Resistances = { 0, BasicStats.ArcaneResistance + BasicStats.ArcaneResistanceBuff, BasicStats.FireResistance + BasicStats.FireResistanceBuff, BasicStats.FrostResistance + BasicStats.FrostResistanceBuff, BasicStats.NatureResistance + BasicStats.NatureResistanceBuff, BasicStats.ShadowResistance + BasicStats.ShadowResistanceBuff, }; string[] ResistanceNames = { "None", "Arcane", "Fire", "Frost", "Nature", "Shadow", }; string ResistanceString = "*Resistances:"; float MaxResist = Resistances[0]; int MaxResistIndex = 0; float AvgResist = 0f; for (int x = 1; x < Resistances.Length; x++) { AvgResist += Resistances[x]; if (Resistances[x] > MaxResist) { MaxResist = Resistances[x]; MaxResistIndex = x; } ResistanceString += string.Format("\r\n{0} : {1}", ResistanceNames[x], Resistances[x]); } AvgResist /= (Resistances.Length - 1); if (AvgResist == 0) { ResistanceString = "None" + ResistanceString; } else { string ResistanceName = (MaxResist == AvgResist) ? "All" : ResistanceNames[MaxResistIndex]; ResistanceString = string.Format("{0} : {1}", ResistanceName, MaxResist.ToString("0")) + ResistanceString; ResistanceString += string.Format("\r\n\r\nResist ({0}):", ResistanceName); ResistanceString += string.Format("\r\n{0}", StatConversion.GetResistanceTableString(character.Level + 3, character.Level, MaxResist, 0)); } dictValues.Add("Resistance", ResistanceString); BaseSolver solver; if ((character.CalculationOptions as CalculationOptionsHealPriest).Role == eRole.CUSTOM) { solver = new AdvancedSolver(BasicStats, character); } else { solver = new Solver(BasicStats, character); } solver.Calculate(this); dictValues.Add("Role", string.Format("{0}*{1}", solver.Role, solver.ActionList)); dictValues.Add("Burst", string.Format("{0}", HPSBurstPoints.ToString("0"))); dictValues.Add("Sustained", string.Format("{0}", HPSSustainPoints.ToString("0"))); dictValues.Add("Renew", new Renew(BasicStats, character).ToString()); dictValues.Add("Flash Heal", new FlashHeal(BasicStats, character).ToString()); dictValues.Add("Greater Heal", new Heal(BasicStats, character).ToString()); dictValues.Add("PoH", new PrayerOfHealing(BasicStats, character).ToString()); dictValues.Add("Binding Heal", new BindingHeal(BasicStats, character).ToString()); dictValues.Add("Prayer of Mending", new PrayerOfMending(BasicStats, character).ToString()); dictValues.Add("Power Word Shield", new PowerWordShield(BasicStats, character).ToString()); dictValues.Add("Holy Nova", new HolyNova(BasicStats, character).ToString()); if (character.PriestTalents.CircleOfHealing > 0) { dictValues.Add("CoH", new CircleOfHealing(BasicStats, character).ToString()); } else { dictValues.Add("CoH", "- *No required talents"); } if (character.PriestTalents.Lightwell > 0) { dictValues.Add("Lightwell", new Lightwell(BasicStats, character).ToString()); } else { dictValues.Add("Lightwell", "- *No required talents"); } if (character.PriestTalents.Penance > 0) { dictValues.Add("Penance", new Penance(BasicStats, character).ToString()); } else { dictValues.Add("Penance", "- *No required talents"); } if (Race == CharacterRace.Draenei) { dictValues.Add("Gift of the Naaru", new GiftOfTheNaaru(BasicStats, character).ToString()); } else { dictValues.Add("Gift of the Naaru", "-"); } dictValues.Add("Divine Hymn", new DivineHymn(BasicStats, character).ToString()); dictValues.Add("Resurrection", new Resurrection(BasicStats, character).ToString()); return(dictValues); }
public DRW(CombatTable combatTable, CharacterCalculationsDPSDK calcs, CalculationOptionsDPSDK calcOpts, Stats stats, Character character, DeathKnightTalents talents) { bool DW = false; float dpsWhite = 0f; float dpsBCB = 0f; float dpsNecrosis = 0f; float dpsDeathCoil = 0f; float dpsIcyTouch = 0f; float dpsPlagueStrike = 0f; float dpsFrostFever = 0f; float dpsBloodPlague = 0f; float dpsDeathStrike = 0f; float dpsHeartStrike = 0f; float dpsWPFromFF = 0f; float dpsWPFromBP = 0f; float dpsWhiteMinusGlancing = 0f; float dpsWhiteBeforeArmor = 0f; float IcyTouchAPMult = 0.1f; float FrostFeverAPMult = 0.055f; float BloodPlagueAPMult = 0.055f; float DeathCoilAPMult = 0.15f; float OHMult = 0.5f; int targetLevel = calcOpts.TargetLevel; float arpBuffs = talents.BloodGorged * 2f / 100; float mitigation = StatConversion.GetArmorDamageReduction(character.Level, calcOpts.BossArmor, stats.ArmorPenetration, arpBuffs, stats.ArmorPenetrationRating); mitigation = 1 - mitigation; float MHDPS = 0f, OHDPS = 0f; #region White Dmg { #region Main Hand { float dpsMHglancing = (StatConversion.WHITE_GLANCE_CHANCE_CAP[targetLevel - 80] * combatTable.MH.DPS) * 0.7f; float dpsMHBeforeArmor = ((combatTable.MH.DPS * (1f - calcs.AvoidedAttacks - StatConversion.WHITE_GLANCE_CHANCE_CAP[targetLevel - 80])) * (1f + combatTable.physCrits)) + dpsMHglancing; dpsWhiteMinusGlancing = dpsMHBeforeArmor - dpsMHglancing; dpsWhiteBeforeArmor = dpsMHBeforeArmor; MHDPS = dpsMHBeforeArmor * mitigation; } #endregion #region Off Hand if (DW || (character.MainHand == null && character.OffHand != null)) { float dpsOHglancing = (StatConversion.WHITE_GLANCE_CHANCE_CAP[targetLevel - 80] * combatTable.OH.DPS) * 0.7f; float dpsOHBeforeArmor = ((combatTable.OH.DPS * (1f - calcs.AvoidedAttacks - StatConversion.WHITE_GLANCE_CHANCE_CAP[targetLevel - 80])) * (1f + combatTable.physCrits)) + dpsOHglancing; dpsOHBeforeArmor *= OHMult; dpsWhiteMinusGlancing += dpsOHBeforeArmor - dpsOHglancing; dpsWhiteBeforeArmor += dpsOHBeforeArmor; OHDPS = dpsOHBeforeArmor * mitigation; } #endregion dpsWhite = MHDPS + OHDPS; } #endregion #region Necrosis { dpsNecrosis = dpsWhiteMinusGlancing * (.04f * (float)talents.Necrosis); // doesn't proc off Glancings } #endregion #region Blood Caked Blade { float dpsMHBCB = 0f; if (combatTable.MH.damage != 0) { float MHBCBDmg = (float)(combatTable.MH.damage * (.25f + .125f * calcOpts.rotation.AvgDiseaseMult)); dpsMHBCB = MHBCBDmg / combatTable.MH.hastedSpeed; } dpsBCB = dpsMHBCB; dpsBCB *= .1f * (float)talents.BloodCakedBlade; } #endregion #region Death Coil { if (calcOpts.rotation.DeathCoil > 0f) { float DCCD = 1; float DCDmg = 443f + (DeathCoilAPMult * stats.AttackPower); dpsDeathCoil = DCDmg / DCCD; float DCCritDmgMult = .5f * (2f + stats.BonusCritMultiplier); float DCCrit = 1f + ((combatTable.spellCrits + stats.BonusDeathCoilCrit) * DCCritDmgMult); dpsDeathCoil *= DCCrit; dpsDeathCoil *= 1f + (.05f * (float)talents.Morbidity); } } #endregion #region Icy Touch { if (calcOpts.rotation.IcyTouch > 0f) { float ITCD = 1; float ITDmg = 236f + (IcyTouchAPMult * stats.AttackPower) + stats.BonusIcyTouchDamage; ITDmg *= 1f + .1f * (float)talents.ImprovedIcyTouch; dpsIcyTouch = ITDmg / ITCD; float ITCritDmgMult = .5f * (2f + stats.CritBonusDamage + stats.BonusCritMultiplier); float ITCrit = 1f + (Math.Min((combatTable.spellCrits + (.05f * (float)talents.Rime)), 1f) * ITCritDmgMult); dpsIcyTouch *= ITCrit; } } #endregion #region Plague Strike { if (calcOpts.rotation.PlagueStrike > 0f) { float PSCD = 1; float PSDmg = (combatTable.MH.baseDamage + ((stats.AttackPower / 14f) * combatTable.normalizationFactor)) * 0.5f + 189f; dpsPlagueStrike = PSDmg / PSCD; float PSCritDmgMult = 1f + (.15f * (float)talents.ViciousStrikes) + stats.BonusCritMultiplier; float PSCrit = 1f + ((combatTable.physCrits + (.03f * (float)talents.ViciousStrikes) + stats.BonusPlagueStrikeCrit) * PSCritDmgMult); dpsPlagueStrike *= PSCrit; dpsPlagueStrike *= 1f + (.1f * (float)talents.Outbreak); } } #endregion #region Frost Fever { if (calcOpts.rotation.IcyTouch > 0f || (talents.GlyphofHowlingBlast && calcOpts.rotation.HowlingBlast > 0f) || (talents.GlyphofDisease && calcOpts.rotation.Pestilence > 0f)) { float FFDmg = FrostFeverAPMult * stats.AttackPower + 25.6f; dpsFrostFever = FFDmg; dpsFrostFever *= 1.15f; // Patch 3.2: Diseases hit 15% harder. dpsWPFromFF = dpsFrostFever * combatTable.physCrits; } } #endregion #region Blood Plague { if (calcOpts.rotation.PlagueStrike > 0f || talents.GlyphofDisease) { float BPDmg = BloodPlagueAPMult * stats.AttackPower + 31.1f; dpsBloodPlague = BPDmg; dpsBloodPlague *= 1.15f; // Patch 3.2: Diseases hit 15% harder. dpsWPFromBP = dpsBloodPlague * combatTable.physCrits; } } #endregion #region Death Strike { if (calcOpts.rotation.DeathStrike > 0f) { float DSCD = 1; // TODO: This should be changed to make use of the new glyph stats: float DSDmg = ((combatTable.MH.baseDamage + ((stats.AttackPower / 14f) * combatTable.normalizationFactor)) * 0.75f) + 222.75f; DSDmg *= 1f + 0.15f * (float)talents.ImprovedDeathStrike; dpsDeathStrike = DSDmg / DSCD; float DSCritDmgMult = 1f + (.15f * (float)talents.MightOfMograine) + stats.BonusCritMultiplier; float DSCrit = 1f + ((combatTable.physCrits + (.03f * (float)talents.ImprovedDeathStrike) + stats.BonusDeathStrikeCrit) * DSCritDmgMult); dpsDeathStrike *= DSCrit; } } #endregion #region Heart Strike { if (talents.HeartStrike > 0 && calcOpts.rotation.HeartStrike > 0f) { float HSCD = 1; float HSDmg = ((combatTable.MH.baseDamage + ((stats.AttackPower / 14f) * combatTable.normalizationFactor)) * 0.5f) + 368f; HSDmg *= 1f + 0.1f * (float)calcOpts.rotation.AvgDiseaseMult * (1f + stats.BonusPerDiseaseHeartStrikeDamage); dpsHeartStrike = HSDmg / HSCD; //float HSCrit = 1f + combatTable.physCrits + ( .03f * (float)talents.Subversion ); float HSCritDmgMult = 1f + (.15f * (float)talents.MightOfMograine) + stats.BonusCritMultiplier; float HSCrit = 1f + ((combatTable.physCrits + (.03f * (float)talents.Subversion)) * HSCritDmgMult); dpsHeartStrike = (dpsHeartStrike) * HSCrit; dpsHeartStrike *= 1f + (.15f * (float)talents.BloodyStrikes); } } #endregion float BCBMult = 1f; float BloodPlagueMult = 1f; float DeathCoilMult = 1f; float FrostFeverMult = 1f; float HeartStrikeMult = 1f; float IcyTouchMult = 1f; float NecrosisMult = 1f; float DeathStrikeMult = 1f; float PlagueStrikeMult = 1f; float WhiteMult = 1f; float spellPowerMult = 1f + stats.BonusSpellPowerMultiplier; float frostSpellPowerMult = 1f + stats.BonusSpellPowerMultiplier + Math.Max((stats.BonusFrostDamageMultiplier - stats.BonusShadowDamageMultiplier), 0f); float partialResist = 0.94f; float physPowerMult = 1f; #region Apply Physical Mitigation { float physMit = mitigation; physMit *= 1f + (!DW ? .02f * talents.TwoHandedWeaponSpecialization : 0f); dpsBCB *= physMit; dpsHeartStrike *= physMit; dpsDeathStrike *= physMit; dpsPlagueStrike *= physMit; WhiteMult += physPowerMult - 1f; BCBMult += physPowerMult - 1f; HeartStrikeMult += physPowerMult - 1f; DeathStrikeMult += physPowerMult - 1f; PlagueStrikeMult += physPowerMult - 1f; } #endregion #region Apply Magical Mitigation { // some of this applies to necrosis, I wonder if it is ever accounted for float magicMit = partialResist /** combatTable.spellResist*/; // magicMit = 1f - magicMit; dpsNecrosis *= magicMit; dpsBloodPlague *= magicMit; dpsDeathCoil *= magicMit * (1f - combatTable.spellResist); dpsFrostFever *= magicMit; dpsIcyTouch *= magicMit; NecrosisMult += spellPowerMult - 1f; BloodPlagueMult += spellPowerMult - 1f; DeathCoilMult += spellPowerMult - 1f; FrostFeverMult += frostSpellPowerMult - 1f; IcyTouchMult += frostSpellPowerMult - 1f; } #endregion #region Apply Multi-Ability Talent Multipliers { float BloodyVengeanceMult = .03f * (float)talents.BloodyVengeance; BCBMult *= 1 + BloodyVengeanceMult; HeartStrikeMult *= 1 + BloodyVengeanceMult; DeathStrikeMult *= 1 + BloodyVengeanceMult; PlagueStrikeMult *= 1 + BloodyVengeanceMult; WhiteMult *= 1 + BloodyVengeanceMult; float HysteriaCoeff = .2f / 2f; // current uptime is 50% for now float HysteriaMult = HysteriaCoeff * (float)talents.Hysteria; BCBMult *= 1 + HysteriaMult; HeartStrikeMult *= 1 + HysteriaMult; DeathStrikeMult *= 1 + HysteriaMult; PlagueStrikeMult *= 1 + HysteriaMult; WhiteMult *= 1 + HysteriaMult; float BlackIceMult = .02f * (float)talents.BlackIce; FrostFeverMult *= 1 + BlackIceMult; IcyTouchMult *= 1 + BlackIceMult; DeathCoilMult *= 1 + BlackIceMult; BloodPlagueMult *= 1 + BlackIceMult; float CryptFeverMult = .1f * (float)talents.CryptFever; float CryptFeverBuff = stats.BonusDiseaseDamageMultiplier; CryptFeverMult = Math.Max(CryptFeverMult, CryptFeverBuff); FrostFeverMult *= 1 + CryptFeverMult; BloodPlagueMult *= 1 + CryptFeverMult; } #endregion dpsDancingRuneWeapon = dpsWhite * WhiteMult * 17f + dpsBCB * BCBMult * 17f + dpsNecrosis * NecrosisMult * 17f + dpsDeathCoil * DeathCoilMult + dpsIcyTouch * IcyTouchMult + dpsPlagueStrike * PlagueStrikeMult + dpsFrostFever * (5f + talents.Epidemic) * FrostFeverMult + dpsBloodPlague * (5f + talents.Epidemic) * BloodPlagueMult + dpsDeathStrike * DeathStrikeMult * (talents.GlyphofDancingRuneWeapon ? 1f : 0f) + dpsHeartStrike * HeartStrikeMult * (5f + (talents.GlyphofDancingRuneWeapon ? 2f : 0f)); dpsDancingRuneWeapon *= 0.5f; }
public static float EffectiveTargetArmorReduction(float armorPenetration, int targetArmor, int targetLevel) { return(StatConversion.GetArmorDamageReduction(targetLevel, targetArmor, 0f, armorPenetration, 0f)); }
public override Dictionary <string, string> GetCharacterDisplayCalculationValues() { Dictionary <string, string> dictValues = new Dictionary <string, string>(); dictValues.Add("Single Target Points", SingleTargetPoints.ToString()); dictValues.Add("Sustained Points", SustainedPoints.ToString()); dictValues.Add("Survival Points", SurvivalPoints.ToString()); dictValues.Add("Overall Points", OverallPoints.ToString()); dictValues.Add("Base Health", BasicStats.Health.ToString()); dictValues.Add("Base Armor", Math.Round(BasicStats.Armor, 0) + "*Reduces damage taken by " + Math.Round(StatConversion.GetArmorDamageReduction(83, BasicStats.Armor, 0, 0, 0) * 100.0f, 2) + "%"); dictValues.Add("Base Mana", BasicStats.Mana.ToString()); dictValues.Add("Base Stamina", BasicStats.Stamina.ToString()); dictValues.Add("Base Intellect", BasicStats.Intellect.ToString()); dictValues.Add("Base Spirit", BasicStats.Spirit.ToString()); dictValues.Add("Base Spell Power", (BasicStats.SpellPower).ToString() + "*" + BasicStats.Spirit * LocalCharacter.DruidTalents.ImprovedTreeOfLife * 0.05f + " from Improved Tree of Life"); dictValues.Add("Base Spell Crit", BasicStats.SpellCrit.ToString()); float speed_from_hr = (1f + StatConversion.GetSpellHasteFromRating(BasicStats.HasteRating)); float speed_from_sh = (1f + BasicStats.SpellHaste); float speed = speed_from_hr * speed_from_sh; float hard = (1.5f / (1f * speed_from_sh) - 1) * StatConversion.RATING_PER_SPELLHASTE; float untilcap = hard - BasicStats.HasteRating; dictValues.Add("Base Spell Haste", Math.Round((speed - 1.0f) * 100.0f, 2) + "%*" + Math.Round((speed_from_sh - 1.0f) * 100.0f, 2) + "% from spell effects and talents\n" + Math.Round((speed_from_hr - 1.0f) * 100.0f, 2) + "% from " + BasicStats.HasteRating + " haste rating"); // Use Nourish cast time to equal normal GCD Spell spell = new Nourish(LocalCharacter, BasicStats); dictValues.Add("Base Global CD", Math.Round(spell.gcd, 2) + " sec*" + Math.Ceiling(untilcap).ToString() + " Haste Rating until hard gcd cap"); dictValues.Add("Health", CombatStats.Health.ToString()); dictValues.Add("Armor", Math.Round(CombatStats.Armor, 0) + "*Reduces damage taken by " + Math.Round(StatConversion.GetArmorDamageReduction(83, CombatStats.Armor, 0, 0, 0) * 100.0f, 2) + "%"); dictValues.Add("Mana", CombatStats.Mana.ToString()); dictValues.Add("Stamina", CombatStats.Stamina.ToString()); dictValues.Add("Intellect", CombatStats.Intellect.ToString()); dictValues.Add("Spirit", CombatStats.Spirit.ToString()); dictValues.Add("Spell Power", (CombatStats.SpellPower).ToString() + "*" + CombatStats.Spirit * LocalCharacter.DruidTalents.ImprovedTreeOfLife * 0.05f + " from Improved Tree of Life"); dictValues.Add("Spell Crit", CombatStats.SpellCrit.ToString()); speed_from_hr = (1f + StatConversion.GetSpellHasteFromRating(CombatStats.HasteRating)); speed_from_sh = (1f + CombatStats.SpellHaste); speed = speed_from_hr * speed_from_sh; hard = (1.5f / (1f * speed_from_sh) - 1) * StatConversion.RATING_PER_SPELLHASTE; untilcap = hard - CombatStats.HasteRating; dictValues.Add("Spell Haste", Math.Round((speed - 1.0f) * 100.0f, 2) + "%*" + Math.Round((speed_from_sh - 1.0f) * 100.0f, 2) + "% from spell effects and talents\n" + Math.Round((speed_from_hr - 1.0f) * 100.0f, 2) + "% from " + CombatStats.HasteRating + " haste rating"); // Use Nourish cast time to equal normal GCD spell = Sustained.spellMix.nourish[0]; dictValues.Add("Global CD", Math.Round(spell.gcd, 2) + " sec*" + Math.Ceiling(untilcap).ToString() + " Haste Rating until soft gcd cap"); dictValues.Add("Total Time", Math.Round(Sustained.TotalTime, 2).ToString()); dictValues.Add("Time until OOM (unreduced)", Math.Round(Sustained.TimeToOOM_unreduced, 2).ToString()); dictValues.Add("Time until OOM", Math.Round(Sustained.TimeToOOM, 2).ToString()); dictValues.Add("Total healing done", Math.Round(Sustained.TotalTime * SustainedHPS, 2).ToString()); // Has extra component from procs dictValues.Add("Sustained HPS", Math.Round(SustainedHPS, 2).ToString()); dictValues.Add("Single Target HPS", Math.Round(SingleTargetHPS, 2).ToString()); dictValues.Add("Mana regen per second", Math.Round(Sustained.ManaRegen, 2).ToString()); dictValues.Add("Mana from innervates", Math.Round(Sustained.InnervateMana, 2).ToString()); dictValues.Add("Average casts per minute", Math.Round(Sustained.spellMix.CastsPerMinute, 2).ToString()); dictValues.Add("Average crits per minute", Math.Round(Sustained.spellMix.CritsPerMinute, 2).ToString()); dictValues.Add("Average heals per minute", Math.Round(Sustained.spellMix.HealsPerMinute, 2).ToString()); dictValues.Add("Rejuvenation casts per minute", Math.Round(Sustained.spellMix.RejuvCPM, 2).ToString()); dictValues.Add("Rejuvenation average up", Math.Round(Sustained.spellMix.RejuvAvg, 2).ToString()); dictValues.Add("Regrowth casts per minute", Math.Round(Sustained.spellMix.RegrowthCPM, 2).ToString()); dictValues.Add("Regrowth average up", Math.Round(Sustained.spellMix.RegrowthAvg, 2).ToString()); dictValues.Add("Lifebloom (stack) casts per minute", Math.Round(Sustained.spellMix.LifebloomStackCPM, 2).ToString()); dictValues.Add("Lifebloom (stack) average up", Math.Round(Sustained.spellMix.LifebloomStackAvg, 2).ToString()); dictValues.Add("Lifebloom (stack) method", LifebloomMethod_ToString(3, Sustained.rotSettings.lifeBloomType)); dictValues.Add("Lifebloom casts per minute", Math.Round(Sustained.spellMix.LifebloomCPM, 2).ToString()); dictValues.Add("Lifebloom average up", Math.Round(Sustained.spellMix.LifebloomAvg, 2).ToString()); dictValues.Add("Nourish casts per minute", Math.Round(Sustained.spellMix.NourishCPM, 2).ToString()); //dictValues.Add("Healing Touch casts per minute", Math.Round(, 2).ToString()); dictValues.Add("Swiftmend casts per minute", Math.Round(Sustained.spellMix.SwiftmendCPM, 2).ToString()); dictValues.Add("Wild Growth casts per minute", Math.Round(Sustained.spellMix.WildGrowthCPM, 2).ToString()); dictValues.Add("Revitalize procs per minute", Math.Round(Sustained.spellMix.RevitalizeProcsPerMinute, 2).ToString()); dictValues.Add("RJ Heal per tick", Math.Round(Sustained.spellMix.rejuvenate.PeriodicTickwithCrit, 2).ToString()); dictValues.Add("RJ Tick time", Math.Round(Sustained.spellMix.rejuvenate.PeriodicTickTime, 2).ToString()); dictValues.Add("RJ HPS", Math.Round(Sustained.spellMix.rejuvenate.HPS, 2).ToString()); dictValues.Add("RJ HPM", Math.Round(Sustained.spellMix.rejuvenate.HPM, 2).ToString()); dictValues.Add("RJ HPCT", Math.Round(Sustained.spellMix.rejuvenate.HPCT, 2).ToString()); dictValues.Add("RG Heal", Sustained.spellMix.regrowth.ToString()); dictValues.Add("RG Tick", Math.Round(Sustained.spellMix.regrowth.PeriodicTickwithCrit, 2).ToString()); dictValues.Add("RG HPS", Math.Round(Sustained.spellMix.regrowth.HPS, 2).ToString()); dictValues.Add("RG HPS (HoT only)", Math.Round(Sustained.spellMix.regrowth.HPS_HOT, 2).ToString()); dictValues.Add("RG HPM", Math.Round(Sustained.spellMix.regrowth.HPM, 2).ToString()); dictValues.Add("RG HPCT", Math.Round(Sustained.spellMix.regrowth.HPCT, 2).ToString()); dictValues.Add("RG Heal (spam)", Sustained.spellMix.regrowthAgain.ToString()); dictValues.Add("RG HPS (spam)", Math.Round(Sustained.spellMix.regrowthAgain.HPCT_DH, 2).ToString()); dictValues.Add("RG HPM (spam)", Math.Round(Sustained.spellMix.regrowthAgain.HPM_DH, 2).ToString()); dictValues.Add("RG HPCT (spam)", Math.Round(Sustained.spellMix.regrowthAgain.HPCT_DH, 2).ToString()); dictValues.Add("LB Tick", Math.Round(Sustained.spellMix.lifebloom.PeriodicTick, 2).ToString()); dictValues.Add("LB Bloom Heal", Math.Round(Sustained.spellMix.lifebloom.AverageHealingwithCrit, 2).ToString()); dictValues.Add("LB HPS", Math.Round(Sustained.spellMix.lifebloom.HPS, 2).ToString()); dictValues.Add("LB HPS (HoT only)", Math.Round(Sustained.spellMix.lifebloom.HPS_HOT, 2).ToString()); dictValues.Add("LB HPM", Math.Round(Sustained.spellMix.lifebloom.HPM, 2).ToString()); dictValues.Add("LB HPCT", Math.Round(Sustained.spellMix.lifebloom.HPCT, 2).ToString()); dictValues.Add("LBx2 (fast stack) HPS", Math.Round(Sustained.spellMix.lifebloomFast2Stack.HPS, 2).ToString()); dictValues.Add("LBx2 (fast stack) HPM", Math.Round(Sustained.spellMix.lifebloomFast2Stack.HPM, 2).ToString()); dictValues.Add("LBx2 (fast stack) HPCT", Math.Round(Sustained.spellMix.lifebloomFast2Stack.HPCT, 2).ToString()); dictValues.Add("LBx3 (fast stack) HPS", Math.Round(Sustained.spellMix.lifebloomFastStack.HPS, 2).ToString()); dictValues.Add("LBx3 (fast stack) HPM", Math.Round(Sustained.spellMix.lifebloomFastStack.HPM, 2).ToString()); dictValues.Add("LBx3 (fast stack) HPCT", Math.Round(Sustained.spellMix.lifebloomFastStack.HPCT, 2).ToString()); dictValues.Add("LBx2 (slow stack) HPS", Math.Round(Sustained.spellMix.lifebloomSlow2Stack.HPS, 2).ToString()); dictValues.Add("LBx2 (slow stack) HPM", Math.Round(Sustained.spellMix.lifebloomSlow2Stack.HPM, 2).ToString()); dictValues.Add("LBx2 (slow stack) HPCT", Math.Round(Sustained.spellMix.lifebloomSlow2Stack.HPCT, 2).ToString()); dictValues.Add("LBx3 (slow stack) HPS", Math.Round(Sustained.spellMix.lifebloomSlowStack.HPS, 2).ToString()); dictValues.Add("LBx3 (slow stack) HPM", Math.Round(Sustained.spellMix.lifebloomSlowStack.HPM, 2).ToString()); dictValues.Add("LBx3 (slow stack) HPCT", Math.Round(Sustained.spellMix.lifebloomSlowStack.HPCT, 2).ToString()); dictValues.Add("LBx3 (rolling) Tick", Math.Round(Sustained.spellMix.lifebloomRollingStack.PeriodicTick, 2).ToString()); dictValues.Add("LBx3 (rolling) HPS", Math.Round(Sustained.spellMix.lifebloomRollingStack.HPS, 2).ToString()); dictValues.Add("LBx3 (rolling) HPM", Math.Round(Sustained.spellMix.lifebloomRollingStack.HPM, 2).ToString()); dictValues.Add("LBx3 (rolling) HPCT", Math.Round(Sustained.spellMix.lifebloomRollingStack.HPCT, 2).ToString()); dictValues.Add("HT Heal", Sustained.spellMix.healingTouch.ToString()); dictValues.Add("HT HPS", Math.Round(Sustained.spellMix.healingTouch.HPCT_DH, 2).ToString()); dictValues.Add("HT HPM", Math.Round(Sustained.spellMix.healingTouch.HPM_DH, 2).ToString()); dictValues.Add("HT HPCT", Math.Round(Sustained.spellMix.healingTouch.HPCT_DH, 2).ToString()); dictValues.Add("WG first Tick", Math.Round(Sustained.spellMix.wildGrowth.Tick[0], 2).ToString()); dictValues.Add("WG HPS(single target)", Math.Round(Sustained.spellMix.wildGrowth.HPS, 2).ToString()); dictValues.Add("WG HPM(single target)", Math.Round(Sustained.spellMix.wildGrowth.HPM, 2).ToString()); dictValues.Add("WG HPS(max)", Math.Round(Sustained.spellMix.wildGrowth.HPS * Sustained.spellMix.wildGrowth.maxTargets, 2).ToString()); dictValues.Add("WG HPM(max)", Math.Round(Sustained.spellMix.wildGrowth.HPM * Sustained.spellMix.wildGrowth.maxTargets, 2).ToString()); dictValues.Add("N Heal", Sustained.spellMix.nourish[0].ToString()); dictValues.Add("N HPM", Math.Round(Sustained.spellMix.nourish[0].HPM_DH, 2).ToString()); dictValues.Add("N HPS", Math.Round(Sustained.spellMix.nourish[0].HPCT_DH, 2).ToString()); dictValues.Add("N HPCT", Math.Round(Sustained.spellMix.nourish[0].HPCT_DH, 2).ToString()); dictValues.Add("N (1 HoT) Heal", Sustained.spellMix.nourish[1].ToString()); dictValues.Add("N (1 HoT) HPM", Math.Round(Sustained.spellMix.nourish[1].HPM_DH, 2).ToString()); dictValues.Add("N (1 HoT) HPS", Math.Round(Sustained.spellMix.nourish[1].HPCT_DH, 2).ToString()); dictValues.Add("N (1 HoT) HPCT", Math.Round(Sustained.spellMix.nourish[1].HPCT_DH, 2).ToString()); dictValues.Add("N (2 HoTs) Heal", Sustained.spellMix.nourish[2].ToString()); dictValues.Add("N (2 HoTs) HPM", Math.Round(Sustained.spellMix.nourish[2].HPM_DH, 2).ToString()); dictValues.Add("N (2 HoTs) HPS", Math.Round(Sustained.spellMix.nourish[2].HPCT_DH, 2).ToString()); dictValues.Add("N (2 HoTs) HPCT", Math.Round(Sustained.spellMix.nourish[2].HPCT_DH, 2).ToString()); dictValues.Add("N (3 HoTs) Heal", Sustained.spellMix.nourish[3].ToString()); dictValues.Add("N (3 HoTs) HPM", Math.Round(Sustained.spellMix.nourish[3].HPM_DH, 2).ToString()); dictValues.Add("N (3 HoTs) HPS", Math.Round(Sustained.spellMix.nourish[3].HPCT_DH, 2).ToString()); dictValues.Add("N (3 HoTs) HPCT", Math.Round(Sustained.spellMix.nourish[3].HPCT_DH, 2).ToString()); dictValues.Add("N (4 HoTs) Heal", Sustained.spellMix.nourish[4].ToString()); dictValues.Add("N (4 HoTs) HPM", Math.Round(Sustained.spellMix.nourish[4].HPM_DH, 2).ToString()); dictValues.Add("N (4 HoTs) HPS", Math.Round(Sustained.spellMix.nourish[4].HPCT_DH, 2).ToString()); dictValues.Add("N (4 HoTs) HPCT", Math.Round(Sustained.spellMix.nourish[4].HPCT_DH, 2).ToString()); Swiftmend swift = new Swiftmend(LocalCharacter, CombatStats, new Rejuvenation(LocalCharacter, CombatStats), null); dictValues.Add("SM Rejuv Heal", swift.ToString()); dictValues.Add("SM Rejuv HPM", Math.Round(swift.HPM, 2).ToString()); dictValues.Add("SM Rejuv Lost Ticks", Math.Round(swift.rejuvTicksLost, 2).ToString()); swift = new Swiftmend(LocalCharacter, BasicStats, null, new Regrowth(LocalCharacter, BasicStats)); dictValues.Add("SM Regrowth Heal", swift.ToString()); dictValues.Add("SM Regrowth HPM", Math.Round(swift.HPM, 2).ToString()); dictValues.Add("SM Regrowth Lost Ticks", Math.Round(swift.regrowthTicksLost, 2).ToString()); swift = new Swiftmend(LocalCharacter, BasicStats, new Rejuvenation(LocalCharacter, BasicStats), new Regrowth(LocalCharacter, BasicStats)); dictValues.Add("SM Both Heal", swift.ToString()); dictValues.Add("SM Both HPM", Math.Round(swift.HPM, 2).ToString()); dictValues.Add("SM Both Rejuv Lost Ticks", Math.Round(swift.rejuvTicksLost, 2).ToString()); dictValues.Add("SM Both Regrowth Lost Ticks", Math.Round(swift.regrowthTicksLost, 2).ToString()); return(dictValues); }
public static float ArmorReduction(Player player) { return(StatConversion.GetArmorDamageReduction(player.BossOpts.Level, player.Stats.Armor, 0f, 0f)); }
public static float TargetArmorReduction(Player player) { return(StatConversion.GetArmorDamageReduction(player.Character.Level, player.BossOpts.Armor, player.Stats.TargetArmorReduction, 0.0f)); }
public static float TargetArmorReduction(int attackerLevel, float armorPenetration, int targetArmor) { return(StatConversion.GetArmorDamageReduction(attackerLevel, targetArmor, armorPenetration, 0f, 0f)); }
public static float ArmorReduction(Character character, Stats stats, int targetLevel) { return(StatConversion.GetArmorDamageReduction(targetLevel, stats.Armor, 0.0f, 0.0f, 0.0f)); }