Example #1
0
        /// <summary>
        /// Calculates the solution by combining subsolutions with and withou Bloodlust
        /// </summary>
        private static RotationSolution GetCombinedSolutionWithBloodlust(
            CombatStats combats,
            Ability[] rotation,
            decimal simulationTime)
        {
            const float bloodlustDuration = 40f;
            const float secondsPerMinute  = 60f;
            const float bloodlustHaste    = 0.3f;

            // in seconds
            float fightLengthWithBloodlust = combats.CalcOpts.Bloodlust ?
                                             Math.Min(combats.CalcOpts.FightLength * secondsPerMinute, bloodlustDuration) :
                                             0;
            // in seconds
            float fightLengthWithoutBloodlust =
                Math.Max(0, combats.CalcOpts.FightLength * secondsPerMinute - fightLengthWithBloodlust);

            float bloodlustSpellHaste = (1 + combats.Stats.SpellHaste) * (1 + bloodlustHaste) - 1;

            float normalSwingTime    = combats.BaseWeaponSpeed / (1 + combats.Stats.PhysicalHaste);
            float bloodlustSwingTime = normalSwingTime / (1 + bloodlustHaste);

            return(RotationSolution.Combine(
                       () => GetCombinedSolutionWithDivineStormCooldown(
                           combats,
                           rotation,
                           simulationTime,
                           combats.Stats.SpellHaste,
                           normalSwingTime),
                       fightLengthWithoutBloodlust,
                       () => GetCombinedSolutionWithDivineStormCooldown(
                           combats,
                           rotation,
                           simulationTime,
                           bloodlustSpellHaste,
                           bloodlustSwingTime),
                       fightLengthWithBloodlust));
        }
Example #2
0
 /// <summary>
 /// Calculates the solution by combining subsolutions with the boss above and under 20% health
 /// </summary>
 private static RotationSolution GetCombinedSolutionWithUnder20PercentHealth(
     CombatStats combats,
     Ability[] rotation,
     decimal simulationTime,
     float divineStormCooldown,
     float spellHaste)
 {
     return(RotationSolution.Combine(
                () => GetSolution(
                    combats,
                    RemoveHammerOfWrathFromRotation(rotation),
                    simulationTime,
                    divineStormCooldown,
                    spellHaste),
                1 - combats.CalcOpts.TimeUnder20,
                () => GetSolution(
                    combats,
                    rotation,
                    simulationTime,
                    divineStormCooldown,
                    spellHaste),
                combats.CalcOpts.TimeUnder20));
 }
Example #3
0
        public static RotationSolution Combine(
            RotationSolution solution1,
            float solution1Weight,
            RotationSolution solution2,
            float solution2Weight)
        {
            RotationSolution result = new RotationSolution();

            for (int ability = 0; ability <= (int)Ability.Last; ability++)
            {
                result.abilityUsagesPerSecond[ability] = Utilities.GetWeightedSum(
                    solution1.abilityUsagesPerSecond[ability],
                    solution1Weight,
                    solution2.abilityUsagesPerSecond[ability],
                    solution2Weight);

                // Zero CD means the ability is not in rotation
                if (solution1.abilityEffectiveCooldowns[ability] == 0)
                {
                    result.abilityEffectiveCooldowns[ability] = solution2.abilityEffectiveCooldowns[ability];
                }
                else if (solution2.abilityEffectiveCooldowns[ability] == 0)
                {
                    result.abilityEffectiveCooldowns[ability] = solution1.abilityEffectiveCooldowns[ability];
                }
                else
                {
                    result.abilityEffectiveCooldowns[ability] = 1 / Utilities.GetWeightedSum(
                        1 / solution1.abilityEffectiveCooldowns[ability],
                        solution1Weight,
                        1 / solution2.abilityEffectiveCooldowns[ability],
                        solution2Weight);
                }
            }

            return(result);
        }
Example #4
0
        /// <summary>
        /// Calculates the solution by combining subsolutions with different Divine Storm cooldowns,
        /// if 2 piece T10 bonus is active.
        /// </summary>
        private static RotationSolution GetCombinedSolutionWithDivineStormCooldown(
            CombatStats combats,
            Ability[] rotation,
            decimal simulationTime,
            float spellHaste,
            float swingTime)
        {
            const float normalDivineStormCooldown = 10;
            const float cooldownRangeStep         = 0.6f;

            if (combats.Stats.DivineStormRefresh == 0)
            {
                return(GetCombinedSolutionWithUnder20PercentHealth(
                           combats,
                           rotation,
                           simulationTime,
                           normalDivineStormCooldown,
                           spellHaste));
            }

            // Calculate solutions for different Divine Storm cooldowns
            // and combine them weighted by their neighbourhood cooldown range probabilities
            RotationSolution result            = null;
            float            resultProbability = 0;

            for (
                float cooldownRangeStart = 0;
                cooldownRangeStart < normalDivineStormCooldown;
                cooldownRangeStart += cooldownRangeStep)
            {
                float currentSolutionProbability =
                    GetT10DivineStormCooldownProbability(
                        swingTime,
                        cooldownRangeStart,
                        Math.Min(normalDivineStormCooldown, cooldownRangeStart + cooldownRangeStep),
                        combats.Stats.DivineStormRefresh);
                result = RotationSolution.Combine(
                    () => result,
                    resultProbability,
                    () => GetCombinedSolutionWithUnder20PercentHealth(
                        combats,
                        rotation,
                        simulationTime,
                        Math.Min(
                            normalDivineStormCooldown,
                            cooldownRangeStart + cooldownRangeStart / 2 + combats.CalcOpts.Delay),
                        spellHaste),
                    currentSolutionProbability);
                resultProbability += currentSolutionProbability;
            }

            // Combine with normal Divine Storm cooldown in cases when T10 doesn't proc
            return(RotationSolution.Combine(
                       () => result,
                       resultProbability,
                       () => GetCombinedSolutionWithUnder20PercentHealth(
                           combats,
                           rotation,
                           simulationTime,
                           normalDivineStormCooldown,
                           spellHaste),
                       1 - resultProbability));
        }
Example #5
0
        private static RotationSolution SimulateRotationCore(SimulatorParameters rot)
        {
            const int timeUnitsPerSecond = 100000;
            const int meleeAbilityGcd    = (int)(1.5m * timeUnitsPerSecond);

            int fightLength = (int)(rot.SimulationTime * timeUnitsPerSecond);
            int spellGcd    = (int)(rot.SpellGCD * timeUnitsPerSecond);

            SimulatorAbility.Delay = (int)(rot.Delay * timeUnitsPerSecond);
            SimulatorAbility.Wait  = (int)(rot.Wait * timeUnitsPerSecond);

            SimulatorAbility[] abilities = new SimulatorAbility[(int)Ability.Last + 1];

            abilities[(int)Ability.Judgement] = new SimulatorAbility(
                (10 - rot.ImpJudgements - (rot.T7_4pc ? 1 : 0)) * timeUnitsPerSecond,
                meleeAbilityGcd);
            abilities[(int)Ability.CrusaderStrike] = new SimulatorAbility(
                4 * timeUnitsPerSecond,
                meleeAbilityGcd);
            abilities[(int)Ability.DivineStorm] = new SimulatorAbility(
                (int)(rot.DivineStormCooldown * timeUnitsPerSecond),
                meleeAbilityGcd);
            abilities[(int)Ability.Consecration] = new SimulatorAbility(
                (rot.GlyphConsecrate ? 10 : 8) * timeUnitsPerSecond,
                spellGcd);
            abilities[(int)Ability.Exorcism] = new SimulatorAbility(
                15 * timeUnitsPerSecond,
                spellGcd);
            abilities[(int)Ability.HammerOfWrath] = new SimulatorAbility(
                6 * timeUnitsPerSecond,
                meleeAbilityGcd);

            int gcdFinishTime = 0;
            int currentTime   = 0;

            while (currentTime < fightLength)
            {
                if (currentTime >= gcdFinishTime)
                {
                    foreach (Ability ability in rot.Priorities)
                    {
                        if (abilities[(int)ability].ShouldAbilityBeUsedNext(currentTime))
                        {
                            if (abilities[(int)ability].CanAbilityBeUsedNow(currentTime))
                            {
                                gcdFinishTime = abilities[(int)ability].UseAbility(currentTime);
                            }

                            break;
                        }
                    }
                }

                int nextTime = fightLength;
                if (currentTime >= gcdFinishTime)
                {
                    foreach (Ability ability in rot.Priorities)
                    {
                        int nextUseTime = abilities[(int)ability].GetNextUseTime(currentTime);
                        if (nextUseTime > currentTime)
                        {
                            nextTime = Math.Min(nextTime, nextUseTime);
                        }
                    }
                }
                else
                {
                    nextTime = Math.Min(nextTime, gcdFinishTime);
                }

                currentTime = nextTime;
            }

            float            fightLengthInSeconds = ((float)fightLength) / timeUnitsPerSecond;
            RotationSolution solution             = new RotationSolution();

            foreach (Ability ability in rot.Priorities)
            {
                solution.SetAbilityUsagePerSecond(
                    ability,
                    abilities[(int)ability].Uses / fightLengthInSeconds);
                solution.SetAbilityEffectiveCooldown(
                    ability,
                    abilities[(int)ability].EffectiveCooldown() / timeUnitsPerSecond);
            }

            return(solution);
        }