private static Tuple <float, float> EvaluateRotation(AbilityCounts counts, BearAbilityBuilder abilities) { float damage = 0f; float threat = 0f; damage += abilities.MeleeStats.DPSTotalAverage * RotationDuration; threat += abilities.MeleeStats.TPSTotalAverage * RotationDuration; damage += abilities.MaulStats.DamageAverage * RotationDuration / 3f; //TODO: Limit this by rage; just assume you maul on cooldown for now threat += abilities.MaulStats.ThreatAverage * RotationDuration / 3f; damage += abilities.FaerieFireStats.DamageAverage * counts.FFF; threat += abilities.FaerieFireStats.ThreatAverage * counts.FFF; damage += abilities.LacerateStats.DamageAverage * counts.Lacerate; threat += abilities.LacerateStats.ThreatAverage * counts.Lacerate; damage += abilities.LacerateStats.DamageTick1Raw * counts.LacerateTick; threat += abilities.LacerateStats.ThreatTick1Raw * counts.LacerateTick; damage += abilities.MangleStats.DamageAverage * counts.Mangle; threat += abilities.MangleStats.ThreatAverage * counts.Mangle; damage += abilities.PulverizeStats.Damage3Average * counts.Pulverize; threat += abilities.PulverizeStats.Threat3Average * counts.FFF; damage += abilities.SwipeStats.DamageAverage * counts.Swipe; threat += abilities.SwipeStats.ThreatAverage * counts.Swipe; damage += abilities.ThrashStats.DamageAverage * counts.Thrash; threat += abilities.ThrashStats.ThreatAverage * counts.Thrash; return(Tuple.Create(damage / RotationDuration, threat / RotationDuration)); }
public static Tuple<BearRotationCalculation, BearRotationCalculation> GetOptimalRotations(BearAbilityBuilder abilities) { int highestDPSRotation = -1; float highestDPSRotationDPS = 0; float highestDPSRotationTPS = 0; int highestTPSRotation = -1; float highestTPSRotationDPS = 0; float highestTPSRotationTPS = 0; for (int i = 0; i < Rotations.Length; i++) { var rotation = Rotations[i]; var dpsTps = EvaluateRotation(rotation.Item2, abilities); if (dpsTps.Item1 > highestDPSRotationDPS) { highestDPSRotation = i; highestDPSRotationDPS = dpsTps.Item1; highestDPSRotationTPS = dpsTps.Item2; } if (dpsTps.Item2 > highestTPSRotationTPS) { highestTPSRotation = i; highestTPSRotationDPS = dpsTps.Item1; highestTPSRotationTPS = dpsTps.Item2; } } return Tuple.Create( highestDPSRotation >= 0 ? new BearRotationCalculation() { Name = BuildRotationName(Rotations[highestDPSRotation].Item1, highestDPSRotationDPS, highestDPSRotationTPS), DPS = highestDPSRotationDPS, TPS = highestDPSRotationTPS } : new BearRotationCalculation() { Name = "None" }, highestTPSRotation >= 0 ? new BearRotationCalculation() { Name = BuildRotationName(Rotations[highestTPSRotation].Item1, highestTPSRotationDPS, highestTPSRotationTPS), DPS = highestTPSRotationDPS, TPS = highestTPSRotationTPS } : new BearRotationCalculation() { Name = "None" } ); }
/// <summary> /// Calculates the threat properties of the Character /// </summary> /// <param name="stats">The total Stats of the character</param> /// <param name="targetLevel">The level of the target</param> /// <param name="calculatedStats">The CharacterCalculationsBear object to fill with results</param> /// <param name="character">The Character to calculate the threat properties of</param> private void CalculateThreat(StatsBear stats, int targetLevel, CharacterCalculationsBear calculatedStats, Character character) { CalculationOptionsBear calcOpts = character.CalculationOptions as CalculationOptionsBear ?? new CalculationOptionsBear(); BossOptions bossOpts = character.BossOptions; if (bossOpts.Attacks.Count < 1) { bossOpts.Attacks.Add(BossHandler.ADefaultMeleeAttack); bossOpts.Attacks[0].IsTheDefaultMelee = true; bossOpts.DamagingTargs = true; } if (bossOpts.DefaultMeleeAttack == null) { bossOpts.Attacks.Add(BossHandler.ADefaultMeleeAttack); bossOpts.Attacks[bossOpts.Attacks.Count - 1].IsTheDefaultMelee = true; bossOpts.DamagingTargs = true; } Attack bossAttack = bossOpts.DefaultMeleeAttack; DruidTalents talents = character.DruidTalents; // Establish base multipliers and chances float modArmor = 1f - StatConversion.GetArmorDamageReduction(character.Level, bossOpts.Armor, stats.TargetArmorReduction, stats.ArmorPenetration); float critMultiplier = 2f * (1 + stats.BonusCritDamageMultiplier); float spellCritMultiplier = 2f * (1 + stats.BonusCritDamageMultiplier); float hasteBonus = StatConversion.GetPhysicalHasteFromRating(stats.HasteRating, CharacterClass.Druid); float attackSpeed = (2.5f) / (1f + hasteBonus); attackSpeed = attackSpeed / (1f + stats.PhysicalHaste); float hitBonus = StatConversion.GetPhysicalHitFromRating(stats.HitRating, CharacterClass.Druid) + stats.PhysicalHit; float expertiseBonus = StatConversion.GetDodgeParryReducFromExpertise(StatConversion.GetExpertiseFromRating(stats.ExpertiseRating, CharacterClass.Druid) + stats.Expertise, CharacterClass.Druid); float spellHitBonus = StatConversion.GetSpellHitFromRating(stats.HitRating, CharacterClass.Druid) + stats.SpellHit; int levelDifference = (targetLevel - character.Level); float chanceDodge = Math.Max(0f, StatConversion.WHITE_DODGE_CHANCE_CAP[levelDifference] - expertiseBonus); float chanceParry = Math.Max(0f, StatConversion.WHITE_PARRY_CHANCE_CAP[levelDifference] - expertiseBonus); float chanceMiss = Math.Max(0f, StatConversion.WHITE_MISS_CHANCE_CAP[levelDifference] - hitBonus); float chanceResist = Math.Max(0f, StatConversion.GetSpellMiss(-levelDifference, false) - spellHitBonus); float chanceGlance = StatConversion.WHITE_GLANCE_CHANCE_CAP[levelDifference]; //0.2335774f; //float glanceMultiplier = 0.7f; float chanceAvoided = chanceMiss + chanceDodge + chanceParry; float rawChanceCrit = StatConversion.GetPhysicalCritFromRating(stats.CritRating, CharacterClass.Druid) + StatConversion.GetPhysicalCritFromAgility(stats.Agility, CharacterClass.Druid) + stats.PhysicalCrit + StatConversion.NPC_LEVEL_CRIT_MOD[levelDifference]; float chanceCrit = rawChanceCrit * (1f - chanceAvoided); float rawChanceCritSpell = StatConversion.GetSpellCritFromRating(stats.CritRating, CharacterClass.Druid) + StatConversion.GetSpellCritFromIntellect(stats.Intellect, CharacterClass.Druid) + stats.SpellCrit + stats.SpellCritOnTarget + StatConversion.NPC_LEVEL_CRIT_MOD[levelDifference]; float chanceCritSpell = rawChanceCritSpell * (1f - chanceResist); calculatedStats.DodgedAttacks = chanceDodge; calculatedStats.ParriedAttacks = chanceParry; calculatedStats.MissedAttacks = chanceMiss; float movementdowntime = 3f / 5.5f / (1 + stats.MovementSpeed); // Movement Duration / Movement Frequency / (1 + Movement Speed) BearAbilityBuilder abilities = new BearAbilityBuilder(stats, character.MainHand == null ? 0.75f : ((character.MainHand.MinDamage + character.MainHand.MaxDamage) / 2f) / character.MainHand.Speed, attackSpeed, modArmor, chanceAvoided, chanceResist, chanceCrit, chanceCritSpell, chanceGlance, critMultiplier, spellCritMultiplier); var optimalRotations = BearRotationCalculator.GetOptimalRotations(abilities); calculatedStats.Abilities = abilities; calculatedStats.HighestDPSRotation = optimalRotations.Item1; float bonusdamage = stats.ArcaneDamage + stats.FireDamage + stats.FrostDamage + stats.NatureDamage + stats.ShadowDamage + stats.HolyDamage + stats.PhysicalDamage; calculatedStats.HighestDPSRotation.DPS += bonusdamage; calculatedStats.HighestDPSRotation.DPS *= 1 - movementdowntime; calculatedStats.HighestTPSRotation = optimalRotations.Item2; calculatedStats.HighestTPSRotation.TPS += bonusdamage * 5f; calculatedStats.HighestTPSRotation.TPS *= 1 - movementdowntime; calculatedStats.ThreatPoints = calculatedStats.HighestTPSRotation.TPS * calcOpts.ThreatScale / 10f; }
public static Tuple <BearRotationCalculation, BearRotationCalculation> GetOptimalRotations(BearAbilityBuilder abilities) { int highestDPSRotation = -1; float highestDPSRotationDPS = 0; float highestDPSRotationTPS = 0; int highestTPSRotation = -1; float highestTPSRotationDPS = 0; float highestTPSRotationTPS = 0; for (int i = 0; i < Rotations.Length; i++) { var rotation = Rotations[i]; var dpsTps = EvaluateRotation(rotation.Item2, abilities); if (dpsTps.Item1 > highestDPSRotationDPS) { highestDPSRotation = i; highestDPSRotationDPS = dpsTps.Item1; highestDPSRotationTPS = dpsTps.Item2; } if (dpsTps.Item2 > highestTPSRotationTPS) { highestTPSRotation = i; highestTPSRotationDPS = dpsTps.Item1; highestTPSRotationTPS = dpsTps.Item2; } } return(Tuple.Create( highestDPSRotation >= 0 ? new BearRotationCalculation() { Name = BuildRotationName(Rotations[highestDPSRotation].Item1, highestDPSRotationDPS, highestDPSRotationTPS), DPS = highestDPSRotationDPS, TPS = highestDPSRotationTPS } : new BearRotationCalculation() { Name = "None" }, highestTPSRotation >= 0 ? new BearRotationCalculation() { Name = BuildRotationName(Rotations[highestTPSRotation].Item1, highestTPSRotationDPS, highestTPSRotationTPS), DPS = highestTPSRotationDPS, TPS = highestTPSRotationTPS } : new BearRotationCalculation() { Name = "None" } )); }
private static Tuple<float,float> EvaluateRotation(AbilityCounts counts, BearAbilityBuilder abilities) { float damage = 0f; float threat = 0f; damage += abilities.MeleeStats.DPSTotalAverage * RotationDuration; threat += abilities.MeleeStats.TPSTotalAverage * RotationDuration; damage += abilities.MaulStats.DamageAverage * RotationDuration / 3f; //TODO: Limit this by rage; just assume you maul on cooldown for now threat += abilities.MaulStats.ThreatAverage * RotationDuration / 3f; damage += abilities.FaerieFireStats.DamageAverage * counts.FFF; threat += abilities.FaerieFireStats.ThreatAverage * counts.FFF; damage += abilities.LacerateStats.DamageAverage * counts.Lacerate; threat += abilities.LacerateStats.ThreatAverage * counts.Lacerate; damage += abilities.LacerateStats.DamageTick1Raw * counts.LacerateTick; threat += abilities.LacerateStats.ThreatTick1Raw * counts.LacerateTick; damage += abilities.MangleStats.DamageAverage * counts.Mangle; threat += abilities.MangleStats.ThreatAverage * counts.Mangle; damage += abilities.PulverizeStats.Damage3Average * counts.Pulverize; threat += abilities.PulverizeStats.Threat3Average * counts.FFF; damage += abilities.SwipeStats.DamageAverage * counts.Swipe; threat += abilities.SwipeStats.ThreatAverage * counts.Swipe; damage += abilities.ThrashStats.DamageAverage * counts.Thrash; threat += abilities.ThrashStats.ThreatAverage * counts.Thrash; return Tuple.Create(damage / RotationDuration, threat / RotationDuration); }