예제 #1
0
 public override string ToString()
 {
     return(string.Format("DPE: {0:N0}  Dmg: {1:N0}*{2}", (DamageTickAverage * Duration / 2f) / EnergyCost, (DamageTickAverage * Duration / 2f),
                          CatAbilityBuilder.BuildTooltip(
                              "Damage Per Tick Hit", DamageTickRaw,
                              "Damage Per Average Tick", DamageTickAverage,
                              "Damage Per Energy", (DamageTickAverage * Duration / 2f) / EnergyCost
                              )));
 }
예제 #2
0
 public override string ToString()
 {
     return(string.Format("DPE: {0:N1}  Dmg: {1:N0}*{2}", DamageAverage / EnergyCost, DamageAverage,
                          CatAbilityBuilder.BuildTooltip(
                              "Damage Per Hit", DamageRaw,
                              "Damage Per Landed Attack", DamageAverage,
                              "Damage Per Energy", DamageAverage / EnergyCost
                              )));
 }
예제 #3
0
 public override string ToString()
 {
     return(string.Format("DPS: {0:N0}*{1}", DPSRoarAverage + DPSFurySwipesAverage,
                          CatAbilityBuilder.BuildTooltip(
                              "Damage Per Hit", DamageRaw,
                              "Damage Per Swing", DamageAverage,
                              "Damage Per Hit w/ Savage Roar", DamageRoarRaw,
                              "Damage Per Swing w/ Savage Roar", DamageRoarAverage,
                              "Damage Per Fury Swipes Hit", DamageFurySwipesRaw,
                              "Damage Per Fury Swipes Swing", DamageFurySwipesAverage
                              )));
 }
예제 #4
0
 public override string ToString()
 {
     return(string.Format("DPE: {0:N0}  Dmg: {1:N0}*{2}", DamageAverage / 10f, DamageAverage,
                          CatAbilityBuilder.BuildTooltip(
                              "Damage Per Hit", DamageRaw,
                              "Damage Per Landed Attack", DamageAverage,
                              "Damage Per Landed Attack Above 80%", DamageAbove80PercentAverage,
                              "Damage Per Energy", DamageAverage / EnergyCost,
                              "Damage Per Energy Above 80%", DamageAbove80PercentAverage / EnergyCost,
                              "Damage Per Energy w/ Stampede", DamageAverage / 10f,
                              "Damage Per Energy Above 80% w/ Stampede", DamageAbove80PercentAverage / 10f
                              )));
 }
예제 #5
0
		public CatRotationCalculator(CatAbilityBuilder abilities, int fightDuration, MangleUsage mangleUsage)
		{
			Abilities = abilities;
			FightDuration = fightDuration;
			MangleUsage = mangleUsage;

			float chanceExtraCPPerHit = abilities.ShredStats.ComboPointsGenerated - 1f;
			float c = chanceExtraCPPerHit, h = (1f - chanceExtraCPPerHit);
			_chanceExtraCP[0] = c;
			_chanceExtraCP[1] = c * h;
			_chanceExtraCP[2] = c * c + c * h * h;
			_chanceExtraCP[3] = 2 * c * c * h + c * h * h * h;
			_chanceExtraCP[4] = c * c * c + 3 * c * c * h * h + c * h * h * h * h;
		}
예제 #6
0
        public CatRotationCalculator(CatAbilityBuilder abilities, int fightDuration, MangleUsage mangleUsage)
        {
            Abilities     = abilities;
            FightDuration = fightDuration;
            MangleUsage   = mangleUsage;

            float chanceExtraCPPerHit = abilities.ShredStats.ComboPointsGenerated - 1f;
            float c = chanceExtraCPPerHit, h = (1f - chanceExtraCPPerHit);

            _chanceExtraCP[0] = c;
            _chanceExtraCP[1] = c * h;
            _chanceExtraCP[2] = c * c + c * h * h;
            _chanceExtraCP[3] = 2 * c * c * h + c * h * h * h;
            _chanceExtraCP[4] = c * c * c + 3 * c * c * h * h + c * h * h * h * h;
        }
예제 #7
0
        public override CharacterCalculationsBase GetCharacterCalculations(Character character, Item additionalItem, bool referenceCalculation, bool significantChange, bool needsDisplayCalculations)
        {
            // First things first, we need to ensure that we aren't using bad data
            CharacterCalculationsCat calculatedStats = new CharacterCalculationsCat();
            if (character == null) { return calculatedStats; }
            CalculationOptionsCat calcOpts = character.CalculationOptions as CalculationOptionsCat;
            if (calcOpts == null) { return calculatedStats; }
            BossOptions bossOpts = character.BossOptions;
            if (bossOpts == null) { return calculatedStats; }
            
            int targetLevel = bossOpts.Level;
            int characterLevel = character.Level;
            float lagVariance = (float)calcOpts.LagVariance / 1000f;
            StatsCat stats = GetCharacterStats(character, additionalItem) as StatsCat;
            int levelDifference = (targetLevel - characterLevel);
            calculatedStats.BasicStats = stats;
            calculatedStats.TargetLevel = targetLevel;
            bool maintainMangleBecauseNooneElseIs = !character.ActiveBuffsConflictingBuffContains("Bleed Damage");
            int T11Count;
            character.SetBonusCount.TryGetValue("Stormrider's Battlegarb", out T11Count);
            MangleUsage mangleusage = maintainMangleBecauseNooneElseIs ? MangleUsage.MaintainMangle : MangleUsage.None;
            if (calcOpts.CustomUseMangle && T11Count >= 4) { mangleusage = MangleUsage.Maintain4T11; }
     //       else if (calcOpts.CustomUseMangle) { mangleusage = MangleUsage.MangleDPS; }
            if (mangleusage != MangleUsage.None) {
                stats.BonusBleedDamageMultiplier = (1f + stats.BonusBleedDamageMultiplier)
                    * (1f + (maintainMangleBecauseNooneElseIs ? 0.30f : 0f)) // if someone else is putting up mangle, don't try to add to it here as it won't stack
                    - 1f;
            }

            #region Basic Chances and Constants
            float modArmor = 1f - StatConversion.GetArmorDamageReduction(character.Level, bossOpts.Armor,
                stats.TargetArmorReduction, stats.ArmorPenetration);
            
            float critMultiplier = 2f * (1f + stats.BonusCritDamageMultiplier);
            float hasteBonus = StatConversion.GetPhysicalHasteFromRating(stats.HasteRating, CharacterClass.Druid);
            float attackSpeed = (1f / (1f + hasteBonus)) / (1f + stats.PhysicalHaste);
            float energyPerSecond = 10f * (1f + hasteBonus);

            float hitBonus = stats.PhysicalHit + StatConversion.GetPhysicalHitFromRating(stats.HitRating, CharacterClass.Druid);
            float expertiseBonus = StatConversion.GetDodgeParryReducFromExpertise(StatConversion.GetExpertiseFromRating(stats.ExpertiseRating, CharacterClass.Druid) + stats.Expertise, CharacterClass.Druid);
            float masteryBonus = StatConversion.GetMasteryFromRating(stats.MasteryRating, CharacterClass.Druid) + 8f;
            stats.NonShredBleedDamageMultiplier = masteryBonus * 0.031f;

            float chanceDodge = Math.Max(0f, StatConversion.WHITE_DODGE_CHANCE_CAP[targetLevel - 85] - expertiseBonus);
            float chanceMiss = Math.Max(0f, StatConversion.WHITE_MISS_CHANCE_CAP[targetLevel - 85] - hitBonus);
            float chanceAvoided = chanceMiss + chanceDodge;

            //Crit Chances
            float chanceCritYellow = 0f;
            float chanceCritBite = 0f;
            float chanceCritRip = 0f;
            float chanceCritRake = 0f;
            float chanceGlance = 0f;
            float chanceCritWhite = 0f;

            for (int i = 0; i < stats.TemporaryCritRatingUptimes.Length; i++)
            { //Sum up the weighted chances for each crit value
                WeightedStat iStat = stats.TemporaryCritRatingUptimes[i];

                //Yellow - 2 Roll, so total of X chance to avoid, total of 1 chance to crit and hit when not avoided
                float chanceCritYellowTemp = Math.Min(1f, StatConversion.GetCritFromRating(stats.CritRating + iStat.Value, CharacterClass.Druid)
                    + StatConversion.GetCritFromAgility(stats.Agility, CharacterClass.Druid)
                    + stats.PhysicalCrit
                    + StatConversion.NPC_LEVEL_CRIT_MOD[targetLevel - 85]);
                //float chanceHitYellowTemp = 1f - chanceCritYellowTemp;
                //float cpPerCPG = chanceHitYellow + chanceCritYellow * (1f + stats.CPOnCrit);

                //Bite - Identical to Yellow, with higher crit chance
                float chanceCritBiteTemp = Math.Min(1f, chanceCritYellowTemp + character.DruidTalents.RendAndTear * 0.25f / 3f);
                //float chanceHitBiteTemp = 1f - chanceCritBiteTemp;

                //Bleeds - 1 Roll, no avoidance, total of 1 chance to crit and hit
                float chanceCritRipTemp = Math.Min(1f, chanceCritYellowTemp);
                float chanceCritRakeTemp = Math.Min(1f, chanceCritYellowTemp);

                //White
                float chanceGlanceTemp = StatConversion.WHITE_GLANCE_CHANCE_CAP[targetLevel - 85];
                float chanceCritWhiteTemp = Math.Min(chanceCritYellowTemp, 1f - chanceGlanceTemp - chanceAvoided);
                //float chanceHitWhiteTemp = 1f - chanceCritWhiteTemp - chanceAvoided - chanceGlanceTemp;


                chanceCritYellow += iStat.Chance * chanceCritYellowTemp;
                chanceCritBite += iStat.Chance * chanceCritBiteTemp;
                chanceCritRip += iStat.Chance * chanceCritRipTemp;
                chanceCritRake += iStat.Chance * chanceCritRakeTemp;
                chanceGlance += iStat.Chance * chanceGlanceTemp;
                chanceCritWhite += iStat.Chance * chanceCritWhiteTemp;
            }
            #endregion

            #region Attack Damages
            /* 
            float baseDamage = 55f + (stats.AttackPower / 14f) + stats.WeaponDamage;
            float meleeDamageRaw = (baseDamage) * (1f + stats.BonusPhysicalDamageMultiplier) * (1f + stats.BonusDamageMultiplier) * modArmor;
            float mangleDamageRaw = (baseDamage * 2f + 566f) * (1f + stats.BonusPhysicalDamageMultiplier) * (1f + stats.BonusDamageMultiplier) * (1f + stats.BonusMangleDamageMultiplier) * modArmor;
            float shredDamageRaw = (baseDamage * 2.25f + 666f + stats.BonusShredDamage) * (1f + stats.BonusPhysicalDamageMultiplier) * (1f + stats.BonusDamageMultiplier) * (1f + stats.BonusShredDamageMultiplier) * (1f + stats.BonusBleedDamageMultiplier) * modArmor;
            float rakeDamageRaw = (176f + stats.AttackPower * 0.01f) * (1f + stats.BonusPhysicalDamageMultiplier) * (1f + stats.BonusDamageMultiplier) * (1f + stats.BonusRakeDamageMultiplier) * (1f + stats.BonusBleedDamageMultiplier);
            float rakeDamageDot = (1074f + stats.AttackPower * 0.18f) * (1f + stats.BonusPhysicalDamageMultiplier) * (1f + stats.BonusDamageMultiplier) * (1f + stats.BonusRakeDamageMultiplier) * (1f + stats.BonusBleedDamageMultiplier) * ((9f + stats.BonusRakeDuration) / 9f);
            float ripDamageRaw = (3006f + stats.AttackPower * 0.3f + (stats.BonusRipDamagePerCPPerTick * 5f * 6f)) * (1f + stats.BonusPhysicalDamageMultiplier) * (1f + stats.BonusDamageMultiplier) * (1f + stats.BonusRipDamageMultiplier) * (1f + stats.BonusBleedDamageMultiplier);
            float biteBaseDamageRaw = 190f * (1f + stats.BonusPhysicalDamageMultiplier) * (1f + stats.BonusDamageMultiplier) * (1f + stats.BonusFerociousBiteDamageMultiplier) * modArmor;
            float biteCPDamageRaw = (290f + stats.AttackPower * 0.07f) * (1f + stats.BonusPhysicalDamageMultiplier) * (1f + stats.BonusDamageMultiplier) * (1f + stats.BonusFerociousBiteDamageMultiplier) * modArmor;

            float meleeDamageAverage = chanceGlance * meleeDamageRaw * glanceMultiplier +
                                        chanceCritWhite * meleeDamageRaw * critMultiplier +
                                        chanceHitWhite * meleeDamageRaw;
            float mangleDamageAverage = (1f - chanceCritYellow) * mangleDamageRaw + chanceCritYellow * mangleDamageRaw * critMultiplier;
            float shredDamageAverage = (1f - chanceCritYellow) * shredDamageRaw + chanceCritYellow * shredDamageRaw * critMultiplier;
            float rakeDamageAverage = ((1f - chanceCritYellow) * rakeDamageRaw + chanceCritYellow * rakeDamageRaw * critMultiplier) + ((1f - chanceCritRake) * rakeDamageDot + chanceCritRake * rakeDamageDot * critMultiplierBleed);
            float ripDamageAverage = ((1f - chanceCritRip) * ripDamageRaw + chanceCritRip * ripDamageRaw * critMultiplierBleed);
            float biteBaseDamageAverage = (1f - chanceCritBite) * biteBaseDamageRaw + chanceCritBite * biteBaseDamageRaw * critMultiplier;
            float biteCPDamageAverage = (1f - chanceCritBite) * biteCPDamageRaw + chanceCritBite * biteCPDamageRaw * critMultiplier;

            //if (needsDisplayCalculations)
            //{
            //    Console.WriteLine("White:    {0:P} Avoided, {1:P} Glance,      {2:P} Hit, {3:P} Crit - Swing: {4}", chanceAvoided, chanceGlance, chanceHitWhite, chanceCritWhite, meleeDamageAverage);
            //    Console.WriteLine("Yellow:   {0:P} Avoided, {1:P} NonAvoided,  {2:P} Hit, {3:P} Crit - Swing: {4}", chanceAvoided, chanceNonAvoided, 1f - chanceCritYellow, chanceCritYellow, mangleDamageAverage);
            //    Console.WriteLine("Bite:     {0:P} Avoided, {1:P} NonAvoided,  {2:P} Hit, {3:P} Crit - Swing: {4}", chanceAvoided, chanceNonAvoided, 1f - chanceCritBite, chanceCritBite, biteBaseDamageAverage);
            //    Console.WriteLine("RipBleed:                                      {0:P} Hit, {1:P} Crit - Swing: {2}", 1f - chanceCritRip, chanceCritRip, ripDamageAverage);
            //    Console.WriteLine();
            //}
            #endregion

            #region Energy Costs
            float mangleEnergyRaw = 45f - stats.MangleCatCostReduction;
            float shredEnergyRaw = 60f - stats.ShredCostReduction;
            float rakeEnergyRaw = 40f - stats.RakeCostReduction;
            float ripEnergyRaw = 30f - stats.RipCostReduction;
            float biteEnergyRaw = 35f; //Assuming no wasted energy
            float roarEnergyRaw = 25f;

            //[rawCost + ((1/chance_to_land) - 1) * rawCost/5] 
            float cpgEnergyCostMultiplier = 1f + ((1f / chanceNonAvoided) - 1f) * 0.2f;
            float finisherEnergyCostMultiplier = 1f + ((1f / chanceNonAvoided) - 1f) * (1f - stats.FinisherEnergyOnAvoid);
            float mangleEnergyAverage = mangleEnergyRaw * cpgEnergyCostMultiplier;
            float shredEnergyAverage = shredEnergyRaw * cpgEnergyCostMultiplier;
            float rakeEnergyAverage = rakeEnergyRaw * cpgEnergyCostMultiplier;
            float ripEnergyAverage = ripEnergyRaw * finisherEnergyCostMultiplier;
            float biteEnergyAverage = biteEnergyRaw * finisherEnergyCostMultiplier;
            float roarEnergyAverage = roarEnergyRaw;
            #endregion

            #region Ability Stats
            CatAbilityStats meleeStats = new CatMeleeStats()
            {
                DamagePerHit = meleeDamageRaw,
                DamagePerSwing = meleeDamageAverage,
            };
            CatAbilityStats mangleStats = new CatMangleStats()
            {
                DamagePerHit = mangleDamageRaw,
                DamagePerSwing = mangleDamageAverage,
                DurationUptime = mangleDurationUptime,
                DurationAverage = mangleDurationAverage,
                EnergyCost = mangleEnergyAverage,
            };
            CatAbilityStats shredStats = new CatShredStats()
            {
                DamagePerHit = shredDamageRaw,
                DamagePerSwing = shredDamageAverage,
                EnergyCost = shredEnergyAverage,
            };
            CatAbilityStats rakeStats = new CatRakeStats()
            {
                DamagePerHit = rakeDamageRaw + rakeDamageDot,
                DamagePerSwing = rakeDamageAverage,
                DurationUptime = rakeDurationUptime,
                DurationAverage = rakeDurationAverage,
                EnergyCost = rakeEnergyAverage,
            };
            CatAbilityStats ripStats = new CatRipStats()
            {
                DamagePerHit = ripDamageRaw,
                DamagePerSwing = ripDamageAverage,
                DurationUptime = ripDurationUptime,
                DurationAverage = ripDurationAverage,
                EnergyCost = ripEnergyAverage,
            };
            CatAbilityStats biteStats = new CatBiteStats()
            {
                DamagePerHit = biteBaseDamageRaw,
                DamagePerSwing = biteBaseDamageAverage,
                DamagePerHitPerCP = biteCPDamageRaw,
                DamagePerSwingPerCP = biteCPDamageAverage,
                EnergyCost = biteEnergyAverage,
            };
            CatAbilityStats roarStats = new CatRoarStats()
            {
                DurationUptime = roarBonusDuration,
                DurationAverage = 9f + roarBonusDuration,
                EnergyCost = roarEnergyAverage,
                DurationPerCP = 5f,
            };
            */
            #endregion

            #region Rotations
            CatAbilityBuilder abilities = new CatAbilityBuilder(stats, character.DruidTalents,
                character.MainHand == null ? 0.75f : 
                ((character.MainHand.MinDamage + character.MainHand.MaxDamage) / 2f) / character.MainHand.Speed,
                attackSpeed, modArmor, hasteBonus, critMultiplier, chanceAvoided, chanceCritWhite, chanceCritYellow, chanceCritYellow,
                chanceCritYellow, chanceCritYellow, chanceCritRake, chanceCritRip, chanceCritBite, chanceGlance);
            var rotationCalculator = new CatRotationCalculator(abilities, 750/*bossOpts.BerserkTimer*/, mangleusage);
            var optimalRotation = rotationCalculator.GetOptimalRotation(); //TODO: Check for 4T11, maintain it if so
            calculatedStats.Abilities = abilities;
            calculatedStats.HighestDPSRotation = optimalRotation;

            //CatRotationCalculator rotationCalculator = new CatRotationCalculator(stats, calcOpts.Duration, cpPerCPG,
            //    maintainMangle, berserkDuration, attackSpeed,
            //    true,
            //    character.DruidTalents.GlyphOfShred, chanceAvoided, chanceCritYellow * stats.BonusCPOnCrit,
            //    cpgEnergyCostMultiplier, stats.ClearcastOnBleedChance, meleeStats, mangleStats, shredStats,
            //    rakeStats, ripStats, biteStats, roarStats);
            //CatRotationCalculator.CatRotationCalculation rotationCalculationDPS = new CatRotationCalculator.CatRotationCalculation();

            //for (int roarCP = 1; roarCP < 6; roarCP++)
            //    for (int biteCP = 0; biteCP < 6; biteCP++)
            //        for (int useRake = 0; useRake < 2; useRake++)
            //            for (int useShred = 0; useShred < 2; useShred++)
            //                for (int useRip = 0; useRip < 2; useRip++)
            //                {
            //                    CatRotationCalculator.CatRotationCalculation rotationCalculation =
            //                        rotationCalculator.GetRotationCalculations(
            //                        useRake == 1, useShred == 1, useRip == 1, biteCP, roarCP);
            //                    if (rotationCalculation.DPS > rotationCalculationDPS.DPS)
            //                        rotationCalculationDPS = rotationCalculation;
            //                }

            //calculatedStats.HighestDPSRotation = rotationCalculationDPS;
            //calculatedStats.CustomRotation = rotationCalculator.GetRotationCalculations(
            //    calcOpts.CustomUseRake, calcOpts.CustomUseShred, calcOpts.CustomUseRip, calcOpts.CustomCPFerociousBite, calcOpts.CustomCPSavageRoar);

            //if (character.DruidTalents.GlyphOfShred && rotationCalculationDPS.ShredCount > 0)
            //{
            //    ripStats.DurationUptime += 6f;
            //    ripStats.DurationAverage += 6f;
            //}
            //ripStats.DamagePerHit *= ripStats.DurationUptime / 12f;
            //ripStats.DamagePerSwing *= ripStats.DurationUptime / 12f;
            #endregion

            calculatedStats.AvoidedAttacks = chanceAvoided * 100f;
            calculatedStats.DodgedAttacks = chanceDodge * 100f;
            calculatedStats.MissedAttacks = chanceMiss * 100f;
            calculatedStats.CritChance = chanceCritYellow * 100f;
            calculatedStats.AttackSpeed = attackSpeed;
            calculatedStats.ArmorMitigation = (1f - modArmor) * 100f;
            calculatedStats.Duration = bossOpts.BerserkTimer;


            float magicDPS = (stats.ShadowDamage + stats.ArcaneDamage + stats.NatureDamage + stats.FireDamage + stats.FrostDamage) * (1f + chanceCritYellow);
            float physicalDPS = stats.PhysicalDamage;
            float abomDPS = (stats.MoteOfAnger * abilities.MeleeStats.DamageAverage);
            calculatedStats.DPSPoints = calculatedStats.HighestDPSRotation.DPS + magicDPS + physicalDPS + abomDPS;
            calculatedStats.SurvivabilityPoints = stats.Health / 1000f;
            calculatedStats.OverallPoints = calculatedStats.DPSPoints + calculatedStats.SurvivabilityPoints;
            return calculatedStats;
        }